diff options
| author | 2018-01-22 11:54:58 -0500 | |
|---|---|---|
| committer | 2018-01-22 11:54:58 -0500 | |
| commit | 8d7686ff8e5a5be74d4808af4311d3746e4072f7 (patch) | |
| tree | afa1c5c7761d167d59ed5de3fad7a28d1edf9d0f /src | |
| parent | Added stubs for audio services. (#116) (diff) | |
| download | yuzu-8d7686ff8e5a5be74d4808af4311d3746e4072f7.tar.gz yuzu-8d7686ff8e5a5be74d4808af4311d3746e4072f7.tar.xz yuzu-8d7686ff8e5a5be74d4808af4311d3746e4072f7.zip | |
VI: Move BufferQueue and NVFlinger to their own folder/namespace.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.cpp | 96 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.h | 82 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 161 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 84 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi.cpp | 250 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi.h | 130 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi_m.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/vi/vi_m.h | 6 |
9 files changed, 452 insertions, 363 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index bef0d7a1e..242c2db0c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -130,6 +130,10 @@ add_library(core STATIC | |||
| 130 | hle/service/nvdrv/nvdrv.h | 130 | hle/service/nvdrv/nvdrv.h |
| 131 | hle/service/nvdrv/nvmemp.cpp | 131 | hle/service/nvdrv/nvmemp.cpp |
| 132 | hle/service/nvdrv/nvmemp.h | 132 | hle/service/nvdrv/nvmemp.h |
| 133 | hle/service/nvflinger/buffer_queue.cpp | ||
| 134 | hle/service/nvflinger/buffer_queue.h | ||
| 135 | hle/service/nvflinger/nvflinger.cpp | ||
| 136 | hle/service/nvflinger/nvflinger.h | ||
| 133 | hle/service/pctl/pctl.cpp | 137 | hle/service/pctl/pctl.cpp |
| 134 | hle/service/pctl/pctl.h | 138 | hle/service/pctl/pctl.h |
| 135 | hle/service/pctl/pctl_a.cpp | 139 | hle/service/pctl/pctl_a.cpp |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp new file mode 100644 index 000000000..705bdbe5d --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | |||
| 7 | #include "common/alignment.h" | ||
| 8 | #include "common/scope_exit.h" | ||
| 9 | #include "core/core_timing.h" | ||
| 10 | #include "core/hle/service/nvflinger/buffer_queue.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | namespace NVFlinger { | ||
| 14 | |||
| 15 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | ||
| 16 | native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); | ||
| 17 | } | ||
| 18 | |||
| 19 | void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { | ||
| 20 | Buffer buffer{}; | ||
| 21 | buffer.slot = slot; | ||
| 22 | buffer.igbp_buffer = igbp_buffer; | ||
| 23 | buffer.status = Buffer::Status::Free; | ||
| 24 | |||
| 25 | LOG_WARNING(Service, "Adding graphics buffer %u", slot); | ||
| 26 | |||
| 27 | queue.emplace_back(buffer); | ||
| 28 | } | ||
| 29 | |||
| 30 | u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { | ||
| 31 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { | ||
| 32 | // Only consider free buffers. Buffers become free once again after they've been Acquired | ||
| 33 | // and Released by the compositor, see the NVFlinger::Compose method. | ||
| 34 | if (buffer.status != Buffer::Status::Free) | ||
| 35 | return false; | ||
| 36 | |||
| 37 | // Make sure that the parameters match. | ||
| 38 | auto& igbp_buffer = buffer.igbp_buffer; | ||
| 39 | return igbp_buffer.format == pixel_format && igbp_buffer.width == width && | ||
| 40 | igbp_buffer.height == height; | ||
| 41 | }); | ||
| 42 | ASSERT(itr != queue.end()); | ||
| 43 | |||
| 44 | itr->status = Buffer::Status::Dequeued; | ||
| 45 | return itr->slot; | ||
| 46 | } | ||
| 47 | |||
| 48 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { | ||
| 49 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 50 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 51 | ASSERT(itr != queue.end()); | ||
| 52 | ASSERT(itr->status == Buffer::Status::Dequeued); | ||
| 53 | return itr->igbp_buffer; | ||
| 54 | } | ||
| 55 | |||
| 56 | void BufferQueue::QueueBuffer(u32 slot) { | ||
| 57 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 58 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 59 | ASSERT(itr != queue.end()); | ||
| 60 | ASSERT(itr->status == Buffer::Status::Dequeued); | ||
| 61 | itr->status = Buffer::Status::Queued; | ||
| 62 | } | ||
| 63 | |||
| 64 | boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() { | ||
| 65 | auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { | ||
| 66 | return buffer.status == Buffer::Status::Queued; | ||
| 67 | }); | ||
| 68 | if (itr == queue.end()) | ||
| 69 | return boost::none; | ||
| 70 | itr->status = Buffer::Status::Acquired; | ||
| 71 | return *itr; | ||
| 72 | } | ||
| 73 | |||
| 74 | void BufferQueue::ReleaseBuffer(u32 slot) { | ||
| 75 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 76 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 77 | ASSERT(itr != queue.end()); | ||
| 78 | ASSERT(itr->status == Buffer::Status::Acquired); | ||
| 79 | itr->status = Buffer::Status::Free; | ||
| 80 | } | ||
| 81 | |||
| 82 | u32 BufferQueue::Query(QueryType type) { | ||
| 83 | LOG_WARNING(Service, "(STUBBED) called type=%u", static_cast<u32>(type)); | ||
| 84 | switch (type) { | ||
| 85 | case QueryType::NativeWindowFormat: | ||
| 86 | // TODO(Subv): Use an enum for this | ||
| 87 | static constexpr u32 FormatABGR8 = 1; | ||
| 88 | return FormatABGR8; | ||
| 89 | } | ||
| 90 | |||
| 91 | UNIMPLEMENTED(); | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | } // namespace NVFlinger | ||
| 96 | } // namespace Service | ||
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h new file mode 100644 index 000000000..5c6719407 --- /dev/null +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | #include <boost/optional.hpp> | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/hle/kernel/event.h" | ||
| 11 | |||
| 12 | namespace CoreTiming { | ||
| 13 | struct EventType; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service { | ||
| 17 | namespace NVFlinger { | ||
| 18 | |||
| 19 | struct IGBPBuffer { | ||
| 20 | u32_le magic; | ||
| 21 | u32_le width; | ||
| 22 | u32_le height; | ||
| 23 | u32_le stride; | ||
| 24 | u32_le format; | ||
| 25 | u32_le usage; | ||
| 26 | INSERT_PADDING_WORDS(1); | ||
| 27 | u32_le index; | ||
| 28 | INSERT_PADDING_WORDS(3); | ||
| 29 | u32_le gpu_buffer_id; | ||
| 30 | INSERT_PADDING_WORDS(17); | ||
| 31 | u32_le nvmap_handle; | ||
| 32 | u32_le offset; | ||
| 33 | INSERT_PADDING_WORDS(60); | ||
| 34 | }; | ||
| 35 | |||
| 36 | static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); | ||
| 37 | |||
| 38 | class BufferQueue final { | ||
| 39 | public: | ||
| 40 | enum class QueryType { | ||
| 41 | NativeWindowWidth = 0, | ||
| 42 | NativeWindowHeight = 1, | ||
| 43 | NativeWindowFormat = 2, | ||
| 44 | }; | ||
| 45 | |||
| 46 | BufferQueue(u32 id, u64 layer_id); | ||
| 47 | ~BufferQueue() = default; | ||
| 48 | |||
| 49 | struct Buffer { | ||
| 50 | enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; | ||
| 51 | |||
| 52 | u32 slot; | ||
| 53 | Status status = Status::Free; | ||
| 54 | IGBPBuffer igbp_buffer; | ||
| 55 | }; | ||
| 56 | |||
| 57 | void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); | ||
| 58 | u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); | ||
| 59 | const IGBPBuffer& RequestBuffer(u32 slot) const; | ||
| 60 | void QueueBuffer(u32 slot); | ||
| 61 | boost::optional<const Buffer&> AcquireBuffer(); | ||
| 62 | void ReleaseBuffer(u32 slot); | ||
| 63 | u32 Query(QueryType type); | ||
| 64 | |||
| 65 | u32 GetId() const { | ||
| 66 | return id; | ||
| 67 | } | ||
| 68 | |||
| 69 | Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const { | ||
| 70 | return native_handle; | ||
| 71 | } | ||
| 72 | |||
| 73 | private: | ||
| 74 | u32 id; | ||
| 75 | u64 layer_id; | ||
| 76 | |||
| 77 | std::vector<Buffer> queue; | ||
| 78 | Kernel::SharedPtr<Kernel::Event> native_handle; | ||
| 79 | }; | ||
| 80 | |||
| 81 | } // namespace NVFlinger | ||
| 82 | } // namespace Service | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp new file mode 100644 index 000000000..fe622b986 --- /dev/null +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -0,0 +1,161 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | |||
| 7 | #include "common/alignment.h" | ||
| 8 | #include "common/scope_exit.h" | ||
| 9 | #include "core/core_timing.h" | ||
| 10 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | ||
| 11 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 12 | #include "core/hle/service/nvflinger/buffer_queue.h" | ||
| 13 | #include "core/hle/service/nvflinger/nvflinger.h" | ||
| 14 | #include "video_core/renderer_base.h" | ||
| 15 | #include "video_core/video_core.h" | ||
| 16 | |||
| 17 | namespace Service { | ||
| 18 | namespace NVFlinger { | ||
| 19 | |||
| 20 | constexpr size_t SCREEN_REFRESH_RATE = 60; | ||
| 21 | constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); | ||
| 22 | |||
| 23 | NVFlinger::NVFlinger() { | ||
| 24 | // Add the different displays to the list of displays. | ||
| 25 | Display default_{0, "Default"}; | ||
| 26 | Display external{1, "External"}; | ||
| 27 | Display edid{2, "Edid"}; | ||
| 28 | Display internal{3, "Internal"}; | ||
| 29 | |||
| 30 | displays.emplace_back(default_); | ||
| 31 | displays.emplace_back(external); | ||
| 32 | displays.emplace_back(edid); | ||
| 33 | displays.emplace_back(internal); | ||
| 34 | |||
| 35 | // Schedule the screen composition events | ||
| 36 | composition_event = | ||
| 37 | CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) { | ||
| 38 | Compose(); | ||
| 39 | CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); | ||
| 40 | }); | ||
| 41 | |||
| 42 | CoreTiming::ScheduleEvent(frame_ticks, composition_event); | ||
| 43 | } | ||
| 44 | |||
| 45 | NVFlinger::~NVFlinger() { | ||
| 46 | CoreTiming::UnscheduleEvent(composition_event, 0); | ||
| 47 | } | ||
| 48 | |||
| 49 | u64 NVFlinger::OpenDisplay(const std::string& name) { | ||
| 50 | LOG_WARNING(Service, "Opening display %s", name.c_str()); | ||
| 51 | |||
| 52 | // TODO(Subv): Currently we only support the Default display. | ||
| 53 | ASSERT(name == "Default"); | ||
| 54 | |||
| 55 | auto itr = std::find_if(displays.begin(), displays.end(), | ||
| 56 | [&](const Display& display) { return display.name == name; }); | ||
| 57 | |||
| 58 | ASSERT(itr != displays.end()); | ||
| 59 | |||
| 60 | return itr->id; | ||
| 61 | } | ||
| 62 | |||
| 63 | u64 NVFlinger::CreateLayer(u64 display_id) { | ||
| 64 | auto& display = GetDisplay(display_id); | ||
| 65 | |||
| 66 | ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment"); | ||
| 67 | |||
| 68 | u64 layer_id = next_layer_id++; | ||
| 69 | u32 buffer_queue_id = next_buffer_queue_id++; | ||
| 70 | auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id); | ||
| 71 | display.layers.emplace_back(layer_id, buffer_queue); | ||
| 72 | buffer_queues.emplace_back(std::move(buffer_queue)); | ||
| 73 | return layer_id; | ||
| 74 | } | ||
| 75 | |||
| 76 | u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { | ||
| 77 | const auto& layer = GetLayer(display_id, layer_id); | ||
| 78 | return layer.buffer_queue->GetId(); | ||
| 79 | } | ||
| 80 | |||
| 81 | Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { | ||
| 82 | const auto& display = GetDisplay(display_id); | ||
| 83 | return display.vsync_event; | ||
| 84 | } | ||
| 85 | |||
| 86 | std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { | ||
| 87 | auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), | ||
| 88 | [&](const auto& queue) { return queue->GetId() == id; }); | ||
| 89 | |||
| 90 | ASSERT(itr != buffer_queues.end()); | ||
| 91 | return *itr; | ||
| 92 | } | ||
| 93 | |||
| 94 | Display& NVFlinger::GetDisplay(u64 display_id) { | ||
| 95 | auto itr = std::find_if(displays.begin(), displays.end(), | ||
| 96 | [&](const Display& display) { return display.id == display_id; }); | ||
| 97 | |||
| 98 | ASSERT(itr != displays.end()); | ||
| 99 | return *itr; | ||
| 100 | } | ||
| 101 | |||
| 102 | Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { | ||
| 103 | auto& display = GetDisplay(display_id); | ||
| 104 | |||
| 105 | auto itr = std::find_if(display.layers.begin(), display.layers.end(), | ||
| 106 | [&](const Layer& layer) { return layer.id == layer_id; }); | ||
| 107 | |||
| 108 | ASSERT(itr != display.layers.end()); | ||
| 109 | return *itr; | ||
| 110 | } | ||
| 111 | |||
| 112 | void NVFlinger::Compose() { | ||
| 113 | for (auto& display : displays) { | ||
| 114 | // Trigger vsync for this display at the end of drawing | ||
| 115 | SCOPE_EXIT({ display.vsync_event->Signal(); }); | ||
| 116 | |||
| 117 | // Don't do anything for displays without layers. | ||
| 118 | if (display.layers.empty()) | ||
| 119 | continue; | ||
| 120 | |||
| 121 | // TODO(Subv): Support more than 1 layer. | ||
| 122 | ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported"); | ||
| 123 | |||
| 124 | Layer& layer = display.layers[0]; | ||
| 125 | auto& buffer_queue = layer.buffer_queue; | ||
| 126 | |||
| 127 | // Search for a queued buffer and acquire it | ||
| 128 | auto buffer = buffer_queue->AcquireBuffer(); | ||
| 129 | |||
| 130 | if (buffer == boost::none) { | ||
| 131 | // There was no queued buffer to draw, render previous frame | ||
| 132 | VideoCore::g_renderer->SwapBuffers({}); | ||
| 133 | continue; | ||
| 134 | } | ||
| 135 | |||
| 136 | auto& igbp_buffer = buffer->igbp_buffer; | ||
| 137 | |||
| 138 | // Now send the buffer to the GPU for drawing. | ||
| 139 | auto nvdrv = Nvidia::nvdrv.lock(); | ||
| 140 | ASSERT(nvdrv); | ||
| 141 | |||
| 142 | // TODO(Subv): Support more than just disp0. The display device selection is probably based | ||
| 143 | // on which display we're drawing (Default, Internal, External, etc) | ||
| 144 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); | ||
| 145 | ASSERT(nvdisp); | ||
| 146 | |||
| 147 | nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, | ||
| 148 | igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride); | ||
| 149 | |||
| 150 | buffer_queue->ReleaseBuffer(buffer->slot); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} | ||
| 155 | |||
| 156 | Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { | ||
| 157 | vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event"); | ||
| 158 | } | ||
| 159 | |||
| 160 | } // namespace NVFlinger | ||
| 161 | } // namespace Service | ||
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h new file mode 100644 index 000000000..3126018ad --- /dev/null +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <boost/optional.hpp> | ||
| 9 | #include "core/hle/kernel/event.h" | ||
| 10 | |||
| 11 | namespace CoreTiming { | ||
| 12 | struct EventType; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service { | ||
| 16 | namespace NVFlinger { | ||
| 17 | |||
| 18 | class BufferQueue; | ||
| 19 | |||
| 20 | struct Layer { | ||
| 21 | Layer(u64 id, std::shared_ptr<BufferQueue> queue); | ||
| 22 | ~Layer() = default; | ||
| 23 | |||
| 24 | u64 id; | ||
| 25 | std::shared_ptr<BufferQueue> buffer_queue; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct Display { | ||
| 29 | Display(u64 id, std::string name); | ||
| 30 | ~Display() = default; | ||
| 31 | |||
| 32 | u64 id; | ||
| 33 | std::string name; | ||
| 34 | |||
| 35 | std::vector<Layer> layers; | ||
| 36 | Kernel::SharedPtr<Kernel::Event> vsync_event; | ||
| 37 | }; | ||
| 38 | |||
| 39 | class NVFlinger final { | ||
| 40 | public: | ||
| 41 | NVFlinger(); | ||
| 42 | ~NVFlinger(); | ||
| 43 | |||
| 44 | /// Opens the specified display and returns the id. | ||
| 45 | u64 OpenDisplay(const std::string& name); | ||
| 46 | |||
| 47 | /// Creates a layer on the specified display and returns the layer id. | ||
| 48 | u64 CreateLayer(u64 display_id); | ||
| 49 | |||
| 50 | /// Gets the buffer queue id of the specified layer in the specified display. | ||
| 51 | u32 GetBufferQueueId(u64 display_id, u64 layer_id); | ||
| 52 | |||
| 53 | /// Gets the vsync event for the specified display. | ||
| 54 | Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); | ||
| 55 | |||
| 56 | /// Obtains a buffer queue identified by the id. | ||
| 57 | std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; | ||
| 58 | |||
| 59 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when | ||
| 60 | /// finished. | ||
| 61 | void Compose(); | ||
| 62 | |||
| 63 | private: | ||
| 64 | /// Returns the display identified by the specified id. | ||
| 65 | Display& GetDisplay(u64 display_id); | ||
| 66 | |||
| 67 | /// Returns the layer identified by the specified id in the desired display. | ||
| 68 | Layer& GetLayer(u64 display_id, u64 layer_id); | ||
| 69 | |||
| 70 | std::vector<Display> displays; | ||
| 71 | std::vector<std::shared_ptr<BufferQueue>> buffer_queues; | ||
| 72 | |||
| 73 | /// Id to use for the next layer that is created, this counter is shared among all displays. | ||
| 74 | u64 next_layer_id = 1; | ||
| 75 | /// Id to use for the next buffer queue that is created, this counter is shared among all | ||
| 76 | /// layers. | ||
| 77 | u32 next_buffer_queue_id = 1; | ||
| 78 | |||
| 79 | /// CoreTiming event that handles screen composition. | ||
| 80 | CoreTiming::EventType* composition_event; | ||
| 81 | }; | ||
| 82 | |||
| 83 | } // namespace NVFlinger | ||
| 84 | } // namespace Service | ||
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 3f2fd72b2..e0bfad290 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -8,8 +8,7 @@ | |||
| 8 | #include "common/scope_exit.h" | 8 | #include "common/scope_exit.h" |
| 9 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 10 | #include "core/hle/ipc_helpers.h" | 10 | #include "core/hle/ipc_helpers.h" |
| 11 | #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" | 11 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 12 | #include "core/hle/service/nvdrv/nvdrv.h" | ||
| 13 | #include "core/hle/service/vi/vi.h" | 12 | #include "core/hle/service/vi/vi.h" |
| 14 | #include "core/hle/service/vi/vi_m.h" | 13 | #include "core/hle/service/vi/vi_m.h" |
| 15 | #include "video_core/renderer_base.h" | 14 | #include "video_core/renderer_base.h" |
| @@ -18,9 +17,6 @@ | |||
| 18 | namespace Service { | 17 | namespace Service { |
| 19 | namespace VI { | 18 | namespace VI { |
| 20 | 19 | ||
| 21 | constexpr size_t SCREEN_REFRESH_RATE = 60; | ||
| 22 | constexpr u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); | ||
| 23 | |||
| 24 | class Parcel { | 20 | class Parcel { |
| 25 | public: | 21 | public: |
| 26 | // This default size was chosen arbitrarily. | 22 | // This default size was chosen arbitrarily. |
| @@ -204,8 +200,8 @@ public: | |||
| 204 | void DeserializeData() override { | 200 | void DeserializeData() override { |
| 205 | std::u16string token = ReadInterfaceToken(); | 201 | std::u16string token = ReadInterfaceToken(); |
| 206 | data = Read<Data>(); | 202 | data = Read<Data>(); |
| 207 | ASSERT(data.graphic_buffer_length == sizeof(IGBPBuffer)); | 203 | ASSERT(data.graphic_buffer_length == sizeof(NVFlinger::IGBPBuffer)); |
| 208 | buffer = Read<IGBPBuffer>(); | 204 | buffer = Read<NVFlinger::IGBPBuffer>(); |
| 209 | } | 205 | } |
| 210 | 206 | ||
| 211 | struct Data { | 207 | struct Data { |
| @@ -216,7 +212,7 @@ public: | |||
| 216 | }; | 212 | }; |
| 217 | 213 | ||
| 218 | Data data; | 214 | Data data; |
| 219 | IGBPBuffer buffer; | 215 | NVFlinger::IGBPBuffer buffer; |
| 220 | }; | 216 | }; |
| 221 | 217 | ||
| 222 | class IGBPSetPreallocatedBufferResponseParcel : public Parcel { | 218 | class IGBPSetPreallocatedBufferResponseParcel : public Parcel { |
| @@ -288,7 +284,8 @@ public: | |||
| 288 | 284 | ||
| 289 | class IGBPRequestBufferResponseParcel : public Parcel { | 285 | class IGBPRequestBufferResponseParcel : public Parcel { |
| 290 | public: | 286 | public: |
| 291 | explicit IGBPRequestBufferResponseParcel(IGBPBuffer buffer) : Parcel(), buffer(buffer) {} | 287 | explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) |
| 288 | : Parcel(), buffer(buffer) {} | ||
| 292 | ~IGBPRequestBufferResponseParcel() override = default; | 289 | ~IGBPRequestBufferResponseParcel() override = default; |
| 293 | 290 | ||
| 294 | protected: | 291 | protected: |
| @@ -296,7 +293,7 @@ protected: | |||
| 296 | // TODO(Subv): Find out what this all means | 293 | // TODO(Subv): Find out what this all means |
| 297 | Write<u32_le>(1); | 294 | Write<u32_le>(1); |
| 298 | 295 | ||
| 299 | Write<u32_le>(sizeof(IGBPBuffer)); | 296 | Write<u32_le>(sizeof(NVFlinger::IGBPBuffer)); |
| 300 | Write<u32_le>(0); // Unknown | 297 | Write<u32_le>(0); // Unknown |
| 301 | 298 | ||
| 302 | Write(buffer); | 299 | Write(buffer); |
| @@ -304,7 +301,7 @@ protected: | |||
| 304 | Write<u32_le>(0); | 301 | Write<u32_le>(0); |
| 305 | } | 302 | } |
| 306 | 303 | ||
| 307 | IGBPBuffer buffer; | 304 | NVFlinger::IGBPBuffer buffer; |
| 308 | }; | 305 | }; |
| 309 | 306 | ||
| 310 | class IGBPQueueBufferRequestParcel : public Parcel { | 307 | class IGBPQueueBufferRequestParcel : public Parcel { |
| @@ -387,7 +384,7 @@ private: | |||
| 387 | 384 | ||
| 388 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { | 385 | class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { |
| 389 | public: | 386 | public: |
| 390 | explicit IHOSBinderDriver(std::shared_ptr<NVFlinger> nv_flinger) | 387 | explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) |
| 391 | : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { | 388 | : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { |
| 392 | static const FunctionInfo functions[] = { | 389 | static const FunctionInfo functions[] = { |
| 393 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, | 390 | {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, |
| @@ -477,7 +474,8 @@ private: | |||
| 477 | } else if (transaction == TransactionId::Query) { | 474 | } else if (transaction == TransactionId::Query) { |
| 478 | IGBPQueryRequestParcel request{input_data}; | 475 | IGBPQueryRequestParcel request{input_data}; |
| 479 | 476 | ||
| 480 | u32 value = buffer_queue->Query(static_cast<BufferQueue::QueryType>(request.type)); | 477 | u32 value = |
| 478 | buffer_queue->Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type)); | ||
| 481 | 479 | ||
| 482 | IGBPQueryResponseParcel response{value}; | 480 | IGBPQueryResponseParcel response{value}; |
| 483 | auto response_buffer = response.Serialize(); | 481 | auto response_buffer = response.Serialize(); |
| @@ -518,7 +516,7 @@ private: | |||
| 518 | rb.PushCopyObjects(buffer_queue->GetNativeHandle()); | 516 | rb.PushCopyObjects(buffer_queue->GetNativeHandle()); |
| 519 | } | 517 | } |
| 520 | 518 | ||
| 521 | std::shared_ptr<NVFlinger> nv_flinger; | 519 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| 522 | }; | 520 | }; |
| 523 | 521 | ||
| 524 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { | 522 | class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { |
| @@ -546,7 +544,7 @@ private: | |||
| 546 | 544 | ||
| 547 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { | 545 | class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { |
| 548 | public: | 546 | public: |
| 549 | explicit IManagerDisplayService(std::shared_ptr<NVFlinger> nv_flinger) | 547 | explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) |
| 550 | : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { | 548 | : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { |
| 551 | static const FunctionInfo functions[] = { | 549 | static const FunctionInfo functions[] = { |
| 552 | {1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"}, | 550 | {1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"}, |
| @@ -593,7 +591,7 @@ private: | |||
| 593 | rb.Push(RESULT_SUCCESS); | 591 | rb.Push(RESULT_SUCCESS); |
| 594 | } | 592 | } |
| 595 | 593 | ||
| 596 | std::shared_ptr<NVFlinger> nv_flinger; | 594 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| 597 | }; | 595 | }; |
| 598 | 596 | ||
| 599 | void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) { | 597 | void IApplicationDisplayService::GetRelayService(Kernel::HLERequestContext& ctx) { |
| @@ -734,7 +732,8 @@ void IApplicationDisplayService::GetDisplayVsyncEvent(Kernel::HLERequestContext& | |||
| 734 | rb.PushCopyObjects(vsync_event); | 732 | rb.PushCopyObjects(vsync_event); |
| 735 | } | 733 | } |
| 736 | 734 | ||
| 737 | IApplicationDisplayService::IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger) | 735 | IApplicationDisplayService::IApplicationDisplayService( |
| 736 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) | ||
| 738 | : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { | 737 | : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { |
| 739 | static const FunctionInfo functions[] = { | 738 | static const FunctionInfo functions[] = { |
| 740 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, | 739 | {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, |
| @@ -758,222 +757,5 @@ void InstallInterfaces(SM::ServiceManager& service_manager) { | |||
| 758 | std::make_shared<VI_M>()->InstallAsService(service_manager); | 757 | std::make_shared<VI_M>()->InstallAsService(service_manager); |
| 759 | } | 758 | } |
| 760 | 759 | ||
| 761 | NVFlinger::NVFlinger() { | ||
| 762 | // Add the different displays to the list of displays. | ||
| 763 | Display default_{0, "Default"}; | ||
| 764 | Display external{1, "External"}; | ||
| 765 | Display edid{2, "Edid"}; | ||
| 766 | Display internal{3, "Internal"}; | ||
| 767 | |||
| 768 | displays.emplace_back(default_); | ||
| 769 | displays.emplace_back(external); | ||
| 770 | displays.emplace_back(edid); | ||
| 771 | displays.emplace_back(internal); | ||
| 772 | |||
| 773 | // Schedule the screen composition events | ||
| 774 | composition_event = | ||
| 775 | CoreTiming::RegisterEvent("ScreenCompositioin", [this](u64 userdata, int cycles_late) { | ||
| 776 | Compose(); | ||
| 777 | CoreTiming::ScheduleEvent(frame_ticks - cycles_late, composition_event); | ||
| 778 | }); | ||
| 779 | |||
| 780 | CoreTiming::ScheduleEvent(frame_ticks, composition_event); | ||
| 781 | } | ||
| 782 | |||
| 783 | NVFlinger::~NVFlinger() { | ||
| 784 | CoreTiming::UnscheduleEvent(composition_event, 0); | ||
| 785 | } | ||
| 786 | |||
| 787 | u64 NVFlinger::OpenDisplay(const std::string& name) { | ||
| 788 | LOG_WARNING(Service, "Opening display %s", name.c_str()); | ||
| 789 | |||
| 790 | // TODO(Subv): Currently we only support the Default display. | ||
| 791 | ASSERT(name == "Default"); | ||
| 792 | |||
| 793 | auto itr = std::find_if(displays.begin(), displays.end(), | ||
| 794 | [&](const Display& display) { return display.name == name; }); | ||
| 795 | |||
| 796 | ASSERT(itr != displays.end()); | ||
| 797 | |||
| 798 | return itr->id; | ||
| 799 | } | ||
| 800 | |||
| 801 | u64 NVFlinger::CreateLayer(u64 display_id) { | ||
| 802 | auto& display = GetDisplay(display_id); | ||
| 803 | |||
| 804 | ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment"); | ||
| 805 | |||
| 806 | u64 layer_id = next_layer_id++; | ||
| 807 | u32 buffer_queue_id = next_buffer_queue_id++; | ||
| 808 | auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id); | ||
| 809 | display.layers.emplace_back(layer_id, buffer_queue); | ||
| 810 | buffer_queues.emplace_back(std::move(buffer_queue)); | ||
| 811 | return layer_id; | ||
| 812 | } | ||
| 813 | |||
| 814 | u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) { | ||
| 815 | const auto& layer = GetLayer(display_id, layer_id); | ||
| 816 | return layer.buffer_queue->GetId(); | ||
| 817 | } | ||
| 818 | |||
| 819 | Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { | ||
| 820 | const auto& display = GetDisplay(display_id); | ||
| 821 | return display.vsync_event; | ||
| 822 | } | ||
| 823 | |||
| 824 | std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { | ||
| 825 | auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), | ||
| 826 | [&](const auto& queue) { return queue->GetId() == id; }); | ||
| 827 | |||
| 828 | ASSERT(itr != buffer_queues.end()); | ||
| 829 | return *itr; | ||
| 830 | } | ||
| 831 | |||
| 832 | Display& NVFlinger::GetDisplay(u64 display_id) { | ||
| 833 | auto itr = std::find_if(displays.begin(), displays.end(), | ||
| 834 | [&](const Display& display) { return display.id == display_id; }); | ||
| 835 | |||
| 836 | ASSERT(itr != displays.end()); | ||
| 837 | return *itr; | ||
| 838 | } | ||
| 839 | |||
| 840 | Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { | ||
| 841 | auto& display = GetDisplay(display_id); | ||
| 842 | |||
| 843 | auto itr = std::find_if(display.layers.begin(), display.layers.end(), | ||
| 844 | [&](const Layer& layer) { return layer.id == layer_id; }); | ||
| 845 | |||
| 846 | ASSERT(itr != display.layers.end()); | ||
| 847 | return *itr; | ||
| 848 | } | ||
| 849 | |||
| 850 | void NVFlinger::Compose() { | ||
| 851 | for (auto& display : displays) { | ||
| 852 | // Trigger vsync for this display at the end of drawing | ||
| 853 | SCOPE_EXIT({ display.vsync_event->Signal(); }); | ||
| 854 | |||
| 855 | // Don't do anything for displays without layers. | ||
| 856 | if (display.layers.empty()) | ||
| 857 | continue; | ||
| 858 | |||
| 859 | // TODO(Subv): Support more than 1 layer. | ||
| 860 | ASSERT_MSG(display.layers.size() == 1, "Max 1 layer per display is supported"); | ||
| 861 | |||
| 862 | Layer& layer = display.layers[0]; | ||
| 863 | auto& buffer_queue = layer.buffer_queue; | ||
| 864 | |||
| 865 | // Search for a queued buffer and acquire it | ||
| 866 | auto buffer = buffer_queue->AcquireBuffer(); | ||
| 867 | |||
| 868 | if (buffer == boost::none) { | ||
| 869 | // There was no queued buffer to draw, render previous frame | ||
| 870 | VideoCore::g_renderer->SwapBuffers({}); | ||
| 871 | continue; | ||
| 872 | } | ||
| 873 | |||
| 874 | auto& igbp_buffer = buffer->igbp_buffer; | ||
| 875 | |||
| 876 | // Now send the buffer to the GPU for drawing. | ||
| 877 | auto nvdrv = Nvidia::nvdrv.lock(); | ||
| 878 | ASSERT(nvdrv); | ||
| 879 | |||
| 880 | // TODO(Subv): Support more than just disp0. The display device selection is probably based | ||
| 881 | // on which display we're drawing (Default, Internal, External, etc) | ||
| 882 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); | ||
| 883 | ASSERT(nvdisp); | ||
| 884 | |||
| 885 | nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, | ||
| 886 | igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride); | ||
| 887 | |||
| 888 | buffer_queue->ReleaseBuffer(buffer->slot); | ||
| 889 | } | ||
| 890 | } | ||
| 891 | |||
| 892 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | ||
| 893 | native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); | ||
| 894 | } | ||
| 895 | |||
| 896 | void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { | ||
| 897 | Buffer buffer{}; | ||
| 898 | buffer.slot = slot; | ||
| 899 | buffer.igbp_buffer = igbp_buffer; | ||
| 900 | buffer.status = Buffer::Status::Free; | ||
| 901 | |||
| 902 | LOG_WARNING(Service, "Adding graphics buffer %u", slot); | ||
| 903 | |||
| 904 | queue.emplace_back(buffer); | ||
| 905 | } | ||
| 906 | |||
| 907 | u32 BufferQueue::DequeueBuffer(u32 pixel_format, u32 width, u32 height) { | ||
| 908 | auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { | ||
| 909 | // Only consider free buffers. Buffers become free once again after they've been Acquired | ||
| 910 | // and Released by the compositor, see the NVFlinger::Compose method. | ||
| 911 | if (buffer.status != Buffer::Status::Free) | ||
| 912 | return false; | ||
| 913 | |||
| 914 | // Make sure that the parameters match. | ||
| 915 | auto& igbp_buffer = buffer.igbp_buffer; | ||
| 916 | return igbp_buffer.format == pixel_format && igbp_buffer.width == width && | ||
| 917 | igbp_buffer.height == height; | ||
| 918 | }); | ||
| 919 | ASSERT(itr != queue.end()); | ||
| 920 | |||
| 921 | itr->status = Buffer::Status::Dequeued; | ||
| 922 | return itr->slot; | ||
| 923 | } | ||
| 924 | |||
| 925 | const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { | ||
| 926 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 927 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 928 | ASSERT(itr != queue.end()); | ||
| 929 | ASSERT(itr->status == Buffer::Status::Dequeued); | ||
| 930 | return itr->igbp_buffer; | ||
| 931 | } | ||
| 932 | |||
| 933 | void BufferQueue::QueueBuffer(u32 slot) { | ||
| 934 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 935 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 936 | ASSERT(itr != queue.end()); | ||
| 937 | ASSERT(itr->status == Buffer::Status::Dequeued); | ||
| 938 | itr->status = Buffer::Status::Queued; | ||
| 939 | } | ||
| 940 | |||
| 941 | boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() { | ||
| 942 | auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { | ||
| 943 | return buffer.status == Buffer::Status::Queued; | ||
| 944 | }); | ||
| 945 | if (itr == queue.end()) | ||
| 946 | return boost::none; | ||
| 947 | itr->status = Buffer::Status::Acquired; | ||
| 948 | return *itr; | ||
| 949 | } | ||
| 950 | |||
| 951 | void BufferQueue::ReleaseBuffer(u32 slot) { | ||
| 952 | auto itr = std::find_if(queue.begin(), queue.end(), | ||
| 953 | [&](const Buffer& buffer) { return buffer.slot == slot; }); | ||
| 954 | ASSERT(itr != queue.end()); | ||
| 955 | ASSERT(itr->status == Buffer::Status::Acquired); | ||
| 956 | itr->status = Buffer::Status::Free; | ||
| 957 | } | ||
| 958 | |||
| 959 | u32 BufferQueue::Query(QueryType type) { | ||
| 960 | LOG_WARNING(Service, "(STUBBED) called type=%u", static_cast<u32>(type)); | ||
| 961 | switch (type) { | ||
| 962 | case QueryType::NativeWindowFormat: | ||
| 963 | // TODO(Subv): Use an enum for this | ||
| 964 | static constexpr u32 FormatABGR8 = 1; | ||
| 965 | return FormatABGR8; | ||
| 966 | } | ||
| 967 | |||
| 968 | UNIMPLEMENTED(); | ||
| 969 | return 0; | ||
| 970 | } | ||
| 971 | |||
| 972 | Layer::Layer(u64 id, std::shared_ptr<BufferQueue> queue) : id(id), buffer_queue(std::move(queue)) {} | ||
| 973 | |||
| 974 | Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { | ||
| 975 | vsync_event = Kernel::Event::Create(Kernel::ResetType::Pulse, "Display VSync Event"); | ||
| 976 | } | ||
| 977 | |||
| 978 | } // namespace VI | 760 | } // namespace VI |
| 979 | } // namespace Service | 761 | } // namespace Service |
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index 4dd4d1783..5e9b7e6cf 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <boost/optional.hpp> | 8 | #include <boost/optional.hpp> |
| 9 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/service/nvflinger/nvflinger.h" | ||
| 10 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 11 | 12 | ||
| 12 | namespace CoreTiming { | 13 | namespace CoreTiming { |
| @@ -16,134 +17,9 @@ struct EventType; | |||
| 16 | namespace Service { | 17 | namespace Service { |
| 17 | namespace VI { | 18 | namespace VI { |
| 18 | 19 | ||
| 19 | struct IGBPBuffer { | ||
| 20 | u32_le magic; | ||
| 21 | u32_le width; | ||
| 22 | u32_le height; | ||
| 23 | u32_le stride; | ||
| 24 | u32_le format; | ||
| 25 | u32_le usage; | ||
| 26 | INSERT_PADDING_WORDS(1); | ||
| 27 | u32_le index; | ||
| 28 | INSERT_PADDING_WORDS(3); | ||
| 29 | u32_le gpu_buffer_id; | ||
| 30 | INSERT_PADDING_WORDS(17); | ||
| 31 | u32_le nvmap_handle; | ||
| 32 | u32_le offset; | ||
| 33 | INSERT_PADDING_WORDS(60); | ||
| 34 | }; | ||
| 35 | |||
| 36 | static_assert(sizeof(IGBPBuffer) == 0x16C, "IGBPBuffer has wrong size"); | ||
| 37 | |||
| 38 | class BufferQueue { | ||
| 39 | public: | ||
| 40 | enum class QueryType { | ||
| 41 | NativeWindowWidth = 0, | ||
| 42 | NativeWindowHeight = 1, | ||
| 43 | NativeWindowFormat = 2, | ||
| 44 | }; | ||
| 45 | |||
| 46 | BufferQueue(u32 id, u64 layer_id); | ||
| 47 | ~BufferQueue() = default; | ||
| 48 | |||
| 49 | struct Buffer { | ||
| 50 | enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; | ||
| 51 | |||
| 52 | u32 slot; | ||
| 53 | Status status = Status::Free; | ||
| 54 | IGBPBuffer igbp_buffer; | ||
| 55 | }; | ||
| 56 | |||
| 57 | void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); | ||
| 58 | u32 DequeueBuffer(u32 pixel_format, u32 width, u32 height); | ||
| 59 | const IGBPBuffer& RequestBuffer(u32 slot) const; | ||
| 60 | void QueueBuffer(u32 slot); | ||
| 61 | boost::optional<const Buffer&> AcquireBuffer(); | ||
| 62 | void ReleaseBuffer(u32 slot); | ||
| 63 | u32 Query(QueryType type); | ||
| 64 | |||
| 65 | u32 GetId() const { | ||
| 66 | return id; | ||
| 67 | } | ||
| 68 | |||
| 69 | Kernel::SharedPtr<Kernel::Event> GetNativeHandle() const { | ||
| 70 | return native_handle; | ||
| 71 | } | ||
| 72 | |||
| 73 | private: | ||
| 74 | u32 id; | ||
| 75 | u64 layer_id; | ||
| 76 | |||
| 77 | std::vector<Buffer> queue; | ||
| 78 | Kernel::SharedPtr<Kernel::Event> native_handle; | ||
| 79 | }; | ||
| 80 | |||
| 81 | struct Layer { | ||
| 82 | Layer(u64 id, std::shared_ptr<BufferQueue> queue); | ||
| 83 | ~Layer() = default; | ||
| 84 | |||
| 85 | u64 id; | ||
| 86 | std::shared_ptr<BufferQueue> buffer_queue; | ||
| 87 | }; | ||
| 88 | |||
| 89 | struct Display { | ||
| 90 | Display(u64 id, std::string name); | ||
| 91 | ~Display() = default; | ||
| 92 | |||
| 93 | u64 id; | ||
| 94 | std::string name; | ||
| 95 | |||
| 96 | std::vector<Layer> layers; | ||
| 97 | Kernel::SharedPtr<Kernel::Event> vsync_event; | ||
| 98 | }; | ||
| 99 | |||
| 100 | class NVFlinger { | ||
| 101 | public: | ||
| 102 | NVFlinger(); | ||
| 103 | ~NVFlinger(); | ||
| 104 | |||
| 105 | /// Opens the specified display and returns the id. | ||
| 106 | u64 OpenDisplay(const std::string& name); | ||
| 107 | |||
| 108 | /// Creates a layer on the specified display and returns the layer id. | ||
| 109 | u64 CreateLayer(u64 display_id); | ||
| 110 | |||
| 111 | /// Gets the buffer queue id of the specified layer in the specified display. | ||
| 112 | u32 GetBufferQueueId(u64 display_id, u64 layer_id); | ||
| 113 | |||
| 114 | /// Gets the vsync event for the specified display. | ||
| 115 | Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); | ||
| 116 | |||
| 117 | /// Obtains a buffer queue identified by the id. | ||
| 118 | std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; | ||
| 119 | |||
| 120 | /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when | ||
| 121 | /// finished. | ||
| 122 | void Compose(); | ||
| 123 | |||
| 124 | private: | ||
| 125 | /// Returns the display identified by the specified id. | ||
| 126 | Display& GetDisplay(u64 display_id); | ||
| 127 | |||
| 128 | /// Returns the layer identified by the specified id in the desired display. | ||
| 129 | Layer& GetLayer(u64 display_id, u64 layer_id); | ||
| 130 | |||
| 131 | std::vector<Display> displays; | ||
| 132 | std::vector<std::shared_ptr<BufferQueue>> buffer_queues; | ||
| 133 | |||
| 134 | /// Id to use for the next layer that is created, this counter is shared among all displays. | ||
| 135 | u64 next_layer_id = 1; | ||
| 136 | /// Id to use for the next buffer queue that is created, this counter is shared among all | ||
| 137 | /// layers. | ||
| 138 | u32 next_buffer_queue_id = 1; | ||
| 139 | |||
| 140 | /// CoreTiming event that handles screen composition. | ||
| 141 | CoreTiming::EventType* composition_event; | ||
| 142 | }; | ||
| 143 | |||
| 144 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { | 20 | class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { |
| 145 | public: | 21 | public: |
| 146 | IApplicationDisplayService(std::shared_ptr<NVFlinger> nv_flinger); | 22 | IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); |
| 147 | ~IApplicationDisplayService() = default; | 23 | ~IApplicationDisplayService() = default; |
| 148 | 24 | ||
| 149 | private: | 25 | private: |
| @@ -159,7 +35,7 @@ private: | |||
| 159 | void DestroyStrayLayer(Kernel::HLERequestContext& ctx); | 35 | void DestroyStrayLayer(Kernel::HLERequestContext& ctx); |
| 160 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); | 36 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx); |
| 161 | 37 | ||
| 162 | std::shared_ptr<NVFlinger> nv_flinger; | 38 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| 163 | }; | 39 | }; |
| 164 | 40 | ||
| 165 | /// Registers all VI services with the specified service manager. | 41 | /// Registers all VI services with the specified service manager. |
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp index 1a5a28b0d..6deedf842 100644 --- a/src/core/hle/service/vi/vi_m.cpp +++ b/src/core/hle/service/vi/vi_m.cpp | |||
| @@ -23,7 +23,7 @@ VI_M::VI_M() : ServiceFramework("vi:m") { | |||
| 23 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, | 23 | {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, |
| 24 | }; | 24 | }; |
| 25 | RegisterHandlers(functions); | 25 | RegisterHandlers(functions); |
| 26 | nv_flinger = std::make_shared<NVFlinger>(); | 26 | nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | } // namespace VI | 29 | } // namespace VI |
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h index 70ff7a2f3..ebe79d5c7 100644 --- a/src/core/hle/service/vi/vi_m.h +++ b/src/core/hle/service/vi/vi_m.h | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 9 | 9 | ||
| 10 | namespace Service { | 10 | namespace Service { |
| 11 | namespace NVFlinger { | ||
| 12 | class NVFlinger; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace VI { | 15 | namespace VI { |
| 12 | 16 | ||
| 13 | class VI_M final : public ServiceFramework<VI_M> { | 17 | class VI_M final : public ServiceFramework<VI_M> { |
| @@ -18,7 +22,7 @@ public: | |||
| 18 | private: | 22 | private: |
| 19 | void GetDisplayService(Kernel::HLERequestContext& ctx); | 23 | void GetDisplayService(Kernel::HLERequestContext& ctx); |
| 20 | 24 | ||
| 21 | std::shared_ptr<NVFlinger> nv_flinger; | 25 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| 22 | }; | 26 | }; |
| 23 | 27 | ||
| 24 | } // namespace VI | 28 | } // namespace VI |