summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando S2022-03-25 03:36:55 +0100
committerGravatar GitHub2022-03-25 03:36:55 +0100
commit0608336c60c62b74af73422115ee0e0797362e8f (patch)
tree33c9b4d79130736839fc28030950d401bf4fd81b /src
parentMerge pull request #8068 from ameerj/shader-if-false (diff)
parentUpdate project license to GPL v3. (diff)
downloadyuzu-0608336c60c62b74af73422115ee0e0797362e8f.tar.gz
yuzu-0608336c60c62b74af73422115ee0e0797362e8f.tar.xz
yuzu-0608336c60c62b74af73422115ee0e0797362e8f.zip
Merge pull request #8050 from bunnei/nvflinger-rewrite
Rewrite of the NVFlinger implementation
Diffstat (limited to 'src')
-rw-r--r--src/common/logging/filter.cpp1
-rw-r--r--src/common/logging/types.h1
-rw-r--r--src/common/math_util.h50
-rw-r--r--src/core/CMakeLists.txt29
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h10
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h10
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h3
-rw-r--r--src/core/hle/service/nvflinger/binder.h42
-rw-r--r--src/core/hle/service/nvflinger/buffer_item.h46
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.cpp59
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.h28
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp225
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.h37
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp134
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h99
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_defs.h21
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp937
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h83
-rw-r--r--src/core/hle/service/nvflinger/buffer_slot.h39
-rw-r--r--src/core/hle/service/nvflinger/buffer_transform_flags.h25
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.cpp130
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.h61
-rw-r--r--src/core/hle/service/nvflinger/consumer_listener.h26
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.cpp20
-rw-r--r--src/core/hle/service/nvflinger/graphic_buffer_producer.h76
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.cpp36
-rw-r--r--src/core/hle/service/nvflinger/hos_binder_driver_server.h37
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp81
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h26
-rw-r--r--src/core/hle/service/nvflinger/parcel.h172
-rw-r--r--src/core/hle/service/nvflinger/pixel_format.h21
-rw-r--r--src/core/hle/service/nvflinger/producer_listener.h16
-rw-r--r--src/core/hle/service/nvflinger/status.h28
-rw-r--r--src/core/hle/service/nvflinger/ui/fence.h32
-rw-r--r--src/core/hle/service/nvflinger/ui/graphic_buffer.h100
-rw-r--r--src/core/hle/service/nvflinger/window.h53
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/service.h4
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp50
-rw-r--r--src/core/hle/service/vi/display/vi_display.h29
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp6
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h57
-rw-r--r--src/core/hle/service/vi/vi.cpp690
-rw-r--r--src/core/hle/service/vi/vi.h10
-rw-r--r--src/core/hle/service/vi/vi_m.cpp9
-rw-r--r--src/core/hle/service/vi/vi_m.h7
-rw-r--r--src/core/hle/service/vi/vi_s.cpp9
-rw-r--r--src/core/hle/service/vi/vi_s.h7
-rw-r--r--src/core/hle/service/vi/vi_u.cpp9
-rw-r--r--src/core/hle/service/vi/vi_u.h7
-rw-r--r--src/video_core/framebuffer_config.h29
-rw-r--r--src/video_core/gpu.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp10
-rw-r--r--src/video_core/surface.cpp8
-rw-r--r--src/video_core/surface.h2
60 files changed, 2984 insertions, 796 deletions
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 4afc1369a..9120cc178 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -119,6 +119,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
119 SUB(Service, NPNS) \ 119 SUB(Service, NPNS) \
120 SUB(Service, NS) \ 120 SUB(Service, NS) \
121 SUB(Service, NVDRV) \ 121 SUB(Service, NVDRV) \
122 SUB(Service, NVFlinger) \
122 SUB(Service, OLSC) \ 123 SUB(Service, OLSC) \
123 SUB(Service, PCIE) \ 124 SUB(Service, PCIE) \
124 SUB(Service, PCTL) \ 125 SUB(Service, PCTL) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 2b6e4daa7..f803ab796 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -87,6 +87,7 @@ enum class Class : u8 {
87 Service_NPNS, ///< The NPNS service 87 Service_NPNS, ///< The NPNS service
88 Service_NS, ///< The NS services 88 Service_NS, ///< The NS services
89 Service_NVDRV, ///< The NVDRV (Nvidia driver) service 89 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
90 Service_NVFlinger, ///< The NVFlinger service
90 Service_OLSC, ///< The OLSC service 91 Service_OLSC, ///< The OLSC service
91 Service_PCIE, ///< The PCIe service 92 Service_PCIE, ///< The PCIe service
92 Service_PCTL, ///< The PCTL (Parental control) service 93 Service_PCTL, ///< The PCTL (Parental control) service
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 510c4e56d..54485bf53 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <cstdlib> 8#include <cstdlib>
8#include <type_traits> 9#include <type_traits>
9 10
@@ -20,10 +21,32 @@ struct Rectangle {
20 21
21 constexpr Rectangle() = default; 22 constexpr Rectangle() = default;
22 23
24 constexpr Rectangle(T width, T height) : right(width), bottom(height) {}
25
23 constexpr Rectangle(T left_, T top_, T right_, T bottom_) 26 constexpr Rectangle(T left_, T top_, T right_, T bottom_)
24 : left(left_), top(top_), right(right_), bottom(bottom_) {} 27 : left(left_), top(top_), right(right_), bottom(bottom_) {}
25 28
26 [[nodiscard]] T GetWidth() const { 29 [[nodiscard]] constexpr T Left() const {
30 return left;
31 }
32
33 [[nodiscard]] constexpr T Top() const {
34 return top;
35 }
36
37 [[nodiscard]] constexpr T Right() const {
38 return right;
39 }
40
41 [[nodiscard]] constexpr T Bottom() const {
42 return bottom;
43 }
44
45 [[nodiscard]] constexpr bool IsEmpty() const {
46 return (GetWidth() <= 0) || (GetHeight() <= 0);
47 }
48
49 [[nodiscard]] constexpr T GetWidth() const {
27 if constexpr (std::is_floating_point_v<T>) { 50 if constexpr (std::is_floating_point_v<T>) {
28 return std::abs(right - left); 51 return std::abs(right - left);
29 } else { 52 } else {
@@ -31,7 +54,7 @@ struct Rectangle {
31 } 54 }
32 } 55 }
33 56
34 [[nodiscard]] T GetHeight() const { 57 [[nodiscard]] constexpr T GetHeight() const {
35 if constexpr (std::is_floating_point_v<T>) { 58 if constexpr (std::is_floating_point_v<T>) {
36 return std::abs(bottom - top); 59 return std::abs(bottom - top);
37 } else { 60 } else {
@@ -39,18 +62,35 @@ struct Rectangle {
39 } 62 }
40 } 63 }
41 64
42 [[nodiscard]] Rectangle<T> TranslateX(const T x) const { 65 [[nodiscard]] constexpr Rectangle<T> TranslateX(const T x) const {
43 return Rectangle{left + x, top, right + x, bottom}; 66 return Rectangle{left + x, top, right + x, bottom};
44 } 67 }
45 68
46 [[nodiscard]] Rectangle<T> TranslateY(const T y) const { 69 [[nodiscard]] constexpr Rectangle<T> TranslateY(const T y) const {
47 return Rectangle{left, top + y, right, bottom + y}; 70 return Rectangle{left, top + y, right, bottom + y};
48 } 71 }
49 72
50 [[nodiscard]] Rectangle<T> Scale(const float s) const { 73 [[nodiscard]] constexpr Rectangle<T> Scale(const float s) const {
51 return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s), 74 return Rectangle{left, top, static_cast<T>(static_cast<float>(left + GetWidth()) * s),
52 static_cast<T>(static_cast<float>(top + GetHeight()) * s)}; 75 static_cast<T>(static_cast<float>(top + GetHeight()) * s)};
53 } 76 }
77
78 [[nodiscard]] constexpr bool operator==(const Rectangle<T>& rhs) const {
79 return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) &&
80 (bottom == rhs.bottom);
81 }
82
83 [[nodiscard]] constexpr bool operator!=(const Rectangle<T>& rhs) const {
84 return !operator==(rhs);
85 }
86
87 [[nodiscard]] constexpr bool Intersect(const Rectangle<T>& with, Rectangle<T>* result) const {
88 result->left = std::max(left, with.left);
89 result->top = std::max(top, with.top);
90 result->right = std::min(right, with.right);
91 result->bottom = std::min(bottom, with.bottom);
92 return !result->IsEmpty();
93 }
54}; 94};
55 95
56template <typename T> 96template <typename T>
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a6f442316..6536d0544 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -535,10 +535,35 @@ add_library(core STATIC
535 hle/service/nvdrv/nvmemp.h 535 hle/service/nvdrv/nvmemp.h
536 hle/service/nvdrv/syncpoint_manager.cpp 536 hle/service/nvdrv/syncpoint_manager.cpp
537 hle/service/nvdrv/syncpoint_manager.h 537 hle/service/nvdrv/syncpoint_manager.h
538 hle/service/nvflinger/buffer_queue.cpp 538 hle/service/nvflinger/binder.h
539 hle/service/nvflinger/buffer_queue.h 539 hle/service/nvflinger/buffer_item.h
540 hle/service/nvflinger/buffer_item_consumer.cpp
541 hle/service/nvflinger/buffer_item_consumer.h
542 hle/service/nvflinger/buffer_queue_consumer.cpp
543 hle/service/nvflinger/buffer_queue_consumer.h
544 hle/service/nvflinger/buffer_queue_core.cpp
545 hle/service/nvflinger/buffer_queue_core.h
546 hle/service/nvflinger/buffer_queue_defs.h
547 hle/service/nvflinger/buffer_queue_producer.cpp
548 hle/service/nvflinger/buffer_queue_producer.h
549 hle/service/nvflinger/buffer_slot.h
550 hle/service/nvflinger/buffer_transform_flags.h
551 hle/service/nvflinger/consumer_base.cpp
552 hle/service/nvflinger/consumer_base.h
553 hle/service/nvflinger/consumer_listener.h
554 hle/service/nvflinger/graphic_buffer_producer.cpp
555 hle/service/nvflinger/graphic_buffer_producer.h
556 hle/service/nvflinger/hos_binder_driver_server.cpp
557 hle/service/nvflinger/hos_binder_driver_server.h
540 hle/service/nvflinger/nvflinger.cpp 558 hle/service/nvflinger/nvflinger.cpp
541 hle/service/nvflinger/nvflinger.h 559 hle/service/nvflinger/nvflinger.h
560 hle/service/nvflinger/parcel.h
561 hle/service/nvflinger/pixel_format.h
562 hle/service/nvflinger/producer_listener.h
563 hle/service/nvflinger/status.h
564 hle/service/nvflinger/ui/fence.h
565 hle/service/nvflinger/ui/graphic_buffer.h
566 hle/service/nvflinger/window.h
542 hle/service/olsc/olsc.cpp 567 hle/service/olsc/olsc.cpp
543 hle/service/olsc/olsc.h 568 hle/service/olsc/olsc.h
544 hle/service/pcie/pcie.cpp 569 hle/service/pcie/pcie.cpp
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 68f1e9060..9fad45fe1 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -38,18 +38,16 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>&
38void nvdisp_disp0::OnOpen(DeviceFD fd) {} 38void nvdisp_disp0::OnOpen(DeviceFD fd) {}
39void nvdisp_disp0::OnClose(DeviceFD fd) {} 39void nvdisp_disp0::OnClose(DeviceFD fd) {}
40 40
41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, 41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width,
42 u32 stride, NVFlinger::BufferQueue::BufferTransformFlags transform, 42 u32 height, u32 stride, android::BufferTransformFlags transform,
43 const Common::Rectangle<int>& crop_rect) { 43 const Common::Rectangle<int>& crop_rect) {
44 const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle); 44 const VAddr addr = nvmap_dev->GetObjectAddress(buffer_handle);
45 LOG_TRACE(Service, 45 LOG_TRACE(Service,
46 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", 46 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}",
47 addr, offset, width, height, stride, format); 47 addr, offset, width, height, stride, format);
48 48
49 const auto pixel_format = static_cast<Tegra::FramebufferConfig::PixelFormat>(format); 49 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
50 const auto transform_flags = static_cast<Tegra::FramebufferConfig::TransformFlags>(transform); 50 stride, format, transform, crop_rect};
51 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height,
52 stride, pixel_format, transform_flags, crop_rect};
53 51
54 system.GetPerfStats().EndSystemFrame(); 52 system.GetPerfStats().EndSystemFrame();
55 system.GPU().SwapBuffers(&framebuffer); 53 system.GPU().SwapBuffers(&framebuffer);
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index de01e1d5f..30b5da429 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -9,7 +9,8 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/math_util.h" 10#include "common/math_util.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h" 11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12#include "core/hle/service/nvflinger/buffer_queue.h" 12#include "core/hle/service/nvflinger/buffer_transform_flags.h"
13#include "core/hle/service/nvflinger/pixel_format.h"
13 14
14namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
15 16
@@ -31,8 +32,8 @@ public:
31 void OnClose(DeviceFD fd) override; 32 void OnClose(DeviceFD fd) override;
32 33
33 /// Performs a screen flip, drawing the buffer pointed to by the handle. 34 /// Performs a screen flip, drawing the buffer pointed to by the handle.
34 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, 35 void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height,
35 NVFlinger::BufferQueue::BufferTransformFlags transform, 36 u32 stride, android::BufferTransformFlags transform,
36 const Common::Rectangle<int>& crop_rect); 37 const Common::Rectangle<int>& crop_rect);
37 38
38private: 39private:
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 0a043e386..dde5b1507 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -187,7 +187,7 @@ NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::ve
187 return NvResult::Success; 187 return NvResult::Success;
188} 188}
189 189
190static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { 190static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) {
191 return { 191 return {
192 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, 192 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
193 Tegra::SubmissionMode::Increasing), 193 Tegra::SubmissionMode::Increasing),
@@ -198,7 +198,8 @@ static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
198 }; 198 };
199} 199}
200 200
201static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) { 201static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(NvFence fence,
202 u32 add_increment) {
202 std::vector<Tegra::CommandHeader> result{ 203 std::vector<Tegra::CommandHeader> result{
203 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, 204 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
204 Tegra::SubmissionMode::Increasing), 205 Tegra::SubmissionMode::Increasing),
@@ -213,7 +214,7 @@ static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence,
213 return result; 214 return result;
214} 215}
215 216
216static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence, 217static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(NvFence fence,
217 u32 add_increment) { 218 u32 add_increment) {
218 std::vector<Tegra::CommandHeader> result{ 219 std::vector<Tegra::CommandHeader> result{
219 Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, 220 Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 3e4f3b6a7..b2e943e45 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -109,7 +109,7 @@ private:
109 static_assert(sizeof(IoctlGetErrorNotification) == 16, 109 static_assert(sizeof(IoctlGetErrorNotification) == 16,
110 "IoctlGetErrorNotification is incorrect size"); 110 "IoctlGetErrorNotification is incorrect size");
111 111
112 static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); 112 static_assert(sizeof(NvFence) == 8, "Fence is incorrect size");
113 113
114 struct IoctlAllocGpfifoEx { 114 struct IoctlAllocGpfifoEx {
115 u32_le num_entries{}; 115 u32_le num_entries{};
@@ -127,7 +127,7 @@ private:
127 u32_le num_entries{}; // in 127 u32_le num_entries{}; // in
128 u32_le flags{}; // in 128 u32_le flags{}; // in
129 u32_le unk0{}; // in (1 works) 129 u32_le unk0{}; // in (1 works)
130 Fence fence_out{}; // out 130 NvFence fence_out{}; // out
131 u32_le unk1{}; // in 131 u32_le unk1{}; // in
132 u32_le unk2{}; // in 132 u32_le unk2{}; // in
133 u32_le unk3{}; // in 133 u32_le unk3{}; // in
@@ -153,13 +153,13 @@ private:
153 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt 153 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
154 BitField<8, 1, u32_le> increment; // increment the returned fence 154 BitField<8, 1, u32_le> increment; // increment the returned fence
155 } flags; 155 } flags;
156 Fence fence_out{}; // returned new fence object for others to wait on 156 NvFence fence_out{}; // returned new fence object for others to wait on
157 157
158 u32 AddIncrementValue() const { 158 u32 AddIncrementValue() const {
159 return flags.add_increment.Value() << 1; 159 return flags.add_increment.Value() << 1;
160 } 160 }
161 }; 161 };
162 static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), 162 static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(NvFence),
163 "IoctlSubmitGpfifo is incorrect size"); 163 "IoctlSubmitGpfifo is incorrect size");
164 164
165 struct IoctlGetWaitbase { 165 struct IoctlGetWaitbase {
@@ -194,7 +194,7 @@ private:
194 194
195 std::shared_ptr<nvmap> nvmap_dev; 195 std::shared_ptr<nvmap> nvmap_dev;
196 SyncpointManager& syncpoint_manager; 196 SyncpointManager& syncpoint_manager;
197 Fence channel_fence; 197 NvFence channel_fence;
198}; 198};
199 199
200} // namespace Service::Nvidia::Devices 200} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index 5ab221fc1..3069c3c80 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -16,17 +16,11 @@ using DeviceFD = s32;
16 16
17constexpr DeviceFD INVALID_NVDRV_FD = -1; 17constexpr DeviceFD INVALID_NVDRV_FD = -1;
18 18
19struct Fence { 19struct NvFence {
20 s32 id; 20 s32 id;
21 u32 value; 21 u32 value;
22}; 22};
23 23static_assert(sizeof(NvFence) == 8, "NvFence has wrong size");
24static_assert(sizeof(Fence) == 8, "Fence has wrong size");
25
26struct MultiFence {
27 u32 num_fences;
28 std::array<Fence, 4> fences;
29};
30 24
31enum class NvResult : u32 { 25enum class NvResult : u32 {
32 Success = 0x0, 26 Success = 0x0,
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a5af5b785..11cf6c0d1 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -12,6 +12,7 @@
12#include "core/hle/service/kernel_helpers.h" 12#include "core/hle/service/kernel_helpers.h"
13#include "core/hle/service/nvdrv/nvdata.h" 13#include "core/hle/service/nvdrv/nvdata.h"
14#include "core/hle/service/nvdrv/syncpoint_manager.h" 14#include "core/hle/service/nvdrv/syncpoint_manager.h"
15#include "core/hle/service/nvflinger/ui/fence.h"
15#include "core/hle/service/service.h" 16#include "core/hle/service/service.h"
16 17
17namespace Core { 18namespace Core {
@@ -37,7 +38,7 @@ class nvdevice;
37/// Represents an Nvidia event 38/// Represents an Nvidia event
38struct NvEvent { 39struct NvEvent {
39 Kernel::KEvent* event{}; 40 Kernel::KEvent* event{};
40 Fence fence{}; 41 NvFence fence{};
41}; 42};
42 43
43struct EventInterface { 44struct EventInterface {
diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvflinger/binder.h
new file mode 100644
index 000000000..7d0d4d819
--- /dev/null
+++ b/src/core/hle/service/nvflinger/binder.h
@@ -0,0 +1,42 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/binder/IBinder.h
6
7#pragma once
8
9#include "common/common_types.h"
10
11namespace Kernel {
12class HLERequestContext;
13class KReadableEvent;
14} // namespace Kernel
15
16namespace Service::android {
17
18enum class TransactionId {
19 RequestBuffer = 1,
20 SetBufferCount = 2,
21 DequeueBuffer = 3,
22 DetachBuffer = 4,
23 DetachNextBuffer = 5,
24 AttachBuffer = 6,
25 QueueBuffer = 7,
26 CancelBuffer = 8,
27 Query = 9,
28 Connect = 10,
29 Disconnect = 11,
30 AllocateBuffers = 13,
31 SetPreallocatedBuffer = 14,
32 GetBufferHistory = 17,
33};
34
35class IBinder {
36public:
37 virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code,
38 u32 flags) = 0;
39 virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
40};
41
42} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvflinger/buffer_item.h
new file mode 100644
index 000000000..64b82b851
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_item.h
@@ -0,0 +1,46 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItem.h
6
7#pragma once
8
9#include <memory>
10
11#include "common/common_types.h"
12#include "common/math_util.h"
13#include "core/hle/service/nvflinger/ui/fence.h"
14#include "core/hle/service/nvflinger/window.h"
15
16namespace Service::android {
17
18class GraphicBuffer;
19
20class BufferItem final {
21public:
22 constexpr BufferItem() = default;
23
24 std::shared_ptr<GraphicBuffer> graphic_buffer;
25 Fence fence;
26 Common::Rectangle<s32> crop;
27 NativeWindowTransform transform{};
28 u32 scaling_mode{};
29 s64 timestamp{};
30 bool is_auto_timestamp{};
31 u64 frame_number{};
32
33 // The default value for buf, used to indicate this doesn't correspond to a slot.
34 static constexpr s32 INVALID_BUFFER_SLOT = -1;
35 union {
36 s32 slot{INVALID_BUFFER_SLOT};
37 s32 buf;
38 };
39
40 bool is_droppable{};
41 bool acquire_called{};
42 bool transform_to_display_inverse{};
43 s32 swap_interval{};
44};
45
46} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
new file mode 100644
index 000000000..7f32c0775
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
@@ -0,0 +1,59 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2012 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferItemConsumer.cpp
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hle/service/nvflinger/buffer_item.h"
10#include "core/hle/service/nvflinger/buffer_item_consumer.h"
11#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
12
13namespace Service::android {
14
15BufferItemConsumer::BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer_)
16 : ConsumerBase{std::move(consumer_)} {}
17
18Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
19 bool wait_for_fence) {
20 if (!item) {
21 return Status::BadValue;
22 }
23
24 std::unique_lock lock(mutex);
25
26 if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) {
27 if (status != Status::NoBufferAvailable) {
28 LOG_ERROR(Service_NVFlinger, "Failed to acquire buffer: {}", status);
29 }
30 return status;
31 }
32
33 if (wait_for_fence) {
34 UNIMPLEMENTED();
35 }
36
37 item->graphic_buffer = slots[item->slot].graphic_buffer;
38
39 return Status::NoError;
40}
41
42Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) {
43 std::unique_lock lock(mutex);
44
45 if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence);
46 status != Status::NoError) {
47 LOG_ERROR(Service_NVFlinger, "Failed to add fence: {}", status);
48 }
49
50 if (const auto status = ReleaseBufferLocked(item.buf, item.graphic_buffer);
51 status != Status::NoError) {
52 LOG_WARNING(Service_NVFlinger, "Failed to release buffer: {}", status);
53 return status;
54 }
55
56 return Status::NoError;
57}
58
59} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h
new file mode 100644
index 000000000..536db81e2
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h
@@ -0,0 +1,28 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2012 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferItemConsumer.h
6
7#pragma once
8
9#include <chrono>
10#include <memory>
11
12#include "common/common_types.h"
13#include "core/hle/service/nvflinger/consumer_base.h"
14#include "core/hle/service/nvflinger/status.h"
15
16namespace Service::android {
17
18class BufferItem;
19
20class BufferItemConsumer final : public ConsumerBase {
21public:
22 explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer);
23 Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
24 bool wait_for_fence = true);
25 Status ReleaseBuffer(const BufferItem& item, Fence& release_fence);
26};
27
28} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
new file mode 100644
index 000000000..677bec932
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
@@ -0,0 +1,225 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
6
7#include "common/logging/log.h"
8#include "core/hle/service/nvflinger/buffer_item.h"
9#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
10#include "core/hle/service/nvflinger/buffer_queue_core.h"
11#include "core/hle/service/nvflinger/producer_listener.h"
12
13namespace Service::android {
14
15BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
16 : core{std::move(core_)}, slots{core->slots} {}
17
18BufferQueueConsumer::~BufferQueueConsumer() = default;
19
20Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
21 std::chrono::nanoseconds expected_present,
22 u64 max_frame_number) {
23 s32 num_dropped_buffers{};
24
25 std::shared_ptr<IProducerListener> listener;
26 {
27 std::unique_lock lock(core->mutex);
28
29 // Check that the consumer doesn't currently have the maximum number of buffers acquired.
30 const s32 num_acquired_buffers{
31 static_cast<s32>(std::count_if(slots.begin(), slots.end(), [](const auto& slot) {
32 return slot.buffer_state == BufferState::Acquired;
33 }))};
34
35 if (num_acquired_buffers >= core->max_acquired_buffer_count + 1) {
36 LOG_ERROR(Service_NVFlinger, "max acquired buffer count reached: {} (max {})",
37 num_acquired_buffers, core->max_acquired_buffer_count);
38 return Status::InvalidOperation;
39 }
40
41 // Check if the queue is empty.
42 if (core->queue.empty()) {
43 return Status::NoBufferAvailable;
44 }
45
46 auto front(core->queue.begin());
47
48 // If expected_present is specified, we may not want to return a buffer yet.
49 if (expected_present.count() != 0) {
50 constexpr auto MAX_REASONABLE_NSEC = 1000000000LL; // 1 second
51
52 // The expected_present argument indicates when the buffer is expected to be
53 // presented on-screen.
54 while (core->queue.size() > 1 && !core->queue[0].is_auto_timestamp) {
55 const auto& buffer_item{core->queue[1]};
56
57 // If dropping entry[0] would leave us with a buffer that the consumer is not yet
58 // ready for, don't drop it.
59 if (max_frame_number && buffer_item.frame_number > max_frame_number) {
60 break;
61 }
62
63 // If entry[1] is timely, drop entry[0] (and repeat).
64 const auto desired_present = buffer_item.timestamp;
65 if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC ||
66 desired_present > expected_present.count()) {
67 // This buffer is set to display in the near future, or desired_present is
68 // garbage.
69 LOG_DEBUG(Service_NVFlinger, "nodrop desire={} expect={}", desired_present,
70 expected_present.count());
71 break;
72 }
73
74 LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present,
75 expected_present.count(), core->queue.size());
76
77 if (core->StillTracking(*front)) {
78 // Front buffer is still in mSlots, so mark the slot as free
79 slots[front->slot].buffer_state = BufferState::Free;
80 core->free_buffers.push_back(front->slot);
81 listener = core->connected_producer_listener;
82 ++num_dropped_buffers;
83 }
84
85 core->queue.erase(front);
86 front = core->queue.begin();
87 }
88
89 // See if the front buffer is ready to be acquired.
90 const auto desired_present = front->timestamp;
91 const auto buffer_is_due =
92 desired_present <= expected_present.count() ||
93 desired_present > expected_present.count() + MAX_REASONABLE_NSEC;
94 const auto consumer_is_ready =
95 max_frame_number > 0 ? front->frame_number <= max_frame_number : true;
96
97 if (!buffer_is_due || !consumer_is_ready) {
98 LOG_DEBUG(Service_NVFlinger, "defer desire={} expect={}", desired_present,
99 expected_present.count());
100 return Status::PresentLater;
101 }
102
103 LOG_DEBUG(Service_NVFlinger, "accept desire={} expect={}", desired_present,
104 expected_present.count());
105 }
106
107 const auto slot = front->slot;
108 *out_buffer = *front;
109
110 LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot);
111
112 // If the front buffer is still being tracked, update its slot state
113 if (core->StillTracking(*front)) {
114 slots[slot].acquire_called = true;
115 slots[slot].needs_cleanup_on_release = false;
116 slots[slot].buffer_state = BufferState::Acquired;
117 slots[slot].fence = Fence::NoFence();
118 }
119
120 // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr
121 // to avoid unnecessarily remapping this buffer on the consumer side.
122 if (out_buffer->acquire_called) {
123 out_buffer->graphic_buffer = nullptr;
124 }
125
126 core->queue.erase(front);
127
128 // We might have freed a slot while dropping old buffers, or the producer may be blocked
129 // waiting for the number of buffers in the queue to decrease.
130 core->SignalDequeueCondition();
131 }
132
133 if (listener != nullptr) {
134 for (s32 i = 0; i < num_dropped_buffers; ++i) {
135 listener->OnBufferReleased();
136 }
137 }
138
139 return Status::NoError;
140}
141
142Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence) {
143 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
144 LOG_ERROR(Service_NVFlinger, "slot {} out of range", slot);
145 return Status::BadValue;
146 }
147
148 std::shared_ptr<IProducerListener> listener;
149 {
150 std::unique_lock lock(core->mutex);
151
152 // If the frame number has changed because the buffer has been reallocated, we can ignore
153 // this ReleaseBuffer for the old buffer.
154 if (frame_number != slots[slot].frame_number) {
155 return Status::StaleBufferSlot;
156 }
157
158 // Make sure this buffer hasn't been queued while acquired by the consumer.
159 auto current(core->queue.begin());
160 while (current != core->queue.end()) {
161 if (current->slot == slot) {
162 LOG_ERROR(Service_NVFlinger, "buffer slot {} pending release is currently queued",
163 slot);
164 return Status::BadValue;
165 }
166 ++current;
167 }
168
169 if (slots[slot].buffer_state == BufferState::Acquired) {
170 slots[slot].fence = release_fence;
171 slots[slot].buffer_state = BufferState::Free;
172
173 core->free_buffers.push_back(slot);
174
175 listener = core->connected_producer_listener;
176
177 LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot);
178 } else if (slots[slot].needs_cleanup_on_release) {
179 LOG_DEBUG(Service_NVFlinger, "releasing a stale buffer slot {} (state = {})", slot,
180 slots[slot].buffer_state);
181
182 slots[slot].needs_cleanup_on_release = false;
183
184 return Status::StaleBufferSlot;
185 } else {
186 LOG_ERROR(Service_NVFlinger, "attempted to release buffer slot {} but its state was {}",
187 slot, slots[slot].buffer_state);
188
189 return Status::BadValue;
190 }
191
192 core->dequeue_condition.notify_all();
193 }
194
195 // Call back without lock held
196 if (listener != nullptr) {
197 listener->OnBufferReleased();
198 }
199
200 return Status::NoError;
201}
202
203Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_listener,
204 bool controlled_by_app) {
205 if (consumer_listener == nullptr) {
206 LOG_ERROR(Service_NVFlinger, "consumer_listener may not be nullptr");
207 return Status::BadValue;
208 }
209
210 LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app);
211
212 BufferQueueCore::AutoLock lock(core);
213
214 if (core->is_abandoned) {
215 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
216 return Status::NoInit;
217 }
218
219 core->consumer_listener = consumer_listener;
220 core->consumer_controlled_by_app = controlled_by_app;
221
222 return Status::NoError;
223}
224
225} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvflinger/buffer_queue_consumer.h
new file mode 100644
index 000000000..f22854394
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.h
@@ -0,0 +1,37 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueConsumer.h
6
7#pragma once
8
9#include <chrono>
10#include <memory>
11
12#include "common/common_types.h"
13#include "core/hle/service/nvflinger/buffer_queue_defs.h"
14#include "core/hle/service/nvflinger/status.h"
15
16namespace Service::android {
17
18class BufferItem;
19class BufferQueueCore;
20class IConsumerListener;
21
22class BufferQueueConsumer final {
23public:
24 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
25 ~BufferQueueConsumer();
26
27 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present,
28 u64 max_frame_number = 0);
29 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
30 Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
31
32private:
33 std::shared_ptr<BufferQueueCore> core;
34 BufferQueueDefs::SlotsType& slots;
35};
36
37} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
new file mode 100644
index 000000000..eb93b43ee
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -0,0 +1,134 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueCore.cpp
6
7#include "common/assert.h"
8
9#include "core/hle/service/nvflinger/buffer_queue_core.h"
10
11namespace Service::android {
12
13BufferQueueCore::BufferQueueCore() : lock{mutex, std::defer_lock} {
14 for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
15 free_slots.insert(slot);
16 }
17}
18
19BufferQueueCore::~BufferQueueCore() = default;
20
21void BufferQueueCore::NotifyShutdown() {
22 std::unique_lock lk(mutex);
23
24 is_shutting_down = true;
25
26 SignalDequeueCondition();
27}
28
29void BufferQueueCore::SignalDequeueCondition() {
30 dequeue_condition.notify_all();
31}
32
33bool BufferQueueCore::WaitForDequeueCondition() {
34 if (is_shutting_down) {
35 return false;
36 }
37
38 dequeue_condition.wait(lock);
39
40 return true;
41}
42
43s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const {
44 // If DequeueBuffer is allowed to error out, we don't have to add an extra buffer.
45 if (!use_async_buffer) {
46 return max_acquired_buffer_count;
47 }
48
49 if (dequeue_buffer_cannot_block || async) {
50 return max_acquired_buffer_count + 1;
51 }
52
53 return max_acquired_buffer_count;
54}
55
56s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const {
57 return GetMinUndequeuedBufferCountLocked(async) + 1;
58}
59
60s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const {
61 const auto min_buffer_count = GetMinMaxBufferCountLocked(async);
62 auto max_buffer_count = std::max(default_max_buffer_count, min_buffer_count);
63
64 if (override_max_buffer_count != 0) {
65 ASSERT(override_max_buffer_count >= min_buffer_count);
66 max_buffer_count = override_max_buffer_count;
67 }
68
69 // Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed
70 // need to have their slots preserved.
71 for (s32 slot = max_buffer_count; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
72 const auto state = slots[slot].buffer_state;
73 if (state == BufferState::Queued || state == BufferState::Dequeued) {
74 max_buffer_count = slot + 1;
75 }
76 }
77
78 return max_buffer_count;
79}
80
81s32 BufferQueueCore::GetPreallocatedBufferCountLocked() const {
82 return static_cast<s32>(std::count_if(slots.begin(), slots.end(),
83 [](const auto& slot) { return slot.is_preallocated; }));
84}
85
86void BufferQueueCore::FreeBufferLocked(s32 slot) {
87 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
88
89 const auto had_buffer = slots[slot].graphic_buffer != nullptr;
90
91 slots[slot].graphic_buffer.reset();
92
93 if (slots[slot].buffer_state == BufferState::Acquired) {
94 slots[slot].needs_cleanup_on_release = true;
95 }
96
97 if (slots[slot].buffer_state != BufferState::Free) {
98 free_slots.insert(slot);
99 } else if (had_buffer) {
100 // If the slot was FREE, but we had a buffer, we need to move this slot from the free
101 // buffers list to the the free slots list.
102 free_buffers.remove(slot);
103 free_slots.insert(slot);
104 }
105
106 slots[slot].buffer_state = BufferState::Free;
107 slots[slot].acquire_called = false;
108 slots[slot].frame_number = 0;
109 slots[slot].fence = Fence::NoFence();
110}
111
112void BufferQueueCore::FreeAllBuffersLocked() {
113 queue.clear();
114 buffer_has_been_queued = false;
115
116 for (s32 slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
117 FreeBufferLocked(slot);
118 }
119}
120
121bool BufferQueueCore::StillTracking(const BufferItem& item) const {
122 const BufferSlot& slot = slots[item.slot];
123
124 return (slot.graphic_buffer != nullptr) && (item.graphic_buffer == slot.graphic_buffer);
125}
126
127void BufferQueueCore::WaitWhileAllocatingLocked() const {
128 while (is_allocating) {
129 std::unique_lock lk(mutex);
130 is_allocating_condition.wait(lk);
131 }
132}
133
134} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h
new file mode 100644
index 000000000..a3cd89f1c
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.h
@@ -0,0 +1,99 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueCore.h
6
7#pragma once
8
9#include <condition_variable>
10#include <list>
11#include <memory>
12#include <mutex>
13#include <set>
14#include <vector>
15
16#include "core/hle/service/nvflinger/buffer_item.h"
17#include "core/hle/service/nvflinger/buffer_queue_defs.h"
18#include "core/hle/service/nvflinger/pixel_format.h"
19#include "core/hle/service/nvflinger/status.h"
20#include "core/hle/service/nvflinger/window.h"
21
22namespace Service::android {
23
24class IConsumerListener;
25class IProducerListener;
26
27class BufferQueueCore final {
28 friend class BufferQueueProducer;
29 friend class BufferQueueConsumer;
30
31public:
32 static constexpr s32 INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT;
33
34 BufferQueueCore();
35 ~BufferQueueCore();
36
37 void NotifyShutdown();
38
39private:
40 void SignalDequeueCondition();
41 bool WaitForDequeueCondition();
42
43 s32 GetMinUndequeuedBufferCountLocked(bool async) const;
44 s32 GetMinMaxBufferCountLocked(bool async) const;
45 s32 GetMaxBufferCountLocked(bool async) const;
46 s32 GetPreallocatedBufferCountLocked() const;
47 void FreeBufferLocked(s32 slot);
48 void FreeAllBuffersLocked();
49 bool StillTracking(const BufferItem& item) const;
50 void WaitWhileAllocatingLocked() const;
51
52private:
53 class AutoLock final {
54 public:
55 AutoLock(std::shared_ptr<BufferQueueCore>& core_) : core{core_} {
56 core->lock.lock();
57 }
58
59 ~AutoLock() {
60 core->lock.unlock();
61 }
62
63 private:
64 std::shared_ptr<BufferQueueCore>& core;
65 };
66
67private:
68 mutable std::mutex mutex;
69 mutable std::unique_lock<std::mutex> lock;
70 bool is_abandoned{};
71 bool consumer_controlled_by_app{};
72 std::shared_ptr<IConsumerListener> consumer_listener;
73 u32 consumer_usage_bit{};
74 NativeWindowApi connected_api{NativeWindowApi::NoConnectedApi};
75 std::shared_ptr<IProducerListener> connected_producer_listener;
76 BufferQueueDefs::SlotsType slots{};
77 std::vector<BufferItem> queue;
78 std::set<s32> free_slots;
79 std::list<s32> free_buffers;
80 s32 override_max_buffer_count{};
81 mutable std::condition_variable dequeue_condition;
82 const bool use_async_buffer{}; // This is always disabled on HOS
83 bool dequeue_buffer_cannot_block{};
84 PixelFormat default_buffer_format{PixelFormat::Rgba8888};
85 u32 default_width{1};
86 u32 default_height{1};
87 s32 default_max_buffer_count{2};
88 const s32 max_acquired_buffer_count{}; // This is always zero on HOS
89 bool buffer_has_been_queued{};
90 u64 frame_counter{};
91 u32 transform_hint{};
92 bool is_allocating{};
93 mutable std::condition_variable is_allocating_condition;
94 bool allow_allocation{true};
95 u64 buffer_age{};
96 bool is_shutting_down{};
97};
98
99} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_defs.h b/src/core/hle/service/nvflinger/buffer_queue_defs.h
new file mode 100644
index 000000000..387d3d36a
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_defs.h
@@ -0,0 +1,21 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueDefs.h
6
7#pragma once
8
9#include <array>
10
11#include "common/common_types.h"
12#include "core/hle/service/nvflinger/buffer_slot.h"
13
14namespace Service::android::BufferQueueDefs {
15
16// BufferQueue will keep track of at most this value of buffers.
17constexpr s32 NUM_BUFFER_SLOTS = 64;
18
19using SlotsType = std::array<BufferSlot, NUM_BUFFER_SLOTS>;
20
21} // namespace Service::android::BufferQueueDefs
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
new file mode 100644
index 000000000..078091904
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -0,0 +1,937 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueProducer.cpp
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "common/settings.h"
10#include "core/core.h"
11#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/kernel/k_event.h"
13#include "core/hle/kernel/k_readable_event.h"
14#include "core/hle/kernel/k_writable_event.h"
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/service/kernel_helpers.h"
17#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue_core.h"
19#include "core/hle/service/nvflinger/buffer_queue_producer.h"
20#include "core/hle/service/nvflinger/consumer_listener.h"
21#include "core/hle/service/nvflinger/parcel.h"
22#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
23#include "core/hle/service/nvflinger/window.h"
24#include "core/hle/service/vi/vi.h"
25
26namespace Service::android {
27
28BufferQueueProducer::BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
29 std::shared_ptr<BufferQueueCore> buffer_queue_core_)
30 : service_context{service_context_}, core{std::move(buffer_queue_core_)}, slots(core->slots) {
31 buffer_wait_event = service_context.CreateEvent("BufferQueue:WaitEvent");
32}
33
34BufferQueueProducer::~BufferQueueProducer() {
35 service_context.CloseEvent(buffer_wait_event);
36}
37
38Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) {
39 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
40
41 BufferQueueCore::AutoLock lock(core);
42
43 if (core->is_abandoned) {
44 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
45 return Status::NoInit;
46 }
47 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
48 LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
49 BufferQueueDefs::NUM_BUFFER_SLOTS);
50 return Status::BadValue;
51 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
52 LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
53 slots[slot].buffer_state);
54 return Status::BadValue;
55 }
56
57 slots[slot].request_buffer_called = true;
58 *buf = slots[slot].graphic_buffer;
59
60 return Status::NoError;
61}
62
63Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
64 LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count);
65 std::shared_ptr<IConsumerListener> listener;
66
67 {
68 BufferQueueCore::AutoLock lock(core);
69 core->WaitWhileAllocatingLocked();
70 if (core->is_abandoned) {
71 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
72 return Status::NoInit;
73 }
74
75 if (buffer_count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
76 LOG_ERROR(Service_NVFlinger, "buffer_count {} too large (max {})", buffer_count,
77 BufferQueueDefs::NUM_BUFFER_SLOTS);
78 return Status::BadValue;
79 }
80
81 // There must be no dequeued buffers when changing the buffer count.
82 for (s32 s{}; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
83 if (slots[s].buffer_state == BufferState::Dequeued) {
84 LOG_ERROR(Service_NVFlinger, "buffer owned by producer");
85 return Status::BadValue;
86 }
87 }
88
89 if (buffer_count == 0) {
90 core->override_max_buffer_count = 0;
91 core->SignalDequeueCondition();
92 return Status::NoError;
93 }
94
95 const s32 min_buffer_slots = core->GetMinMaxBufferCountLocked(false);
96 if (buffer_count < min_buffer_slots) {
97 LOG_ERROR(Service_NVFlinger, "requested buffer count {} is less than minimum {}",
98 buffer_count, min_buffer_slots);
99 return Status::BadValue;
100 }
101
102 // Here we are guaranteed that the producer doesn't have any dequeued buffers and will
103 // release all of its buffer references.
104 if (core->GetPreallocatedBufferCountLocked() <= 0) {
105 core->FreeAllBuffersLocked();
106 }
107
108 core->override_max_buffer_count = buffer_count;
109 core->SignalDequeueCondition();
110 buffer_wait_event->GetWritableEvent().Signal();
111 listener = core->consumer_listener;
112 }
113
114 // Call back without lock held
115 if (listener != nullptr) {
116 listener->OnBuffersReleased();
117 }
118
119 return Status::NoError;
120}
121
122Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
123 Status* returnFlags) const {
124 bool try_again = true;
125
126 while (try_again) {
127 if (core->is_abandoned) {
128 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
129 return Status::NoInit;
130 }
131
132 const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
133 if (async && core->override_max_buffer_count) {
134 if (core->override_max_buffer_count < max_buffer_count) {
135 LOG_ERROR(Service_NVFlinger, "async mode is invalid with buffer count override");
136 return Status::BadValue;
137 }
138 }
139
140 // Free up any buffers that are in slots beyond the max buffer count
141 for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
142 ASSERT(slots[s].buffer_state == BufferState::Free);
143 if (slots[s].graphic_buffer != nullptr) {
144 core->FreeBufferLocked(s);
145 *returnFlags |= Status::ReleaseAllBuffers;
146 }
147 }
148
149 s32 dequeued_count{};
150 s32 acquired_count{};
151 for (s32 s{}; s < max_buffer_count; ++s) {
152 switch (slots[s].buffer_state) {
153 case BufferState::Dequeued:
154 ++dequeued_count;
155 break;
156 case BufferState::Acquired:
157 ++acquired_count;
158 break;
159 default:
160 break;
161 }
162 }
163
164 // Producers are not allowed to dequeue more than one buffer if they did not set a buffer
165 // count
166 if (!core->override_max_buffer_count && dequeued_count) {
167 LOG_ERROR(Service_NVFlinger,
168 "can't dequeue multiple buffers without setting the buffer count");
169 return Status::InvalidOperation;
170 }
171
172 // See whether a buffer has been queued since the last SetBufferCount so we know whether to
173 // perform the min undequeued buffers check below
174 if (core->buffer_has_been_queued) {
175 // Make sure the producer is not trying to dequeue more buffers than allowed
176 const s32 new_undequeued_count = max_buffer_count - (dequeued_count + 1);
177 const s32 min_undequeued_count = core->GetMinUndequeuedBufferCountLocked(async);
178 if (new_undequeued_count < min_undequeued_count) {
179 LOG_ERROR(Service_NVFlinger,
180 "min undequeued buffer count({}) exceeded (dequeued={} undequeued={})",
181 min_undequeued_count, dequeued_count, new_undequeued_count);
182 return Status::InvalidOperation;
183 }
184 }
185
186 *found = BufferQueueCore::INVALID_BUFFER_SLOT;
187
188 // If we disconnect and reconnect quickly, we can be in a state where our slots are empty
189 // but we have many buffers in the queue. This can cause us to run out of memory if we
190 // outrun the consumer. Wait here if it looks like we have too many buffers queued up.
191 const bool too_many_buffers = core->queue.size() > static_cast<size_t>(max_buffer_count);
192 if (too_many_buffers) {
193 LOG_ERROR(Service_NVFlinger, "queue size is {}, waiting", core->queue.size());
194 } else {
195 if (!core->free_buffers.empty()) {
196 auto slot = core->free_buffers.begin();
197 *found = *slot;
198 core->free_buffers.erase(slot);
199 } else if (core->allow_allocation && !core->free_slots.empty()) {
200 auto slot = core->free_slots.begin();
201 // Only return free slots up to the max buffer count
202 if (*slot < max_buffer_count) {
203 *found = *slot;
204 core->free_slots.erase(slot);
205 }
206 }
207 }
208
209 // If no buffer is found, or if the queue has too many buffers outstanding, wait for a
210 // buffer to be acquired or released, or for the max buffer count to change.
211 try_again = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) || too_many_buffers;
212 if (try_again) {
213 // Return an error if we're in non-blocking mode (producer and consumer are controlled
214 // by the application).
215 if (core->dequeue_buffer_cannot_block &&
216 (acquired_count <= core->max_acquired_buffer_count)) {
217 return Status::WouldBlock;
218 }
219
220 if (!core->WaitForDequeueCondition()) {
221 // We are no longer running
222 return Status::NoError;
223 }
224 }
225 }
226
227 return Status::NoError;
228}
229
230Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool async, u32 width,
231 u32 height, PixelFormat format, u32 usage) {
232 LOG_DEBUG(Service_NVFlinger, "async={} w={} h={} format={}, usage={}", async ? "true" : "false",
233 width, height, format, usage);
234
235 if ((width != 0 && height == 0) || (width == 0 && height != 0)) {
236 LOG_ERROR(Service_NVFlinger, "invalid size: w={} h={}", width, height);
237 return Status::BadValue;
238 }
239
240 Status return_flags = Status::NoError;
241 bool attached_by_consumer = false;
242 {
243 BufferQueueCore::AutoLock lock(core);
244 core->WaitWhileAllocatingLocked();
245 if (format == PixelFormat::NoFormat) {
246 format = core->default_buffer_format;
247 }
248
249 // Enable the usage bits the consumer requested
250 usage |= core->consumer_usage_bit;
251 const bool use_default_size = !width && !height;
252 if (use_default_size) {
253 width = core->default_width;
254 height = core->default_height;
255 }
256
257 s32 found = BufferItem::INVALID_BUFFER_SLOT;
258 while (found == BufferItem::INVALID_BUFFER_SLOT) {
259 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags);
260 if (status != Status::NoError) {
261 return status;
262 }
263
264 // This should not happen
265 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
266 LOG_DEBUG(Service_NVFlinger, "no available buffer slots");
267 return Status::Busy;
268 }
269
270 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
271
272 // If we are not allowed to allocate new buffers, WaitForFreeSlotThenRelock must have
273 // returned a slot containing a buffer. If this buffer would require reallocation to
274 // meet the requested attributes, we free it and attempt to get another one.
275 if (!core->allow_allocation) {
276 if (buffer->NeedsReallocation(width, height, format, usage)) {
277 core->FreeBufferLocked(found);
278 found = BufferItem::INVALID_BUFFER_SLOT;
279 continue;
280 }
281 }
282 }
283
284 *out_slot = found;
285 attached_by_consumer = slots[found].attached_by_consumer;
286 slots[found].buffer_state = BufferState::Dequeued;
287
288 const std::shared_ptr<GraphicBuffer>& buffer(slots[found].graphic_buffer);
289
290 if ((buffer == nullptr) || buffer->NeedsReallocation(width, height, format, usage)) {
291 slots[found].acquire_called = false;
292 slots[found].graphic_buffer = nullptr;
293 slots[found].request_buffer_called = false;
294 slots[found].fence = Fence::NoFence();
295 core->buffer_age = 0;
296 return_flags |= Status::BufferNeedsReallocation;
297 } else {
298 // We add 1 because that will be the frame number when this buffer
299 // is queued
300 core->buffer_age = core->frame_counter + 1 - slots[found].frame_number;
301 }
302
303 LOG_DEBUG(Service_NVFlinger, "setting buffer age to {}", core->buffer_age);
304
305 *out_fence = slots[found].fence;
306
307 slots[found].fence = Fence::NoFence();
308 }
309
310 if ((return_flags & Status::BufferNeedsReallocation) != Status::None) {
311 LOG_DEBUG(Service_NVFlinger, "allocating a new buffer for slot {}", *out_slot);
312
313 auto graphic_buffer = std::make_shared<GraphicBuffer>(width, height, format, usage);
314 if (graphic_buffer == nullptr) {
315 LOG_ERROR(Service_NVFlinger, "creating GraphicBuffer failed");
316 return Status::NoMemory;
317 }
318
319 {
320 BufferQueueCore::AutoLock lock(core);
321 if (core->is_abandoned) {
322 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
323 return Status::NoInit;
324 }
325
326 slots[*out_slot].graphic_buffer = graphic_buffer;
327 }
328 }
329
330 if (attached_by_consumer) {
331 return_flags |= Status::BufferNeedsReallocation;
332 }
333
334 LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot,
335 slots[*out_slot].frame_number, return_flags);
336 return return_flags;
337}
338
339Status BufferQueueProducer::DetachBuffer(s32 slot) {
340 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
341
342 BufferQueueCore::AutoLock lock(core);
343 if (core->is_abandoned) {
344 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
345 return Status::NoInit;
346 }
347
348 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
349 LOG_ERROR(Service_NVFlinger, "slot {} out of range [0, {})", slot,
350 BufferQueueDefs::NUM_BUFFER_SLOTS);
351 return Status::BadValue;
352 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
353 LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
354 slots[slot].buffer_state);
355 return Status::BadValue;
356 } else if (!slots[slot].request_buffer_called) {
357 LOG_ERROR(Service_NVFlinger, "buffer in slot {} has not been requested", slot);
358 return Status::BadValue;
359 }
360
361 core->FreeBufferLocked(slot);
362 core->SignalDequeueCondition();
363
364 return Status::NoError;
365}
366
367Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer,
368 Fence* out_fence) {
369 if (out_buffer == nullptr) {
370 LOG_ERROR(Service_NVFlinger, "out_buffer must not be nullptr");
371 return Status::BadValue;
372 } else if (out_fence == nullptr) {
373 LOG_ERROR(Service_NVFlinger, "out_fence must not be nullptr");
374 return Status::BadValue;
375 }
376
377 BufferQueueCore::AutoLock lock(core);
378
379 core->WaitWhileAllocatingLocked();
380
381 if (core->is_abandoned) {
382 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
383 return Status::NoInit;
384 }
385 if (core->free_buffers.empty()) {
386 return Status::NoMemory;
387 }
388
389 const s32 found = core->free_buffers.front();
390 core->free_buffers.remove(found);
391
392 LOG_DEBUG(Service_NVFlinger, "Detached slot {}", found);
393
394 *out_buffer = slots[found].graphic_buffer;
395 *out_fence = slots[found].fence;
396
397 core->FreeBufferLocked(found);
398
399 return Status::NoError;
400}
401
402Status BufferQueueProducer::AttachBuffer(s32* out_slot,
403 const std::shared_ptr<GraphicBuffer>& buffer) {
404 if (out_slot == nullptr) {
405 LOG_ERROR(Service_NVFlinger, "out_slot must not be nullptr");
406 return Status::BadValue;
407 } else if (buffer == nullptr) {
408 LOG_ERROR(Service_NVFlinger, "Cannot attach nullptr buffer");
409 return Status::BadValue;
410 }
411
412 BufferQueueCore::AutoLock lock(core);
413 core->WaitWhileAllocatingLocked();
414
415 Status return_flags = Status::NoError;
416 s32 found{};
417
418 const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags);
419 if (status != Status::NoError) {
420 return status;
421 }
422
423 if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
424 LOG_ERROR(Service_NVFlinger, "No available buffer slots");
425 return Status::Busy;
426 }
427
428 *out_slot = found;
429
430 LOG_DEBUG(Service_NVFlinger, "Returning slot {} flags={}", *out_slot, return_flags);
431
432 slots[*out_slot].graphic_buffer = buffer;
433 slots[*out_slot].buffer_state = BufferState::Dequeued;
434 slots[*out_slot].fence = Fence::NoFence();
435 slots[*out_slot].request_buffer_called = true;
436
437 return return_flags;
438}
439
440Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
441 QueueBufferOutput* output) {
442 s64 timestamp{};
443 bool is_auto_timestamp{};
444 Common::Rectangle<s32> crop;
445 NativeWindowScalingMode scaling_mode{};
446 NativeWindowTransform transform;
447 u32 sticky_transform_{};
448 bool async{};
449 s32 swap_interval{};
450 Fence fence{};
451
452 input.Deflate(&timestamp, &is_auto_timestamp, &crop, &scaling_mode, &transform,
453 &sticky_transform_, &async, &swap_interval, &fence);
454
455 switch (scaling_mode) {
456 case NativeWindowScalingMode::Freeze:
457 case NativeWindowScalingMode::ScaleToWindow:
458 case NativeWindowScalingMode::ScaleCrop:
459 case NativeWindowScalingMode::NoScaleCrop:
460 break;
461 default:
462 LOG_ERROR(Service_NVFlinger, "unknown scaling mode {}", scaling_mode);
463 return Status::BadValue;
464 }
465
466 std::shared_ptr<IConsumerListener> frameAvailableListener;
467 std::shared_ptr<IConsumerListener> frameReplacedListener;
468 s32 callback_ticket{};
469 BufferItem item;
470
471 {
472 BufferQueueCore::AutoLock lock(core);
473
474 if (core->is_abandoned) {
475 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
476 return Status::NoInit;
477 }
478
479 const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
480 if (async && core->override_max_buffer_count) {
481 if (core->override_max_buffer_count < max_buffer_count) {
482 LOG_ERROR(Service_NVFlinger, "async mode is invalid with "
483 "buffer count override");
484 return Status::BadValue;
485 }
486 }
487
488 if (slot < 0 || slot >= max_buffer_count) {
489 LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
490 max_buffer_count);
491 return Status::BadValue;
492 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
493 LOG_ERROR(Service_NVFlinger,
494 "slot {} is not owned by the producer "
495 "(state = {})",
496 slot, slots[slot].buffer_state);
497 return Status::BadValue;
498 } else if (!slots[slot].request_buffer_called) {
499 LOG_ERROR(Service_NVFlinger,
500 "slot {} was queued without requesting "
501 "a buffer",
502 slot);
503 return Status::BadValue;
504 }
505
506 LOG_DEBUG(Service_NVFlinger,
507 "slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot,
508 core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(),
509 crop.Bottom(), transform, scaling_mode);
510
511 const std::shared_ptr<GraphicBuffer>& graphic_buffer(slots[slot].graphic_buffer);
512 Common::Rectangle<s32> buffer_rect(graphic_buffer->Width(), graphic_buffer->Height());
513 Common::Rectangle<s32> cropped_rect;
514 [[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect);
515
516 if (cropped_rect != crop) {
517 LOG_ERROR(Service_NVFlinger, "crop rect is not contained within the buffer in slot {}",
518 slot);
519 return Status::BadValue;
520 }
521
522 slots[slot].fence = fence;
523 slots[slot].buffer_state = BufferState::Queued;
524 ++core->frame_counter;
525 slots[slot].frame_number = core->frame_counter;
526
527 item.acquire_called = slots[slot].acquire_called;
528 item.graphic_buffer = slots[slot].graphic_buffer;
529 item.crop = crop;
530 item.transform = transform & ~NativeWindowTransform::InverseDisplay;
531 item.transform_to_display_inverse =
532 (transform & NativeWindowTransform::InverseDisplay) != NativeWindowTransform::None;
533 item.scaling_mode = static_cast<u32>(scaling_mode);
534 item.timestamp = timestamp;
535 item.is_auto_timestamp = is_auto_timestamp;
536 item.frame_number = core->frame_counter;
537 item.slot = slot;
538 item.fence = fence;
539 item.is_droppable = core->dequeue_buffer_cannot_block || async;
540 item.swap_interval = swap_interval;
541 sticky_transform = sticky_transform_;
542
543 if (core->queue.empty()) {
544 // When the queue is empty, we can simply queue this buffer
545 core->queue.push_back(item);
546 frameAvailableListener = core->consumer_listener;
547 } else {
548 // When the queue is not empty, we need to look at the front buffer
549 // state to see if we need to replace it
550 auto front(core->queue.begin());
551
552 if (front->is_droppable) {
553 // If the front queued buffer is still being tracked, we first
554 // mark it as freed
555 if (core->StillTracking(*front)) {
556 slots[front->slot].buffer_state = BufferState::Free;
557 core->free_buffers.push_front(front->slot);
558 }
559 // Overwrite the droppable buffer with the incoming one
560 *front = item;
561 frameReplacedListener = core->consumer_listener;
562 } else {
563 core->queue.push_back(item);
564 frameAvailableListener = core->consumer_listener;
565 }
566 }
567
568 core->buffer_has_been_queued = true;
569 core->SignalDequeueCondition();
570 output->Inflate(core->default_width, core->default_height, core->transform_hint,
571 static_cast<u32>(core->queue.size()));
572
573 // Take a ticket for the callback functions
574 callback_ticket = next_callback_ticket++;
575 }
576
577 // Don't send the GraphicBuffer through the callback, and don't send the slot number, since the
578 // consumer shouldn't need it
579 item.graphic_buffer.reset();
580 item.slot = BufferItem::INVALID_BUFFER_SLOT;
581
582 // Call back without the main BufferQueue lock held, but with the callback lock held so we can
583 // ensure that callbacks occur in order
584 {
585 std::unique_lock lock(callback_mutex);
586 while (callback_ticket != current_callback_ticket) {
587 std::unique_lock<std::mutex> lk(callback_mutex);
588 callback_condition.wait(lk);
589 }
590
591 if (frameAvailableListener != nullptr) {
592 frameAvailableListener->OnFrameAvailable(item);
593 } else if (frameReplacedListener != nullptr) {
594 frameReplacedListener->OnFrameReplaced(item);
595 }
596
597 ++current_callback_ticket;
598 callback_condition.notify_all();
599 }
600
601 return Status::NoError;
602}
603
604void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {
605 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
606
607 BufferQueueCore::AutoLock lock(core);
608
609 if (core->is_abandoned) {
610 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
611 return;
612 }
613
614 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
615 LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
616 BufferQueueDefs::NUM_BUFFER_SLOTS);
617 return;
618 } else if (slots[slot].buffer_state != BufferState::Dequeued) {
619 LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
620 slots[slot].buffer_state);
621 return;
622 }
623
624 core->free_buffers.push_front(slot);
625 slots[slot].buffer_state = BufferState::Free;
626 slots[slot].fence = fence;
627
628 core->SignalDequeueCondition();
629 buffer_wait_event->GetWritableEvent().Signal();
630}
631
632Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
633 BufferQueueCore::AutoLock lock(core);
634
635 if (out_value == nullptr) {
636 LOG_ERROR(Service_NVFlinger, "outValue was nullptr");
637 return Status::BadValue;
638 }
639
640 if (core->is_abandoned) {
641 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
642 return Status::NoInit;
643 }
644
645 u32 value{};
646 switch (what) {
647 case NativeWindow::Width:
648 value = core->default_width;
649 break;
650 case NativeWindow::Height:
651 value = core->default_height;
652 break;
653 case NativeWindow::Format:
654 value = static_cast<u32>(core->default_buffer_format);
655 break;
656 case NativeWindow::MinUndequeedBuffers:
657 value = core->GetMinUndequeuedBufferCountLocked(false);
658 break;
659 case NativeWindow::StickyTransform:
660 value = sticky_transform;
661 break;
662 case NativeWindow::ConsumerRunningBehind:
663 value = (core->queue.size() > 1);
664 break;
665 case NativeWindow::ConsumerUsageBits:
666 value = core->consumer_usage_bit;
667 break;
668 case NativeWindow::BufferAge:
669 if (core->buffer_age > INT32_MAX) {
670 value = 0;
671 } else {
672 value = static_cast<u32>(core->buffer_age);
673 }
674 break;
675 default:
676 UNREACHABLE();
677 return Status::BadValue;
678 }
679
680 LOG_DEBUG(Service_NVFlinger, "what = {}, value = {}", what, value);
681
682 *out_value = static_cast<s32>(value);
683
684 return Status::NoError;
685}
686
687Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& listener,
688 NativeWindowApi api, bool producer_controlled_by_app,
689 QueueBufferOutput* output) {
690 BufferQueueCore::AutoLock lock(core);
691
692 LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api,
693 producer_controlled_by_app);
694
695 if (core->is_abandoned) {
696 LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
697 return Status::NoInit;
698 }
699
700 if (core->consumer_listener == nullptr) {
701 LOG_ERROR(Service_NVFlinger, "BufferQueue has no consumer");
702 return Status::NoInit;
703 }
704
705 if (output == nullptr) {
706 LOG_ERROR(Service_NVFlinger, "output was nullptr");
707 return Status::BadValue;
708 }
709
710 if (core->connected_api != NativeWindowApi::NoConnectedApi) {
711 LOG_ERROR(Service_NVFlinger, "already connected (cur = {} req = {})", core->connected_api,
712 api);
713 return Status::BadValue;
714 }
715
716 Status status = Status::NoError;
717 switch (api) {
718 case NativeWindowApi::Egl:
719 case NativeWindowApi::Cpu:
720 case NativeWindowApi::Media:
721 case NativeWindowApi::Camera:
722 core->connected_api = api;
723 output->Inflate(core->default_width, core->default_height, core->transform_hint,
724 static_cast<u32>(core->queue.size()));
725 core->connected_producer_listener = listener;
726 break;
727 default:
728 LOG_ERROR(Service_NVFlinger, "unknown api = {}", api);
729 status = Status::BadValue;
730 break;
731 }
732
733 core->buffer_has_been_queued = false;
734 core->dequeue_buffer_cannot_block =
735 core->consumer_controlled_by_app && producer_controlled_by_app;
736 core->allow_allocation = true;
737
738 return status;
739}
740
741Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
742 LOG_DEBUG(Service_NVFlinger, "api = {}", api);
743
744 Status status = Status::NoError;
745 std::shared_ptr<IConsumerListener> listener;
746
747 {
748 BufferQueueCore::AutoLock lock(core);
749
750 core->WaitWhileAllocatingLocked();
751
752 if (core->is_abandoned) {
753 // Disconnecting after the surface has been abandoned is a no-op.
754 return Status::NoError;
755 }
756
757 switch (api) {
758 case NativeWindowApi::Egl:
759 case NativeWindowApi::Cpu:
760 case NativeWindowApi::Media:
761 case NativeWindowApi::Camera:
762 if (core->connected_api == api) {
763 core->FreeAllBuffersLocked();
764 core->connected_producer_listener = nullptr;
765 core->connected_api = NativeWindowApi::NoConnectedApi;
766 core->SignalDequeueCondition();
767 buffer_wait_event->GetWritableEvent().Signal();
768 listener = core->consumer_listener;
769 } else if (core->connected_api != NativeWindowApi::NoConnectedApi) {
770 LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})",
771 core->connected_api, api);
772 status = Status::BadValue;
773 }
774 break;
775 default:
776 LOG_ERROR(Service_NVFlinger, "unknown api = {}", api);
777 status = Status::BadValue;
778 break;
779 }
780 }
781
782 // Call back without lock held
783 if (listener != nullptr) {
784 listener->OnBuffersReleased();
785 }
786
787 return status;
788}
789
790Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
791 const std::shared_ptr<GraphicBuffer>& buffer) {
792 LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
793
794 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
795 return Status::BadValue;
796 }
797
798 BufferQueueCore::AutoLock lock(core);
799
800 slots[slot] = {};
801 slots[slot].graphic_buffer = buffer;
802
803 // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for
804 // this to be called with an empty buffer, Naruto Ultimate Ninja Storm is a game that does this.
805 if (buffer) {
806 slots[slot].is_preallocated = true;
807
808 core->override_max_buffer_count = core->GetPreallocatedBufferCountLocked();
809 core->default_width = buffer->Width();
810 core->default_height = buffer->Height();
811 core->default_buffer_format = buffer->Format();
812 }
813
814 core->SignalDequeueCondition();
815 buffer_wait_event->GetWritableEvent().Signal();
816
817 return Status::NoError;
818}
819
820void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) {
821 Status status{Status::NoError};
822 Parcel parcel_in{ctx.ReadBuffer()};
823 Parcel parcel_out{};
824
825 switch (code) {
826 case TransactionId::Connect: {
827 const auto enable_listener = parcel_in.Read<bool>();
828 const auto api = parcel_in.Read<NativeWindowApi>();
829 const auto producer_controlled_by_app = parcel_in.Read<bool>();
830
831 UNIMPLEMENTED_IF_MSG(enable_listener, "Listener is unimplemented!");
832
833 std::shared_ptr<IProducerListener> listener;
834 QueueBufferOutput output{};
835
836 status = Connect(listener, api, producer_controlled_by_app, &output);
837
838 parcel_out.Write(output);
839 break;
840 }
841 case TransactionId::SetPreallocatedBuffer: {
842 const auto slot = parcel_in.Read<s32>();
843 const auto buffer = parcel_in.ReadObject<GraphicBuffer>();
844
845 status = SetPreallocatedBuffer(slot, buffer);
846 break;
847 }
848 case TransactionId::DequeueBuffer: {
849 const auto is_async = parcel_in.Read<bool>();
850 const auto width = parcel_in.Read<u32>();
851 const auto height = parcel_in.Read<u32>();
852 const auto pixel_format = parcel_in.Read<PixelFormat>();
853 const auto usage = parcel_in.Read<u32>();
854
855 s32 slot{};
856 Fence fence{};
857
858 status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage);
859
860 parcel_out.Write(slot);
861 parcel_out.WriteObject(&fence);
862 break;
863 }
864 case TransactionId::RequestBuffer: {
865 const auto slot = parcel_in.Read<s32>();
866
867 std::shared_ptr<GraphicBuffer> buf;
868
869 status = RequestBuffer(slot, &buf);
870
871 parcel_out.WriteObject(buf);
872 break;
873 }
874 case TransactionId::QueueBuffer: {
875 const auto slot = parcel_in.Read<s32>();
876
877 QueueBufferInput input{parcel_in};
878 QueueBufferOutput output;
879
880 status = QueueBuffer(slot, input, &output);
881
882 parcel_out.Write(output);
883 break;
884 }
885 case TransactionId::Query: {
886 const auto what = parcel_in.Read<NativeWindow>();
887
888 s32 value{};
889
890 status = Query(what, &value);
891
892 parcel_out.Write(value);
893 break;
894 }
895 case TransactionId::CancelBuffer: {
896 const auto slot = parcel_in.Read<s32>();
897 const auto fence = parcel_in.ReadFlattened<Fence>();
898
899 CancelBuffer(slot, fence);
900 break;
901 }
902 case TransactionId::Disconnect: {
903 const auto api = parcel_in.Read<NativeWindowApi>();
904
905 status = Disconnect(api);
906 break;
907 }
908 case TransactionId::DetachBuffer: {
909 const auto slot = parcel_in.Read<s32>();
910
911 status = DetachBuffer(slot);
912 break;
913 }
914 case TransactionId::SetBufferCount: {
915 const auto buffer_count = parcel_in.Read<s32>();
916
917 status = SetBufferCount(buffer_count);
918 break;
919 }
920 case TransactionId::GetBufferHistory:
921 LOG_WARNING(Service_NVFlinger, "(STUBBED) called, transaction=GetBufferHistory");
922 break;
923 default:
924 ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
925 break;
926 }
927
928 parcel_out.Write(status);
929
930 ctx.WriteBuffer(parcel_out.Serialize());
931}
932
933Kernel::KReadableEvent& BufferQueueProducer::GetNativeHandle() {
934 return buffer_wait_event->GetReadableEvent();
935}
936
937} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h
new file mode 100644
index 000000000..5ddeebe0c
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h
@@ -0,0 +1,83 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferQueueProducer.h
6
7#pragma once
8
9#include <condition_variable>
10#include <memory>
11#include <mutex>
12
13#include "common/common_funcs.h"
14#include "core/hle/service/nvdrv/nvdata.h"
15#include "core/hle/service/nvflinger/binder.h"
16#include "core/hle/service/nvflinger/buffer_queue_defs.h"
17#include "core/hle/service/nvflinger/buffer_slot.h"
18#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
19#include "core/hle/service/nvflinger/pixel_format.h"
20#include "core/hle/service/nvflinger/status.h"
21#include "core/hle/service/nvflinger/window.h"
22
23namespace Kernel {
24class KernelCore;
25class KEvent;
26class KReadableEvent;
27class KWritableEvent;
28} // namespace Kernel
29
30namespace Service::KernelHelpers {
31class ServiceContext;
32} // namespace Service::KernelHelpers
33
34namespace Service::android {
35
36class BufferQueueCore;
37class IProducerListener;
38
39class BufferQueueProducer final : public IBinder {
40public:
41 explicit BufferQueueProducer(Service::KernelHelpers::ServiceContext& service_context_,
42 std::shared_ptr<BufferQueueCore> buffer_queue_core_);
43 ~BufferQueueProducer();
44
45 void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, u32 flags) override;
46
47 Kernel::KReadableEvent& GetNativeHandle() override;
48
49public:
50 Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
51 Status SetBufferCount(s32 buffer_count);
52 Status DequeueBuffer(s32* out_slot, android::Fence* out_fence, bool async, u32 width,
53 u32 height, PixelFormat format, u32 usage);
54 Status DetachBuffer(s32 slot);
55 Status DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer, Fence* out_fence);
56 Status AttachBuffer(s32* outSlot, const std::shared_ptr<GraphicBuffer>& buffer);
57 Status QueueBuffer(s32 slot, const QueueBufferInput& input, QueueBufferOutput* output);
58 void CancelBuffer(s32 slot, const Fence& fence);
59 Status Query(NativeWindow what, s32* out_value);
60 Status Connect(const std::shared_ptr<IProducerListener>& listener, NativeWindowApi api,
61 bool producer_controlled_by_app, QueueBufferOutput* output);
62
63 Status Disconnect(NativeWindowApi api);
64 Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer);
65
66private:
67 BufferQueueProducer(const BufferQueueProducer&) = delete;
68
69 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* returnFlags) const;
70
71 Kernel::KEvent* buffer_wait_event{};
72 Service::KernelHelpers::ServiceContext& service_context;
73
74 std::shared_ptr<BufferQueueCore> core;
75 BufferQueueDefs::SlotsType& slots;
76 u32 sticky_transform{};
77 std::mutex callback_mutex;
78 s32 next_callback_ticket{};
79 s32 current_callback_ticket{};
80 std::condition_variable callback_condition;
81};
82
83} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h
new file mode 100644
index 000000000..e3ea58910
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_slot.h
@@ -0,0 +1,39 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/BufferSlot.h
6
7#pragma once
8
9#include <memory>
10
11#include "common/common_types.h"
12#include "core/hle/service/nvflinger/ui/fence.h"
13
14namespace Service::android {
15
16class GraphicBuffer;
17
18enum class BufferState : u32 {
19 Free = 0,
20 Dequeued = 1,
21 Queued = 2,
22 Acquired = 3,
23};
24
25struct BufferSlot final {
26 constexpr BufferSlot() = default;
27
28 std::shared_ptr<GraphicBuffer> graphic_buffer;
29 BufferState buffer_state{BufferState::Free};
30 bool request_buffer_called{};
31 u64 frame_number{};
32 Fence fence;
33 bool acquire_called{};
34 bool needs_cleanup_on_release{};
35 bool attached_by_consumer{};
36 bool is_preallocated{};
37};
38
39} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_transform_flags.h b/src/core/hle/service/nvflinger/buffer_transform_flags.h
new file mode 100644
index 000000000..e8e6300e3
--- /dev/null
+++ b/src/core/hle/service/nvflinger/buffer_transform_flags.h
@@ -0,0 +1,25 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::android {
9
10enum class BufferTransformFlags : u32 {
11 /// No transform flags are set
12 Unset = 0x00,
13 /// Flip source image horizontally (around the vertical axis)
14 FlipH = 0x01,
15 /// Flip source image vertically (around the horizontal axis)
16 FlipV = 0x02,
17 /// Rotate source image 90 degrees clockwise
18 Rotate90 = 0x04,
19 /// Rotate source image 180 degrees
20 Rotate180 = 0x03,
21 /// Rotate source image 270 degrees clockwise
22 Rotate270 = 0x07,
23};
24
25} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp
new file mode 100644
index 000000000..3ccbb7fb8
--- /dev/null
+++ b/src/core/hle/service/nvflinger/consumer_base.cpp
@@ -0,0 +1,130 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/ConsumerBase.cpp
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/hle/service/nvflinger/buffer_item.h"
10#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
11#include "core/hle/service/nvflinger/buffer_queue_core.h"
12#include "core/hle/service/nvflinger/consumer_base.h"
13#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
14
15namespace Service::android {
16
17ConsumerBase::ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_)
18 : consumer{std::move(consumer_)} {}
19
20ConsumerBase::~ConsumerBase() {
21 std::unique_lock lock(mutex);
22
23 ASSERT_MSG(is_abandoned, "consumer is not abandoned!");
24}
25
26void ConsumerBase::Connect(bool controlled_by_app) {
27 consumer->Connect(shared_from_this(), controlled_by_app);
28}
29
30void ConsumerBase::FreeBufferLocked(s32 slot_index) {
31 LOG_DEBUG(Service_NVFlinger, "slot_index={}", slot_index);
32
33 slots[slot_index].graphic_buffer = nullptr;
34 slots[slot_index].fence = Fence::NoFence();
35 slots[slot_index].frame_number = 0;
36}
37
38void ConsumerBase::OnFrameAvailable(const BufferItem& item) {
39 std::unique_lock lock(mutex);
40 LOG_DEBUG(Service_NVFlinger, "called");
41}
42
43void ConsumerBase::OnFrameReplaced(const BufferItem& item) {
44 std::unique_lock lock(mutex);
45 LOG_DEBUG(Service_NVFlinger, "called");
46}
47
48void ConsumerBase::OnBuffersReleased() {
49 std::unique_lock lock(mutex);
50 LOG_DEBUG(Service_NVFlinger, "called");
51}
52
53void ConsumerBase::OnSidebandStreamChanged() {}
54
55Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
56 u64 max_frame_number) {
57 if (is_abandoned) {
58 LOG_ERROR(Service_NVFlinger, "consumer is abandoned!");
59 return Status::NoInit;
60 }
61
62 Status err = consumer->AcquireBuffer(item, present_when, max_frame_number);
63 if (err != Status::NoError) {
64 return err;
65 }
66
67 if (item->graphic_buffer != nullptr) {
68 if (slots[item->slot].graphic_buffer != nullptr) {
69 FreeBufferLocked(item->slot);
70 }
71 slots[item->slot].graphic_buffer = item->graphic_buffer;
72 }
73
74 slots[item->slot].frame_number = item->frame_number;
75 slots[item->slot].fence = item->fence;
76
77 LOG_DEBUG(Service_NVFlinger, "slot={}", item->slot);
78
79 return Status::NoError;
80}
81
82Status ConsumerBase::AddReleaseFenceLocked(s32 slot,
83 const std::shared_ptr<GraphicBuffer> graphic_buffer,
84 const Fence& fence) {
85 LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
86
87 // If consumer no longer tracks this graphic_buffer, we can safely
88 // drop this fence, as it will never be received by the producer.
89
90 if (!StillTracking(slot, graphic_buffer)) {
91 return Status::NoError;
92 }
93
94 slots[slot].fence = fence;
95
96 return Status::NoError;
97}
98
99Status ConsumerBase::ReleaseBufferLocked(s32 slot,
100 const std::shared_ptr<GraphicBuffer> graphic_buffer) {
101 // If consumer no longer tracks this graphic_buffer (we received a new
102 // buffer on the same slot), the buffer producer is definitely no longer
103 // tracking it.
104
105 if (!StillTracking(slot, graphic_buffer)) {
106 return Status::NoError;
107 }
108
109 LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
110 Status err = consumer->ReleaseBuffer(slot, slots[slot].frame_number, slots[slot].fence);
111 if (err == Status::StaleBufferSlot) {
112 FreeBufferLocked(slot);
113 }
114
115 slots[slot].fence = Fence::NoFence();
116
117 return err;
118}
119
120bool ConsumerBase::StillTracking(s32 slot,
121 const std::shared_ptr<GraphicBuffer> graphic_buffer) const {
122 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
123 return false;
124 }
125
126 return (slots[slot].graphic_buffer != nullptr &&
127 slots[slot].graphic_buffer->Handle() == graphic_buffer->Handle());
128}
129
130} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h
new file mode 100644
index 000000000..9ab949420
--- /dev/null
+++ b/src/core/hle/service/nvflinger/consumer_base.h
@@ -0,0 +1,61 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/ConsumerBase.h
6
7#pragma once
8
9#include <array>
10#include <chrono>
11#include <memory>
12#include <mutex>
13
14#include "common/common_types.h"
15#include "core/hle/service/nvflinger/buffer_queue_defs.h"
16#include "core/hle/service/nvflinger/consumer_listener.h"
17#include "core/hle/service/nvflinger/status.h"
18
19namespace Service::android {
20
21class BufferItem;
22class BufferQueueConsumer;
23
24class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
25public:
26 void Connect(bool controlled_by_app);
27
28protected:
29 explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
30 virtual ~ConsumerBase();
31
32 virtual void OnFrameAvailable(const BufferItem& item) override;
33 virtual void OnFrameReplaced(const BufferItem& item) override;
34 virtual void OnBuffersReleased() override;
35 virtual void OnSidebandStreamChanged() override;
36
37 void FreeBufferLocked(s32 slot_index);
38 Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when,
39 u64 max_frame_number = 0);
40 Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer);
41 bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const;
42 Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer,
43 const Fence& fence);
44
45 struct Slot final {
46 std::shared_ptr<GraphicBuffer> graphic_buffer;
47 Fence fence;
48 u64 frame_number{};
49 };
50
51protected:
52 std::array<Slot, BufferQueueDefs::NUM_BUFFER_SLOTS> slots;
53
54 bool is_abandoned{};
55
56 std::unique_ptr<BufferQueueConsumer> consumer;
57
58 mutable std::mutex mutex;
59};
60
61} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/consumer_listener.h b/src/core/hle/service/nvflinger/consumer_listener.h
new file mode 100644
index 000000000..b6d1c3e9a
--- /dev/null
+++ b/src/core/hle/service/nvflinger/consumer_listener.h
@@ -0,0 +1,26 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IConsumerListener.h
6
7#pragma once
8
9namespace Service::android {
10
11class BufferItem;
12
13/// ConsumerListener is the interface through which the BufferQueue notifies the consumer of events
14/// that the consumer may wish to react to.
15class IConsumerListener {
16public:
17 IConsumerListener() = default;
18 virtual ~IConsumerListener() = default;
19
20 virtual void OnFrameAvailable(const BufferItem& item) = 0;
21 virtual void OnFrameReplaced(const BufferItem& item) = 0;
22 virtual void OnBuffersReleased() = 0;
23 virtual void OnSidebandStreamChanged() = 0;
24};
25
26}; // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
new file mode 100644
index 000000000..d4da98ddb
--- /dev/null
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
@@ -0,0 +1,20 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp
6
7#pragma once
8
9#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
10#include "core/hle/service/nvflinger/parcel.h"
11
12namespace Service::android {
13
14QueueBufferInput::QueueBufferInput(Parcel& parcel) {
15 parcel.ReadFlattened(*this);
16}
17
18QueueBufferOutput::QueueBufferOutput() = default;
19
20} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
new file mode 100644
index 000000000..98d27871c
--- /dev/null
+++ b/src/core/hle/service/nvflinger/graphic_buffer_producer.h
@@ -0,0 +1,76 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2010 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IGraphicBufferProducer.h
6
7#pragma once
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "common/math_util.h"
12#include "core/hle/service/nvflinger/ui/fence.h"
13#include "core/hle/service/nvflinger/window.h"
14
15namespace Service::android {
16
17class Parcel;
18
19#pragma pack(push, 1)
20struct QueueBufferInput final {
21 explicit QueueBufferInput(Parcel& parcel);
22
23 void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
24 NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
25 u32* sticky_transform_, bool* async_, s32* swap_interval_, Fence* fence_) const {
26 *timestamp_ = timestamp;
27 *is_auto_timestamp_ = static_cast<bool>(is_auto_timestamp);
28 *crop_ = crop;
29 *scaling_mode_ = scaling_mode;
30 *transform_ = transform;
31 *sticky_transform_ = sticky_transform;
32 *async_ = static_cast<bool>(async);
33 *swap_interval_ = swap_interval;
34 *fence_ = fence;
35 }
36
37private:
38 s64 timestamp{};
39 s32 is_auto_timestamp{};
40 Common::Rectangle<s32> crop{};
41 NativeWindowScalingMode scaling_mode{};
42 NativeWindowTransform transform{};
43 u32 sticky_transform{};
44 s32 async{};
45 s32 swap_interval{};
46 Fence fence{};
47};
48#pragma pack(pop)
49static_assert(sizeof(QueueBufferInput) == 84, "QueueBufferInput has wrong size");
50
51struct QueueBufferOutput final {
52 QueueBufferOutput();
53
54 void Deflate(u32* width_, u32* height_, u32* transform_hint_, u32* num_pending_buffers_) const {
55 *width_ = width;
56 *height_ = height;
57 *transform_hint_ = transform_hint;
58 *num_pending_buffers_ = num_pending_buffers;
59 }
60
61 void Inflate(u32 width_, u32 height_, u32 transform_hint_, u32 num_pending_buffers_) {
62 width = width_;
63 height = height_;
64 transform_hint = transform_hint_;
65 num_pending_buffers = num_pending_buffers_;
66 }
67
68private:
69 u32 width{};
70 u32 height{};
71 u32 transform_hint{};
72 u32 num_pending_buffers{};
73};
74static_assert(sizeof(QueueBufferOutput) == 16, "QueueBufferOutput has wrong size");
75
76} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
new file mode 100644
index 000000000..0c937d682
--- /dev/null
+++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
@@ -0,0 +1,36 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#include <mutex>
5
6#include "common/common_types.h"
7#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
8
9namespace Service::NVFlinger {
10
11HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)
12 : service_context(system_, "HosBinderDriverServer") {}
13
14HosBinderDriverServer::~HosBinderDriverServer() {}
15
16u64 HosBinderDriverServer::RegisterProducer(std::unique_ptr<android::IBinder>&& binder) {
17 std::lock_guard lk{lock};
18
19 last_id++;
20
21 producers[last_id] = std::move(binder);
22
23 return last_id;
24}
25
26android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) {
27 std::lock_guard lk{lock};
28
29 if (auto search = producers.find(id); search != producers.end()) {
30 return search->second.get();
31 }
32
33 return {};
34}
35
36} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.h b/src/core/hle/service/nvflinger/hos_binder_driver_server.h
new file mode 100644
index 000000000..cbca87fa0
--- /dev/null
+++ b/src/core/hle/service/nvflinger/hos_binder_driver_server.h
@@ -0,0 +1,37 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include <memory>
7#include <mutex>
8#include <unordered_map>
9
10#include "common/common_types.h"
11#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/nvflinger/binder.h"
13
14namespace Core {
15class System;
16}
17
18namespace Service::NVFlinger {
19
20class HosBinderDriverServer final {
21public:
22 explicit HosBinderDriverServer(Core::System& system_);
23 ~HosBinderDriverServer();
24
25 u64 RegisterProducer(std::unique_ptr<android::IBinder>&& binder);
26
27 android::IBinder* TryGetProducer(u64 id);
28
29private:
30 KernelHelpers::ServiceContext service_context;
31
32 std::unordered_map<u64, std::unique_ptr<android::IBinder>> producers;
33 std::mutex lock;
34 u64 last_id{};
35};
36
37} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 01e69de30..76ce1fbfd 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -1,6 +1,5 @@
1// Copyright 2018 yuzu emulator team 1// SPDX-License-Identifier: GPL-3.0-or-later
2// Licensed under GPLv2 or any later version 2// Copyright 2021 yuzu Emulator Project
3// Refer to the license.txt file included.
4 3
5#include <algorithm> 4#include <algorithm>
6#include <optional> 5#include <optional>
@@ -16,8 +15,11 @@
16#include "core/hle/kernel/k_readable_event.h" 15#include "core/hle/kernel/k_readable_event.h"
17#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 16#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
18#include "core/hle/service/nvdrv/nvdrv.h" 17#include "core/hle/service/nvdrv/nvdrv.h"
19#include "core/hle/service/nvflinger/buffer_queue.h" 18#include "core/hle/service/nvflinger/buffer_item_consumer.h"
19#include "core/hle/service/nvflinger/buffer_queue_core.h"
20#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
20#include "core/hle/service/nvflinger/nvflinger.h" 21#include "core/hle/service/nvflinger/nvflinger.h"
22#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
21#include "core/hle/service/vi/display/vi_display.h" 23#include "core/hle/service/vi/display/vi_display.h"
22#include "core/hle/service/vi/layer/vi_layer.h" 24#include "core/hle/service/vi/layer/vi_layer.h"
23#include "video_core/gpu.h" 25#include "video_core/gpu.h"
@@ -53,13 +55,14 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) {
53 } 55 }
54} 56}
55 57
56NVFlinger::NVFlinger(Core::System& system_) 58NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
57 : system(system_), service_context(system_, "nvflinger") { 59 : system(system_), service_context(system_, "nvflinger"),
58 displays.emplace_back(0, "Default", service_context, system); 60 hos_binder_driver_server(hos_binder_driver_server_) {
59 displays.emplace_back(1, "External", service_context, system); 61 displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
60 displays.emplace_back(2, "Edid", service_context, system); 62 displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
61 displays.emplace_back(3, "Internal", service_context, system); 63 displays.emplace_back(2, "Edid", hos_binder_driver_server, service_context, system);
62 displays.emplace_back(4, "Null", service_context, system); 64 displays.emplace_back(3, "Internal", hos_binder_driver_server, service_context, system);
65 displays.emplace_back(4, "Null", hos_binder_driver_server, service_context, system);
63 guard = std::make_shared<std::mutex>(); 66 guard = std::make_shared<std::mutex>();
64 67
65 // Schedule the screen composition events 68 // Schedule the screen composition events
@@ -83,12 +86,15 @@ NVFlinger::NVFlinger(Core::System& system_)
83} 86}
84 87
85NVFlinger::~NVFlinger() { 88NVFlinger::~NVFlinger() {
86 for (auto& buffer_queue : buffer_queues) {
87 buffer_queue->Disconnect();
88 }
89 if (!system.IsMulticore()) { 89 if (!system.IsMulticore()) {
90 system.CoreTiming().UnscheduleEvent(composition_event, 0); 90 system.CoreTiming().UnscheduleEvent(composition_event, 0);
91 } 91 }
92
93 for (auto& display : displays) {
94 for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
95 display.GetLayer(layer).Core().NotifyShutdown();
96 }
97 }
92} 98}
93 99
94void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 100void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
@@ -125,10 +131,8 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
125} 131}
126 132
127void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { 133void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
128 const u32 buffer_queue_id = next_buffer_queue_id++; 134 const auto buffer_id = next_buffer_queue_id++;
129 buffer_queues.emplace_back( 135 display.CreateLayer(layer_id, buffer_id);
130 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id, service_context));
131 display.CreateLayer(layer_id, *buffer_queues.back());
132} 136}
133 137
134void NVFlinger::CloseLayer(u64 layer_id) { 138void NVFlinger::CloseLayer(u64 layer_id) {
@@ -147,7 +151,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
147 return std::nullopt; 151 return std::nullopt;
148 } 152 }
149 153
150 return layer->GetBufferQueue().GetId(); 154 return layer->GetBinderId();
151} 155}
152 156
153Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) { 157Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
@@ -161,18 +165,6 @@ Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
161 return &display->GetVSyncEvent(); 165 return &display->GetVSyncEvent();
162} 166}
163 167
164BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
165 const auto lock_guard = Lock();
166 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
167 [id](const auto& queue) { return queue->GetId() == id; });
168
169 if (itr == buffer_queues.end()) {
170 return nullptr;
171 }
172
173 return itr->get();
174}
175
176VI::Display* NVFlinger::FindDisplay(u64 display_id) { 168VI::Display* NVFlinger::FindDisplay(u64 display_id) {
177 const auto itr = 169 const auto itr =
178 std::find_if(displays.begin(), displays.end(), 170 std::find_if(displays.begin(), displays.end(),
@@ -246,23 +238,22 @@ void NVFlinger::Compose() {
246 238
247 // TODO(Subv): Support more than 1 layer. 239 // TODO(Subv): Support more than 1 layer.
248 VI::Layer& layer = display.GetLayer(0); 240 VI::Layer& layer = display.GetLayer(0);
249 auto& buffer_queue = layer.GetBufferQueue();
250 241
251 // Search for a queued buffer and acquire it 242 android::BufferItem buffer{};
252 auto buffer = buffer_queue.AcquireBuffer(); 243 const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false);
253 244
254 if (!buffer) { 245 if (status != android::Status::NoError) {
255 continue; 246 continue;
256 } 247 }
257 248
258 const auto& igbp_buffer = buffer->get().igbp_buffer; 249 const auto& igbp_buffer = *buffer.graphic_buffer;
259 250
260 if (!system.IsPoweredOn()) { 251 if (!system.IsPoweredOn()) {
261 return; // We are likely shutting down 252 return; // We are likely shutting down
262 } 253 }
263 254
264 auto& gpu = system.GPU(); 255 auto& gpu = system.GPU();
265 const auto& multi_fence = buffer->get().multi_fence; 256 const auto& multi_fence = buffer.fence;
266 guard->unlock(); 257 guard->unlock();
267 for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { 258 for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
268 const auto& fence = multi_fence.fences[fence_id]; 259 const auto& fence = multi_fence.fences[fence_id];
@@ -278,12 +269,18 @@ void NVFlinger::Compose() {
278 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); 269 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0");
279 ASSERT(nvdisp); 270 ASSERT(nvdisp);
280 271
281 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.external_format, 272 Common::Rectangle<int> crop_rect{
282 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, 273 static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()),
283 buffer->get().transform, buffer->get().crop_rect); 274 static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
275
276 nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
277 igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
278 static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect);
279
280 swap_interval = buffer.swap_interval;
284 281
285 swap_interval = buffer->get().swap_interval; 282 auto fence = android::Fence::NoFence();
286 buffer_queue.ReleaseBuffer(buffer->get().slot); 283 layer.GetConsumer().ReleaseBuffer(buffer, fence);
287 } 284 }
288} 285}
289 286
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 7935cf773..ed160f6f9 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -1,6 +1,5 @@
1// Copyright 2018 yuzu emulator team 1// SPDX-License-Identifier: GPL-3.0-or-later
2// Licensed under GPLv2 or any later version 2// Copyright 2021 yuzu Emulator Project
3// Refer to the license.txt file included.
4 3
5#pragma once 4#pragma once
6 5
@@ -37,13 +36,16 @@ class Display;
37class Layer; 36class Layer;
38} // namespace Service::VI 37} // namespace Service::VI
39 38
40namespace Service::NVFlinger { 39namespace Service::android {
40class BufferQueueCore;
41class BufferQueueProducer;
42} // namespace Service::android
41 43
42class BufferQueue; 44namespace Service::NVFlinger {
43 45
44class NVFlinger final { 46class NVFlinger final {
45public: 47public:
46 explicit NVFlinger(Core::System& system_); 48 explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
47 ~NVFlinger(); 49 ~NVFlinger();
48 50
49 /// Sets the NVDrv module instance to use to send buffers to the GPU. 51 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -72,9 +74,6 @@ public:
72 /// If an invalid display ID is provided, then nullptr is returned. 74 /// If an invalid display ID is provided, then nullptr is returned.
73 [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id); 75 [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
74 76
75 /// Obtains a buffer queue identified by the ID.
76 [[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
77
78 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when 77 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
79 /// finished. 78 /// finished.
80 void Compose(); 79 void Compose();
@@ -82,6 +81,12 @@ public:
82 [[nodiscard]] s64 GetNextTicks() const; 81 [[nodiscard]] s64 GetNextTicks() const;
83 82
84private: 83private:
84 struct Layer {
85 std::unique_ptr<android::BufferQueueCore> core;
86 std::unique_ptr<android::BufferQueueProducer> producer;
87 };
88
89private:
85 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { 90 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
86 return std::unique_lock{*guard}; 91 return std::unique_lock{*guard};
87 } 92 }
@@ -111,7 +116,6 @@ private:
111 std::shared_ptr<Nvidia::Module> nvdrv; 116 std::shared_ptr<Nvidia::Module> nvdrv;
112 117
113 std::list<VI::Display> displays; 118 std::list<VI::Display> displays;
114 std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
115 119
116 /// Id to use for the next layer that is created, this counter is shared among all displays. 120 /// Id to use for the next layer that is created, this counter is shared among all displays.
117 u64 next_layer_id = 1; 121 u64 next_layer_id = 1;
@@ -131,6 +135,8 @@ private:
131 std::jthread vsync_thread; 135 std::jthread vsync_thread;
132 136
133 KernelHelpers::ServiceContext service_context; 137 KernelHelpers::ServiceContext service_context;
138
139 HosBinderDriverServer& hos_binder_driver_server;
134}; 140};
135 141
136} // namespace Service::NVFlinger 142} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h
new file mode 100644
index 000000000..aa36e6479
--- /dev/null
+++ b/src/core/hle/service/nvflinger/parcel.h
@@ -0,0 +1,172 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include <memory>
7#include <vector>
8
9#include "common/alignment.h"
10#include "common/assert.h"
11#include "common/common_types.h"
12
13namespace Service::android {
14
15class Parcel final {
16public:
17 static constexpr std::size_t DefaultBufferSize = 0x40;
18
19 Parcel() : buffer(DefaultBufferSize) {}
20
21 template <typename T>
22 explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) {
23 Write(out_data);
24 }
25
26 explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) {
27 DeserializeHeader();
28 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
29 }
30
31 template <typename T>
32 void Read(T& val) {
33 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
34 ASSERT(read_index + sizeof(T) <= buffer.size());
35
36 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
37 read_index += sizeof(T);
38 read_index = Common::AlignUp(read_index, 4);
39 }
40
41 template <typename T>
42 T Read() {
43 T val;
44 Read(val);
45 return val;
46 }
47
48 template <typename T>
49 void ReadFlattened(T& val) {
50 const auto flattened_size = Read<s64>();
51 ASSERT(sizeof(T) == flattened_size);
52 Read(val);
53 }
54
55 template <typename T>
56 T ReadFlattened() {
57 T val;
58 ReadFlattened(val);
59 return val;
60 }
61
62 template <typename T>
63 T ReadUnaligned() {
64 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
65 ASSERT(read_index + sizeof(T) <= buffer.size());
66
67 T val;
68 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
69 read_index += sizeof(T);
70 return val;
71 }
72
73 template <typename T>
74 const std::shared_ptr<T> ReadObject() {
75 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
76
77 const auto is_valid{Read<bool>()};
78
79 if (is_valid) {
80 auto result = std::make_shared<T>();
81 ReadFlattened(*result);
82 return result;
83 }
84
85 return {};
86 }
87
88 std::u16string ReadInterfaceToken() {
89 [[maybe_unused]] const u32 unknown = Read<u32>();
90 const u32 length = Read<u32>();
91
92 std::u16string token;
93 token.reserve(length + 1);
94
95 for (u32 ch = 0; ch < length + 1; ++ch) {
96 token.push_back(ReadUnaligned<u16>());
97 }
98
99 read_index = Common::AlignUp(read_index, 4);
100
101 return token;
102 }
103
104 template <typename T>
105 void Write(const T& val) {
106 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
107
108 if (buffer.size() < write_index + sizeof(T)) {
109 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
110 }
111
112 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
113 write_index += sizeof(T);
114 write_index = Common::AlignUp(write_index, 4);
115 }
116
117 template <typename T>
118 void WriteObject(const T* ptr) {
119 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
120
121 if (!ptr) {
122 Write<u32>(0);
123 return;
124 }
125
126 Write<u32>(1);
127 Write<s64>(sizeof(T));
128 Write(*ptr);
129 }
130
131 template <typename T>
132 void WriteObject(const std::shared_ptr<T> ptr) {
133 WriteObject(ptr.get());
134 }
135
136 void DeserializeHeader() {
137 ASSERT(buffer.size() > sizeof(Header));
138
139 Header header{};
140 std::memcpy(&header, buffer.data(), sizeof(Header));
141
142 read_index = header.data_offset;
143 }
144
145 std::vector<u8> Serialize() const {
146 ASSERT(read_index == 0);
147
148 Header header{};
149 header.data_size = static_cast<u32>(write_index - sizeof(Header));
150 header.data_offset = sizeof(Header);
151 header.objects_size = 4;
152 header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
153 std::memcpy(buffer.data(), &header, sizeof(Header));
154
155 return buffer;
156 }
157
158private:
159 struct Header {
160 u32 data_size;
161 u32 data_offset;
162 u32 objects_size;
163 u32 objects_offset;
164 };
165 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
166
167 mutable std::vector<u8> buffer;
168 std::size_t read_index = 0;
169 std::size_t write_index = sizeof(Header);
170};
171
172} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/pixel_format.h b/src/core/hle/service/nvflinger/pixel_format.h
new file mode 100644
index 000000000..8a77d8bea
--- /dev/null
+++ b/src/core/hle/service/nvflinger/pixel_format.h
@@ -0,0 +1,21 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::android {
9
10enum class PixelFormat : u32 {
11 NoFormat = 0,
12 Rgba8888 = 1,
13 Rgbx8888 = 2,
14 Rgb888 = 3,
15 Rgb565 = 4,
16 Bgra8888 = 5,
17 Rgba5551 = 6,
18 Rgba4444 = 7,
19};
20
21} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h
new file mode 100644
index 000000000..468e06431
--- /dev/null
+++ b/src/core/hle/service/nvflinger/producer_listener.h
@@ -0,0 +1,16 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2014 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/gui/IProducerListener.h
6
7#pragma once
8
9namespace Service::android {
10
11class IProducerListener {
12public:
13 virtual void OnBufferReleased() = 0;
14};
15
16} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/status.h b/src/core/hle/service/nvflinger/status.h
new file mode 100644
index 000000000..a003eda89
--- /dev/null
+++ b/src/core/hle/service/nvflinger/status.h
@@ -0,0 +1,28 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::android {
10
11enum class Status : s32 {
12 None = 0,
13 NoError = 0,
14 StaleBufferSlot = 1,
15 NoBufferAvailable = 2,
16 PresentLater = 3,
17 WouldBlock = -11,
18 NoMemory = -12,
19 Busy = -16,
20 NoInit = -19,
21 BadValue = -22,
22 InvalidOperation = -37,
23 BufferNeedsReallocation = 1,
24 ReleaseAllBuffers = 2,
25};
26DECLARE_ENUM_FLAG_OPERATORS(Status);
27
28} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/ui/fence.h b/src/core/hle/service/nvflinger/ui/fence.h
new file mode 100644
index 000000000..4a74e26a3
--- /dev/null
+++ b/src/core/hle/service/nvflinger/ui/fence.h
@@ -0,0 +1,32 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2012 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/Fence.h
6
7#pragma once
8
9#include <array>
10
11#include "common/common_types.h"
12#include "core/hle/service/nvdrv/nvdata.h"
13
14namespace Service::android {
15
16class Fence {
17public:
18 constexpr Fence() = default;
19
20 static constexpr Fence NoFence() {
21 Fence fence;
22 fence.fences[0].id = -1;
23 return fence;
24 }
25
26public:
27 u32 num_fences{};
28 std::array<Service::Nvidia::NvFence, 4> fences{};
29};
30static_assert(sizeof(Fence) == 36, "Fence has wrong size");
31
32} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvflinger/ui/graphic_buffer.h
new file mode 100644
index 000000000..7abbf78ba
--- /dev/null
+++ b/src/core/hle/service/nvflinger/ui/graphic_buffer.h
@@ -0,0 +1,100 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3// Copyright 2007 The Android Open Source Project
4// Parts of this implementation were base on:
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/include/ui/GraphicBuffer.h
6
7#pragma once
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11#include "core/hle/service/nvflinger/pixel_format.h"
12
13namespace Service::android {
14
15class GraphicBuffer final {
16public:
17 constexpr GraphicBuffer() = default;
18
19 constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
20 : width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_},
21 usage{static_cast<s32>(usage_)} {}
22
23 constexpr u32 Width() const {
24 return static_cast<u32>(width);
25 }
26
27 constexpr u32 Height() const {
28 return static_cast<u32>(height);
29 }
30
31 constexpr u32 Stride() const {
32 return static_cast<u32>(stride);
33 }
34
35 constexpr u32 Usage() const {
36 return static_cast<u32>(usage);
37 }
38
39 constexpr PixelFormat Format() const {
40 return format;
41 }
42
43 constexpr u32 BufferId() const {
44 return buffer_id;
45 }
46
47 constexpr PixelFormat ExternalFormat() const {
48 return external_format;
49 }
50
51 constexpr u32 Handle() const {
52 return handle;
53 }
54
55 constexpr u32 Offset() const {
56 return offset;
57 }
58
59 constexpr bool NeedsReallocation(u32 width_, u32 height_, PixelFormat format_,
60 u32 usage_) const {
61 if (static_cast<s32>(width_) != width) {
62 return true;
63 }
64
65 if (static_cast<s32>(height_) != height) {
66 return true;
67 }
68
69 if (format_ != format) {
70 return true;
71 }
72
73 if ((static_cast<u32>(usage) & usage_) != usage_) {
74 return true;
75 }
76
77 return false;
78 }
79
80private:
81 u32 magic{};
82 s32 width{};
83 s32 height{};
84 s32 stride{};
85 PixelFormat format{};
86 s32 usage{};
87 INSERT_PADDING_WORDS(1);
88 u32 index{};
89 INSERT_PADDING_WORDS(3);
90 u32 buffer_id{};
91 INSERT_PADDING_WORDS(6);
92 PixelFormat external_format{};
93 INSERT_PADDING_WORDS(10);
94 u32 handle{};
95 u32 offset{};
96 INSERT_PADDING_WORDS(60);
97};
98static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size");
99
100} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/window.h b/src/core/hle/service/nvflinger/window.h
new file mode 100644
index 000000000..e26f8160e
--- /dev/null
+++ b/src/core/hle/service/nvflinger/window.h
@@ -0,0 +1,53 @@
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright 2021 yuzu Emulator Project
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::android {
10
11/// Attributes queryable with Query
12enum class NativeWindow : s32 {
13 Width = 0,
14 Height = 1,
15 Format = 2,
16 MinUndequeedBuffers = 3,
17 QueuesToWindowComposer = 4,
18 ConcreteType = 5,
19 DefaultWidth = 6,
20 DefaultHeight = 7,
21 TransformHint = 8,
22 ConsumerRunningBehind = 9,
23 ConsumerUsageBits = 10,
24 StickyTransform = 11,
25 DefaultDataSpace = 12,
26 BufferAge = 13,
27};
28
29/// Parameter for Connect/Disconnect
30enum class NativeWindowApi : s32 {
31 NoConnectedApi = 0,
32 Egl = 1,
33 Cpu = 2,
34 Media = 3,
35 Camera = 4,
36};
37
38/// Scaling mode parameter for QueueBuffer
39enum class NativeWindowScalingMode : s32 {
40 Freeze = 0,
41 ScaleToWindow = 1,
42 ScaleCrop = 2,
43 NoScaleCrop = 3,
44};
45
46/// Transform parameter for QueueBuffer
47enum class NativeWindowTransform : u32 {
48 None = 0x0,
49 InverseDisplay = 0x08,
50};
51DECLARE_ENUM_FLAG_OPERATORS(NativeWindowTransform);
52
53} // namespace Service::android
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index eb1138313..ab3286db9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -49,6 +49,7 @@
49#include "core/hle/service/npns/npns.h" 49#include "core/hle/service/npns/npns.h"
50#include "core/hle/service/ns/ns.h" 50#include "core/hle/service/ns/ns.h"
51#include "core/hle/service/nvdrv/nvdrv.h" 51#include "core/hle/service/nvdrv/nvdrv.h"
52#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
52#include "core/hle/service/nvflinger/nvflinger.h" 53#include "core/hle/service/nvflinger/nvflinger.h"
53#include "core/hle/service/olsc/olsc.h" 54#include "core/hle/service/olsc/olsc.h"
54#include "core/hle/service/pcie/pcie.h" 55#include "core/hle/service/pcie/pcie.h"
@@ -230,7 +231,8 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& sessi
230 231
231/// Initialize Services 232/// Initialize Services
232Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) 233Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
233 : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} { 234 : hos_binder_driver_server{std::make_unique<NVFlinger::HosBinderDriverServer>(system)},
235 nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system, *hos_binder_driver_server)} {
234 236
235 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 237 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
236 // here and pass it into the respective InstallInterfaces functions. 238 // here and pass it into the respective InstallInterfaces functions.
@@ -290,7 +292,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
290 SSL::InstallInterfaces(*sm, system); 292 SSL::InstallInterfaces(*sm, system);
291 Time::InstallInterfaces(system); 293 Time::InstallInterfaces(system);
292 USB::InstallInterfaces(*sm, system); 294 USB::InstallInterfaces(*sm, system);
293 VI::InstallInterfaces(*sm, system, *nv_flinger); 295 VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server);
294 WLAN::InstallInterfaces(*sm, system); 296 WLAN::InstallInterfaces(*sm, system);
295} 297}
296 298
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c9d6b879d..b9ab2c465 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -33,8 +33,9 @@ class FileSystemController;
33} 33}
34 34
35namespace NVFlinger { 35namespace NVFlinger {
36class HosBinderDriverServer;
36class NVFlinger; 37class NVFlinger;
37} 38} // namespace NVFlinger
38 39
39namespace SM { 40namespace SM {
40class ServiceManager; 41class ServiceManager;
@@ -236,6 +237,7 @@ public:
236 ~Services(); 237 ~Services();
237 238
238private: 239private:
240 std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
239 std::unique_ptr<NVFlinger::NVFlinger> nv_flinger; 241 std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
240}; 242};
241 243
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index b7705c02a..558022511 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -13,14 +13,34 @@
13#include "core/hle/kernel/k_readable_event.h" 13#include "core/hle/kernel/k_readable_event.h"
14#include "core/hle/kernel/k_writable_event.h" 14#include "core/hle/kernel/k_writable_event.h"
15#include "core/hle/service/kernel_helpers.h" 15#include "core/hle/service/kernel_helpers.h"
16#include "core/hle/service/nvflinger/buffer_item_consumer.h"
17#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
18#include "core/hle/service/nvflinger/buffer_queue_core.h"
19#include "core/hle/service/nvflinger/buffer_queue_producer.h"
20#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
16#include "core/hle/service/vi/display/vi_display.h" 21#include "core/hle/service/vi/display/vi_display.h"
17#include "core/hle/service/vi/layer/vi_layer.h" 22#include "core/hle/service/vi/layer/vi_layer.h"
18 23
19namespace Service::VI { 24namespace Service::VI {
20 25
21Display::Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, 26struct BufferQueue {
22 Core::System& system_) 27 std::shared_ptr<android::BufferQueueCore> core;
23 : display_id{id}, name{std::move(name_)}, service_context{service_context_} { 28 std::unique_ptr<android::BufferQueueProducer> producer;
29 std::unique_ptr<android::BufferQueueConsumer> consumer;
30};
31
32static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_context) {
33 auto buffer_queue_core = std::make_shared<android::BufferQueueCore>();
34 return {buffer_queue_core,
35 std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core),
36 std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
37}
38
39Display::Display(u64 id, std::string name_,
40 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
41 KernelHelpers::ServiceContext& service_context_, Core::System& system_)
42 : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
43 service_context{service_context_} {
24 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); 44 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
25} 45}
26 46
@@ -44,21 +64,29 @@ void Display::SignalVSyncEvent() {
44 vsync_event->GetWritableEvent().Signal(); 64 vsync_event->GetWritableEvent().Signal();
45} 65}
46 66
47void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) { 67void Display::CreateLayer(u64 layer_id, u32 binder_id) {
48 // TODO(Subv): Support more than 1 layer.
49 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment"); 68 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
50 69
51 layers.emplace_back(std::make_shared<Layer>(layer_id, buffer_queue)); 70 auto [core, producer, consumer] = CreateBufferQueue(service_context);
71
72 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
73 buffer_item_consumer->Connect(false);
74
75 layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
76 std::move(buffer_item_consumer)));
77
78 hos_binder_driver_server.RegisterProducer(std::move(producer));
52} 79}
53 80
54void Display::CloseLayer(u64 layer_id) { 81void Display::CloseLayer(u64 layer_id) {
55 std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; }); 82 std::erase_if(layers,
83 [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
56} 84}
57 85
58Layer* Display::FindLayer(u64 layer_id) { 86Layer* Display::FindLayer(u64 layer_id) {
59 const auto itr = 87 const auto itr =
60 std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) { 88 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
61 return layer->GetID() == layer_id; 89 return layer->GetLayerId() == layer_id;
62 }); 90 });
63 91
64 if (itr == layers.end()) { 92 if (itr == layers.end()) {
@@ -70,8 +98,8 @@ Layer* Display::FindLayer(u64 layer_id) {
70 98
71const Layer* Display::FindLayer(u64 layer_id) const { 99const Layer* Display::FindLayer(u64 layer_id) const {
72 const auto itr = 100 const auto itr =
73 std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) { 101 std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {
74 return layer->GetID() == layer_id; 102 return layer->GetLayerId() == layer_id;
75 }); 103 });
76 104
77 if (itr == layers.end()) { 105 if (itr == layers.end()) {
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 329f4ba86..e93d084ee 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -15,12 +15,17 @@ namespace Kernel {
15class KEvent; 15class KEvent;
16} 16}
17 17
18namespace Service::NVFlinger { 18namespace Service::android {
19class BufferQueue; 19class BufferQueueProducer;
20} 20}
21
21namespace Service::KernelHelpers { 22namespace Service::KernelHelpers {
22class ServiceContext; 23class ServiceContext;
23} // namespace Service::KernelHelpers 24}
25
26namespace Service::NVFlinger {
27class HosBinderDriverServer;
28}
24 29
25namespace Service::VI { 30namespace Service::VI {
26 31
@@ -35,12 +40,13 @@ public:
35 /// Constructs a display with a given unique ID and name. 40 /// Constructs a display with a given unique ID and name.
36 /// 41 ///
37 /// @param id The unique ID for this display. 42 /// @param id The unique ID for this display.
43 /// @param hos_binder_driver_server_ NVFlinger HOSBinderDriver server instance.
38 /// @param service_context_ The ServiceContext for the owning service. 44 /// @param service_context_ The ServiceContext for the owning service.
39 /// @param name_ The name for this display. 45 /// @param name_ The name for this display.
40 /// @param system_ The global system instance. 46 /// @param system_ The global system instance.
41 /// 47 ///
42 Display(u64 id, std::string name_, KernelHelpers::ServiceContext& service_context_, 48 Display(u64 id, std::string name_, NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
43 Core::System& system_); 49 KernelHelpers::ServiceContext& service_context_, Core::System& system_);
44 ~Display(); 50 ~Display();
45 51
46 /// Gets the unique ID assigned to this display. 52 /// Gets the unique ID assigned to this display.
@@ -64,6 +70,10 @@ public:
64 /// Gets a layer for this display based off an index. 70 /// Gets a layer for this display based off an index.
65 const Layer& GetLayer(std::size_t index) const; 71 const Layer& GetLayer(std::size_t index) const;
66 72
73 std::size_t GetNumLayers() const {
74 return layers.size();
75 }
76
67 /// Gets the readable vsync event. 77 /// Gets the readable vsync event.
68 Kernel::KReadableEvent& GetVSyncEvent(); 78 Kernel::KReadableEvent& GetVSyncEvent();
69 79
@@ -72,10 +82,10 @@ public:
72 82
73 /// Creates and adds a layer to this display with the given ID. 83 /// Creates and adds a layer to this display with the given ID.
74 /// 84 ///
75 /// @param layer_id The ID to assign to the created layer. 85 /// @param layer_id The ID to assign to the created layer.
76 /// @param buffer_queue The buffer queue for the layer instance to use. 86 /// @param binder_id The ID assigned to the buffer queue.
77 /// 87 ///
78 void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue); 88 void CreateLayer(u64 layer_id, u32 binder_id);
79 89
80 /// Closes and removes a layer from this display with the given ID. 90 /// Closes and removes a layer from this display with the given ID.
81 /// 91 ///
@@ -104,9 +114,10 @@ public:
104private: 114private:
105 u64 display_id; 115 u64 display_id;
106 std::string name; 116 std::string name;
117 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
107 KernelHelpers::ServiceContext& service_context; 118 KernelHelpers::ServiceContext& service_context;
108 119
109 std::vector<std::shared_ptr<Layer>> layers; 120 std::vector<std::unique_ptr<Layer>> layers;
110 Kernel::KEvent* vsync_event{}; 121 Kernel::KEvent* vsync_event{};
111}; 122};
112 123
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 9bc382587..93858e91f 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -6,7 +6,11 @@
6 6
7namespace Service::VI { 7namespace Service::VI {
8 8
9Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {} 9Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
10 android::BufferQueueProducer& binder_,
11 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
12 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
13 consumer_)} {}
10 14
11Layer::~Layer() = default; 15Layer::~Layer() = default;
12 16
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index ebdd85505..c28b14450 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -4,11 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9namespace Service::NVFlinger { 11namespace Service::android {
10class BufferQueue; 12class BufferItemConsumer;
11} 13class BufferQueueCore;
14class BufferQueueProducer;
15} // namespace Service::android
12 16
13namespace Service::VI { 17namespace Service::VI {
14 18
@@ -17,10 +21,13 @@ class Layer {
17public: 21public:
18 /// Constructs a layer with a given ID and buffer queue. 22 /// Constructs a layer with a given ID and buffer queue.
19 /// 23 ///
20 /// @param id The ID to assign to this layer. 24 /// @param layer_id_ The ID to assign to this layer.
21 /// @param queue The buffer queue for this layer to use. 25 /// @param binder_id_ The binder ID to assign to this layer.
26 /// @param binder_ The buffer producer queue for this layer to use.
22 /// 27 ///
23 Layer(u64 id, NVFlinger::BufferQueue& queue); 28 Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
29 android::BufferQueueProducer& binder_,
30 std::shared_ptr<android::BufferItemConsumer>&& consumer_);
24 ~Layer(); 31 ~Layer();
25 32
26 Layer(const Layer&) = delete; 33 Layer(const Layer&) = delete;
@@ -30,23 +37,47 @@ public:
30 Layer& operator=(Layer&&) = delete; 37 Layer& operator=(Layer&&) = delete;
31 38
32 /// Gets the ID for this layer. 39 /// Gets the ID for this layer.
33 u64 GetID() const { 40 u64 GetLayerId() const {
34 return layer_id; 41 return layer_id;
35 } 42 }
36 43
44 /// Gets the binder ID for this layer.
45 u32 GetBinderId() const {
46 return binder_id;
47 }
48
37 /// Gets a reference to the buffer queue this layer is using. 49 /// Gets a reference to the buffer queue this layer is using.
38 NVFlinger::BufferQueue& GetBufferQueue() { 50 android::BufferQueueProducer& GetBufferQueue() {
39 return buffer_queue; 51 return binder;
40 } 52 }
41 53
42 /// Gets a const reference to the buffer queue this layer is using. 54 /// Gets a const reference to the buffer queue this layer is using.
43 const NVFlinger::BufferQueue& GetBufferQueue() const { 55 const android::BufferQueueProducer& GetBufferQueue() const {
44 return buffer_queue; 56 return binder;
57 }
58
59 android::BufferItemConsumer& GetConsumer() {
60 return *consumer;
61 }
62
63 const android::BufferItemConsumer& GetConsumer() const {
64 return *consumer;
65 }
66
67 android::BufferQueueCore& Core() {
68 return core;
69 }
70
71 const android::BufferQueueCore& Core() const {
72 return core;
45 } 73 }
46 74
47private: 75private:
48 u64 layer_id; 76 const u64 layer_id;
49 NVFlinger::BufferQueue& buffer_queue; 77 const u32 binder_id;
78 android::BufferQueueCore& core;
79 android::BufferQueueProducer& binder;
80 std::shared_ptr<android::BufferItemConsumer> consumer;
50}; 81};
51 82
52} // namespace Service::VI 83} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 75ee3e5e4..430cbc546 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -22,8 +22,11 @@
22#include "core/hle/kernel/k_readable_event.h" 22#include "core/hle/kernel/k_readable_event.h"
23#include "core/hle/kernel/k_thread.h" 23#include "core/hle/kernel/k_thread.h"
24#include "core/hle/service/nvdrv/nvdata.h" 24#include "core/hle/service/nvdrv/nvdata.h"
25#include "core/hle/service/nvflinger/buffer_queue.h" 25#include "core/hle/service/nvflinger/binder.h"
26#include "core/hle/service/nvflinger/buffer_queue_producer.h"
27#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
26#include "core/hle/service/nvflinger/nvflinger.h" 28#include "core/hle/service/nvflinger/nvflinger.h"
29#include "core/hle/service/nvflinger/parcel.h"
27#include "core/hle/service/service.h" 30#include "core/hle/service/service.h"
28#include "core/hle/service/vi/vi.h" 31#include "core/hle/service/vi/vi.h"
29#include "core/hle/service/vi/vi_m.h" 32#include "core/hle/service/vi/vi_m.h"
@@ -57,447 +60,24 @@ struct DisplayInfo {
57}; 60};
58static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); 61static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size");
59 62
60class Parcel { 63class NativeWindow final {
61public: 64public:
62 // This default size was chosen arbitrarily. 65 constexpr explicit NativeWindow(u32 id_) : id{id_} {}
63 static constexpr std::size_t DefaultBufferSize = 0x40;
64 Parcel() : buffer(DefaultBufferSize) {}
65 explicit Parcel(std::vector<u8> data) : buffer(std::move(data)) {}
66 virtual ~Parcel() = default;
67
68 template <typename T>
69 T Read() {
70 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
71 ASSERT(read_index + sizeof(T) <= buffer.size());
72
73 T val;
74 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
75 read_index += sizeof(T);
76 read_index = Common::AlignUp(read_index, 4);
77 return val;
78 }
79
80 template <typename T>
81 T ReadUnaligned() {
82 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
83 ASSERT(read_index + sizeof(T) <= buffer.size());
84
85 T val;
86 std::memcpy(&val, buffer.data() + read_index, sizeof(T));
87 read_index += sizeof(T);
88 return val;
89 }
90
91 std::vector<u8> ReadBlock(std::size_t length) {
92 ASSERT(read_index + length <= buffer.size());
93 const u8* const begin = buffer.data() + read_index;
94 const u8* const end = begin + length;
95 std::vector<u8> data(begin, end);
96 read_index += length;
97 read_index = Common::AlignUp(read_index, 4);
98 return data;
99 }
100
101 std::u16string ReadInterfaceToken() {
102 [[maybe_unused]] const u32 unknown = Read<u32_le>();
103 const u32 length = Read<u32_le>();
104
105 std::u16string token{};
106
107 for (u32 ch = 0; ch < length + 1; ++ch) {
108 token.push_back(ReadUnaligned<u16_le>());
109 }
110
111 read_index = Common::AlignUp(read_index, 4);
112
113 return token;
114 }
115
116 template <typename T>
117 void Write(const T& val) {
118 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
119
120 if (buffer.size() < write_index + sizeof(T)) {
121 buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
122 }
123
124 std::memcpy(buffer.data() + write_index, &val, sizeof(T));
125 write_index += sizeof(T);
126 write_index = Common::AlignUp(write_index, 4);
127 }
128
129 template <typename T>
130 void WriteObject(const T& val) {
131 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
132
133 const u32_le size = static_cast<u32>(sizeof(val));
134 Write(size);
135 // TODO(Subv): Support file descriptors.
136 Write<u32_le>(0); // Fd count.
137 Write(val);
138 }
139
140 void Deserialize() {
141 ASSERT(buffer.size() > sizeof(Header));
142
143 Header header{};
144 std::memcpy(&header, buffer.data(), sizeof(Header));
145
146 read_index = header.data_offset;
147 DeserializeData();
148 }
149
150 std::vector<u8> Serialize() {
151 ASSERT(read_index == 0);
152 write_index = sizeof(Header);
153
154 SerializeData();
155
156 Header header{};
157 header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
158 header.data_offset = sizeof(Header);
159 header.objects_size = 4;
160 header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
161 std::memcpy(buffer.data(), &header, sizeof(Header));
162
163 return buffer;
164 }
165
166protected:
167 virtual void SerializeData() {}
168
169 virtual void DeserializeData() {}
170
171private:
172 struct Header {
173 u32_le data_size;
174 u32_le data_offset;
175 u32_le objects_size;
176 u32_le objects_offset;
177 };
178 static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
179
180 std::vector<u8> buffer;
181 std::size_t read_index = 0;
182 std::size_t write_index = 0;
183};
184
185class NativeWindow : public Parcel {
186public:
187 explicit NativeWindow(u32 id) {
188 data.id = id;
189 }
190 ~NativeWindow() override = default;
191
192protected:
193 void SerializeData() override {
194 Write(data);
195 }
196
197private:
198 struct Data {
199 u32_le magic = 2;
200 u32_le process_id = 1;
201 u32_le id;
202 INSERT_PADDING_WORDS(3);
203 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
204 INSERT_PADDING_WORDS(2);
205 };
206 static_assert(sizeof(Data) == 0x28, "ParcelData has wrong size");
207
208 Data data{};
209};
210
211class IGBPConnectRequestParcel : public Parcel {
212public:
213 explicit IGBPConnectRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
214 Deserialize();
215 }
216
217 void DeserializeData() override {
218 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
219 data = Read<Data>();
220 }
221
222 struct Data {
223 u32_le unk;
224 u32_le api;
225 u32_le producer_controlled_by_app;
226 };
227
228 Data data;
229};
230
231class IGBPConnectResponseParcel : public Parcel {
232public:
233 explicit IGBPConnectResponseParcel(u32 width, u32 height) {
234 data.width = width;
235 data.height = height;
236 }
237 ~IGBPConnectResponseParcel() override = default;
238
239protected:
240 void SerializeData() override {
241 Write(data);
242 }
243
244private:
245 struct Data {
246 u32_le width;
247 u32_le height;
248 u32_le transform_hint;
249 u32_le num_pending_buffers;
250 u32_le status;
251 };
252 static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
253
254 Data data{};
255};
256
257/// Represents a parcel containing one int '0' as its data
258/// Used by DetachBuffer and Disconnect
259class IGBPEmptyResponseParcel : public Parcel {
260protected:
261 void SerializeData() override {
262 Write(data);
263 }
264
265private:
266 struct Data {
267 u32_le unk_0{};
268 };
269
270 Data data{};
271};
272
273class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
274public:
275 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
276 : Parcel(std::move(buffer_)) {
277 Deserialize();
278 }
279
280 void DeserializeData() override {
281 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
282 data = Read<Data>();
283 if (data.contains_object != 0) {
284 buffer_container = Read<BufferContainer>();
285 }
286 }
287
288 struct Data {
289 u32_le slot;
290 u32_le contains_object;
291 };
292
293 struct BufferContainer {
294 u32_le graphic_buffer_length;
295 INSERT_PADDING_WORDS(1);
296 NVFlinger::IGBPBuffer buffer{};
297 };
298
299 Data data{};
300 BufferContainer buffer_container{};
301};
302
303class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
304protected:
305 void SerializeData() override {
306 // TODO(Subv): Find out what this means
307 Write<u32>(0);
308 }
309};
310
311class IGBPCancelBufferRequestParcel : public Parcel {
312public:
313 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
314 Deserialize();
315 }
316
317 void DeserializeData() override {
318 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
319 data = Read<Data>();
320 }
321
322 struct Data {
323 u32_le slot;
324 Service::Nvidia::MultiFence multi_fence;
325 };
326
327 Data data;
328};
329
330class IGBPCancelBufferResponseParcel : public Parcel {
331protected:
332 void SerializeData() override {
333 Write<u32>(0); // Success
334 }
335};
336
337class IGBPDequeueBufferRequestParcel : public Parcel {
338public:
339 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
340 Deserialize();
341 }
342
343 void DeserializeData() override {
344 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
345 data = Read<Data>();
346 }
347
348 struct Data {
349 u32_le pixel_format;
350 u32_le width;
351 u32_le height;
352 u32_le get_frame_timestamps;
353 u32_le usage;
354 };
355
356 Data data;
357};
358
359class IGBPDequeueBufferResponseParcel : public Parcel {
360public:
361 explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
362 : slot(slot_), multi_fence(multi_fence_) {}
363
364protected:
365 void SerializeData() override {
366 Write(slot);
367 Write<u32_le>(1);
368 WriteObject(multi_fence);
369 Write<u32_le>(0);
370 }
371
372 u32_le slot;
373 Service::Nvidia::MultiFence multi_fence;
374};
375
376class IGBPRequestBufferRequestParcel : public Parcel {
377public:
378 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
379 Deserialize();
380 }
381
382 void DeserializeData() override {
383 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
384 slot = Read<u32_le>();
385 }
386
387 u32_le slot;
388};
389
390class IGBPRequestBufferResponseParcel : public Parcel {
391public:
392 explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
393 ~IGBPRequestBufferResponseParcel() override = default;
394
395protected:
396 void SerializeData() override {
397 // TODO(Subv): Figure out what this value means, writing non-zero here will make libnx
398 // try to read an IGBPBuffer object from the parcel.
399 Write<u32_le>(1);
400 WriteObject(buffer);
401 Write<u32_le>(0);
402 }
403
404 NVFlinger::IGBPBuffer buffer;
405};
406
407class IGBPQueueBufferRequestParcel : public Parcel {
408public:
409 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
410 Deserialize();
411 }
412
413 void DeserializeData() override {
414 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
415 data = Read<Data>();
416 }
417
418 struct Data {
419 u32_le slot;
420 INSERT_PADDING_WORDS(3);
421 u32_le timestamp;
422 s32_le is_auto_timestamp;
423 s32_le crop_top;
424 s32_le crop_left;
425 s32_le crop_right;
426 s32_le crop_bottom;
427 s32_le scaling_mode;
428 NVFlinger::BufferQueue::BufferTransformFlags transform;
429 u32_le sticky_transform;
430 INSERT_PADDING_WORDS(1);
431 u32_le swap_interval;
432 Service::Nvidia::MultiFence multi_fence;
433
434 Common::Rectangle<int> GetCropRect() const {
435 return {crop_left, crop_top, crop_right, crop_bottom};
436 }
437 };
438 static_assert(sizeof(Data) == 96, "ParcelData has wrong size");
439
440 Data data;
441};
442
443class IGBPQueueBufferResponseParcel : public Parcel {
444public:
445 explicit IGBPQueueBufferResponseParcel(u32 width, u32 height) {
446 data.width = width;
447 data.height = height;
448 }
449 ~IGBPQueueBufferResponseParcel() override = default;
450
451protected:
452 void SerializeData() override {
453 Write(data);
454 }
455
456private:
457 struct Data {
458 u32_le width;
459 u32_le height;
460 u32_le transform_hint;
461 u32_le num_pending_buffers;
462 u32_le status;
463 };
464 static_assert(sizeof(Data) == 20, "ParcelData has wrong size");
465
466 Data data{};
467};
468
469class IGBPQueryRequestParcel : public Parcel {
470public:
471 explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
472 Deserialize();
473 }
474
475 void DeserializeData() override {
476 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
477 type = Read<u32_le>();
478 }
479
480 u32 type;
481};
482
483class IGBPQueryResponseParcel : public Parcel {
484public:
485 explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
486 ~IGBPQueryResponseParcel() override = default;
487
488protected:
489 void SerializeData() override {
490 Write(value);
491 }
492 66
493private: 67private:
494 u32_le value; 68 const u32 magic = 2;
69 const u32 process_id = 1;
70 const u32 id;
71 INSERT_PADDING_WORDS(3);
72 std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
73 INSERT_PADDING_WORDS(2);
495}; 74};
75static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
496 76
497class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { 77class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
498public: 78public:
499 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 79 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
500 : ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) { 80 : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
501 static const FunctionInfo functions[] = { 81 static const FunctionInfo functions[] = {
502 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, 82 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
503 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, 83 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@@ -508,147 +88,16 @@ public:
508 } 88 }
509 89
510private: 90private:
511 enum class TransactionId {
512 RequestBuffer = 1,
513 SetBufferCount = 2,
514 DequeueBuffer = 3,
515 DetachBuffer = 4,
516 DetachNextBuffer = 5,
517 AttachBuffer = 6,
518 QueueBuffer = 7,
519 CancelBuffer = 8,
520 Query = 9,
521 Connect = 10,
522 Disconnect = 11,
523
524 AllocateBuffers = 13,
525 SetPreallocatedBuffer = 14,
526
527 GetBufferHistory = 17
528 };
529
530 void TransactParcel(Kernel::HLERequestContext& ctx) { 91 void TransactParcel(Kernel::HLERequestContext& ctx) {
531 IPC::RequestParser rp{ctx}; 92 IPC::RequestParser rp{ctx};
532 const u32 id = rp.Pop<u32>(); 93 const u32 id = rp.Pop<u32>();
533 const auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); 94 const auto transaction = static_cast<android::TransactionId>(rp.Pop<u32>());
534 const u32 flags = rp.Pop<u32>(); 95 const u32 flags = rp.Pop<u32>();
535 96
536 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, 97 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
537 transaction, flags); 98 transaction, flags);
538 99
539 auto& buffer_queue = *nv_flinger.FindBufferQueue(id); 100 server.TryGetProducer(id)->Transact(ctx, transaction, flags);
540
541 switch (transaction) {
542 case TransactionId::Connect: {
543 IGBPConnectRequestParcel request{ctx.ReadBuffer()};
544 IGBPConnectResponseParcel response{static_cast<u32>(DisplayResolution::UndockedWidth),
545 static_cast<u32>(DisplayResolution::UndockedHeight)};
546
547 buffer_queue.Connect();
548
549 ctx.WriteBuffer(response.Serialize());
550 break;
551 }
552 case TransactionId::SetPreallocatedBuffer: {
553 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
554
555 buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer);
556
557 IGBPSetPreallocatedBufferResponseParcel response{};
558 ctx.WriteBuffer(response.Serialize());
559 break;
560 }
561 case TransactionId::DequeueBuffer: {
562 IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
563 const u32 width{request.data.width};
564 const u32 height{request.data.height};
565
566 do {
567 if (auto result = buffer_queue.DequeueBuffer(width, height); result) {
568 // Buffer is available
569 IGBPDequeueBufferResponseParcel response{result->first, *result->second};
570 ctx.WriteBuffer(response.Serialize());
571 break;
572 }
573 } while (buffer_queue.IsConnected());
574
575 break;
576 }
577 case TransactionId::RequestBuffer: {
578 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
579
580 auto& buffer = buffer_queue.RequestBuffer(request.slot);
581 IGBPRequestBufferResponseParcel response{buffer};
582 ctx.WriteBuffer(response.Serialize());
583
584 break;
585 }
586 case TransactionId::QueueBuffer: {
587 IGBPQueueBufferRequestParcel request{ctx.ReadBuffer()};
588
589 buffer_queue.QueueBuffer(request.data.slot, request.data.transform,
590 request.data.GetCropRect(), request.data.swap_interval,
591 request.data.multi_fence);
592
593 IGBPQueueBufferResponseParcel response{1280, 720};
594 ctx.WriteBuffer(response.Serialize());
595 break;
596 }
597 case TransactionId::Query: {
598 IGBPQueryRequestParcel request{ctx.ReadBuffer()};
599
600 const u32 value =
601 buffer_queue.Query(static_cast<NVFlinger::BufferQueue::QueryType>(request.type));
602
603 IGBPQueryResponseParcel response{value};
604 ctx.WriteBuffer(response.Serialize());
605 break;
606 }
607 case TransactionId::CancelBuffer: {
608 IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
609
610 buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
611
612 IGBPCancelBufferResponseParcel response{};
613 ctx.WriteBuffer(response.Serialize());
614 break;
615 }
616 case TransactionId::Disconnect: {
617 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=Disconnect");
618 const auto buffer = ctx.ReadBuffer();
619
620 buffer_queue.Disconnect();
621
622 IGBPEmptyResponseParcel response{};
623 ctx.WriteBuffer(response.Serialize());
624 break;
625 }
626 case TransactionId::DetachBuffer: {
627 const auto buffer = ctx.ReadBuffer();
628
629 IGBPEmptyResponseParcel response{};
630 ctx.WriteBuffer(response.Serialize());
631 break;
632 }
633 case TransactionId::SetBufferCount: {
634 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=SetBufferCount");
635 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
636
637 IGBPEmptyResponseParcel response{};
638 ctx.WriteBuffer(response.Serialize());
639 break;
640 }
641 case TransactionId::GetBufferHistory: {
642 LOG_WARNING(Service_VI, "(STUBBED) called, transaction=GetBufferHistory");
643 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
644
645 IGBPEmptyResponseParcel response{};
646 ctx.WriteBuffer(response.Serialize());
647 break;
648 }
649 default:
650 ASSERT_MSG(false, "Unimplemented");
651 }
652 101
653 IPC::ResponseBuilder rb{ctx, 2}; 102 IPC::ResponseBuilder rb{ctx, 2};
654 rb.Push(ResultSuccess); 103 rb.Push(ResultSuccess);
@@ -674,13 +123,13 @@ private:
674 123
675 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); 124 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
676 125
677 // TODO(Subv): Find out what this actually is.
678 IPC::ResponseBuilder rb{ctx, 2, 1}; 126 IPC::ResponseBuilder rb{ctx, 2, 1};
679 rb.Push(ResultSuccess); 127 rb.Push(ResultSuccess);
680 rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent()); 128 rb.PushCopyObjects(server.TryGetProducer(id)->GetNativeHandle());
681 } 129 }
682 130
683 NVFlinger::NVFlinger& nv_flinger; 131private:
132 NVFlinger::HosBinderDriverServer& server;
684}; 133};
685 134
686class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { 135class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@@ -937,7 +386,40 @@ private:
937 386
938class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 387class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
939public: 388public:
940 explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 389 IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
390 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
391 : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_},
392 hos_binder_driver_server{hos_binder_driver_server_} {
393
394 static const FunctionInfo functions[] = {
395 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
396 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
397 {102, &IApplicationDisplayService::GetManagerDisplayService,
398 "GetManagerDisplayService"},
399 {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
400 "GetIndirectDisplayTransactionService"},
401 {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
402 {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
403 {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
404 {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
405 {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
406 {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
407 {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
408 {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
409 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
410 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
411 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
412 {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
413 {2450, &IApplicationDisplayService::GetIndirectLayerImageMap,
414 "GetIndirectLayerImageMap"},
415 {2451, nullptr, "GetIndirectLayerImageCropMap"},
416 {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
417 "GetIndirectLayerImageRequiredMemoryInfo"},
418 {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
419 {5203, nullptr, "GetDisplayVsyncEventForDebug"},
420 };
421 RegisterHandlers(functions);
422 }
941 423
942private: 424private:
943 enum class ConvertedScaleMode : u64 { 425 enum class ConvertedScaleMode : u64 {
@@ -961,7 +443,7 @@ private:
961 443
962 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 444 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
963 rb.Push(ResultSuccess); 445 rb.Push(ResultSuccess);
964 rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); 446 rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
965 } 447 }
966 448
967 void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { 449 void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
@@ -985,7 +467,7 @@ private:
985 467
986 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 468 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
987 rb.Push(ResultSuccess); 469 rb.Push(ResultSuccess);
988 rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger); 470 rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
989 } 471 }
990 472
991 void OpenDisplay(Kernel::HLERequestContext& ctx) { 473 void OpenDisplay(Kernel::HLERequestContext& ctx) {
@@ -1089,7 +571,7 @@ private:
1089 void ListDisplays(Kernel::HLERequestContext& ctx) { 571 void ListDisplays(Kernel::HLERequestContext& ctx) {
1090 LOG_WARNING(Service_VI, "(STUBBED) called"); 572 LOG_WARNING(Service_VI, "(STUBBED) called");
1091 573
1092 DisplayInfo display_info; 574 const DisplayInfo display_info;
1093 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 575 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
1094 IPC::ResponseBuilder rb{ctx, 4}; 576 IPC::ResponseBuilder rb{ctx, 4};
1095 rb.Push(ResultSuccess); 577 rb.Push(ResultSuccess);
@@ -1124,8 +606,8 @@ private:
1124 return; 606 return;
1125 } 607 }
1126 608
1127 NativeWindow native_window{*buffer_queue_id}; 609 const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
1128 const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); 610 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
1129 611
1130 IPC::ResponseBuilder rb{ctx, 4}; 612 IPC::ResponseBuilder rb{ctx, 4};
1131 rb.Push(ResultSuccess); 613 rb.Push(ResultSuccess);
@@ -1170,8 +652,8 @@ private:
1170 return; 652 return;
1171 } 653 }
1172 654
1173 NativeWindow native_window{*buffer_queue_id}; 655 const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
1174 const auto buffer_size = ctx.WriteBuffer(native_window.Serialize()); 656 const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
1175 657
1176 IPC::ResponseBuilder rb{ctx, 6}; 658 IPC::ResponseBuilder rb{ctx, 6};
1177 rb.Push(ResultSuccess); 659 rb.Push(ResultSuccess);
@@ -1287,39 +769,9 @@ private:
1287 } 769 }
1288 770
1289 NVFlinger::NVFlinger& nv_flinger; 771 NVFlinger::NVFlinger& nv_flinger;
772 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
1290}; 773};
1291 774
1292IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
1293 NVFlinger::NVFlinger& nv_flinger_)
1294 : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} {
1295 static const FunctionInfo functions[] = {
1296 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
1297 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
1298 {102, &IApplicationDisplayService::GetManagerDisplayService, "GetManagerDisplayService"},
1299 {103, &IApplicationDisplayService::GetIndirectDisplayTransactionService,
1300 "GetIndirectDisplayTransactionService"},
1301 {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"},
1302 {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"},
1303 {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"},
1304 {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"},
1305 {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"},
1306 {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"},
1307 {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"},
1308 {2021, &IApplicationDisplayService::CloseLayer, "CloseLayer"},
1309 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
1310 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
1311 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
1312 {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
1313 {2450, &IApplicationDisplayService::GetIndirectLayerImageMap, "GetIndirectLayerImageMap"},
1314 {2451, nullptr, "GetIndirectLayerImageCropMap"},
1315 {2460, &IApplicationDisplayService::GetIndirectLayerImageRequiredMemoryInfo,
1316 "GetIndirectLayerImageRequiredMemoryInfo"},
1317 {5202, &IApplicationDisplayService::GetDisplayVsyncEvent, "GetDisplayVsyncEvent"},
1318 {5203, nullptr, "GetDisplayVsyncEventForDebug"},
1319 };
1320 RegisterHandlers(functions);
1321}
1322
1323static bool IsValidServiceAccess(Permission permission, Policy policy) { 775static bool IsValidServiceAccess(Permission permission, Policy policy) {
1324 if (permission == Permission::User) { 776 if (permission == Permission::User) {
1325 return policy == Policy::User; 777 return policy == Policy::User;
@@ -1333,7 +785,9 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
1333} 785}
1334 786
1335void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, 787void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
1336 NVFlinger::NVFlinger& nv_flinger, Permission permission) { 788 NVFlinger::NVFlinger& nv_flinger,
789 NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
790 Permission permission) {
1337 IPC::RequestParser rp{ctx}; 791 IPC::RequestParser rp{ctx};
1338 const auto policy = rp.PopEnum<Policy>(); 792 const auto policy = rp.PopEnum<Policy>();
1339 793
@@ -1346,14 +800,18 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System&
1346 800
1347 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 801 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1348 rb.Push(ResultSuccess); 802 rb.Push(ResultSuccess);
1349 rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger); 803 rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server);
1350} 804}
1351 805
1352void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, 806void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
1353 NVFlinger::NVFlinger& nv_flinger) { 807 NVFlinger::NVFlinger& nv_flinger,
1354 std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager); 808 NVFlinger::HosBinderDriverServer& hos_binder_driver_server) {
1355 std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager); 809 std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)
1356 std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager); 810 ->InstallAsService(service_manager);
811 std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)
812 ->InstallAsService(service_manager);
813 std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)
814 ->InstallAsService(service_manager);
1357} 815}
1358 816
1359} // namespace Service::VI 817} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 2fd7f8e61..d68f2646b 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -15,8 +15,9 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::SM { 22namespace Service::SM {
22class ServiceManager; 23class ServiceManager;
@@ -47,11 +48,14 @@ enum class Policy {
47 48
48namespace detail { 49namespace detail {
49void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system, 50void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
50 NVFlinger::NVFlinger& nv_flinger, Permission permission); 51 NVFlinger::NVFlinger& nv_flinger,
52 NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
53 Permission permission);
51} // namespace detail 54} // namespace detail
52 55
53/// Registers all VI services with the specified service manager. 56/// Registers all VI services with the specified service manager.
54void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system, 57void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
55 NVFlinger::NVFlinger& nv_flinger); 58 NVFlinger::NVFlinger& nv_flinger,
59 NVFlinger::HosBinderDriverServer& hos_binder_driver_server);
56 60
57} // namespace Service::VI 61} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 87db1c416..be0255f3d 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -8,8 +8,10 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 11VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
12 : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} { 12 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
13 : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
14 hos_binder_driver_server_} {
13 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
14 {2, &VI_M::GetDisplayService, "GetDisplayService"}, 16 {2, &VI_M::GetDisplayService, "GetDisplayService"},
15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 17 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_M::~VI_M() = default;
22void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { 24void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 25 LOG_DEBUG(Service_VI, "called");
24 26
25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager); 27 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
28 Permission::Manager);
26} 29}
27 30
28} // namespace Service::VI 31} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index d79c41beb..efbd34e09 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -15,20 +15,23 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::VI { 22namespace Service::VI {
22 23
23class VI_M final : public ServiceFramework<VI_M> { 24class VI_M final : public ServiceFramework<VI_M> {
24public: 25public:
25 explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 26 explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
27 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
26 ~VI_M() override; 28 ~VI_M() override;
27 29
28private: 30private:
29 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
30 32
31 NVFlinger::NVFlinger& nv_flinger; 33 NVFlinger::NVFlinger& nv_flinger;
34 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
32}; 35};
33 36
34} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index 5cd22f7df..7996a6811 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -8,8 +8,10 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 11VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
12 : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} { 12 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
13 : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
14 hos_binder_driver_server_} {
13 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
14 {1, &VI_S::GetDisplayService, "GetDisplayService"}, 16 {1, &VI_S::GetDisplayService, "GetDisplayService"},
15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 17 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_S::~VI_S() = default;
22void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { 24void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 25 LOG_DEBUG(Service_VI, "called");
24 26
25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System); 27 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
28 Permission::System);
26} 29}
27 30
28} // namespace Service::VI 31} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 5f1f8f290..3812c5061 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -15,20 +15,23 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::VI { 22namespace Service::VI {
22 23
23class VI_S final : public ServiceFramework<VI_S> { 24class VI_S final : public ServiceFramework<VI_S> {
24public: 25public:
25 explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 26 explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
27 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
26 ~VI_S() override; 28 ~VI_S() override;
27 29
28private: 30private:
29 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
30 32
31 NVFlinger::NVFlinger& nv_flinger; 33 NVFlinger::NVFlinger& nv_flinger;
34 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
32}; 35};
33 36
34} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 0079d51f0..57c888313 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -8,8 +8,10 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_) 11VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
12 : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} { 12 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
13 : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
14 hos_binder_driver_server_} {
13 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
14 {0, &VI_U::GetDisplayService, "GetDisplayService"}, 16 {0, &VI_U::GetDisplayService, "GetDisplayService"},
15 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 17 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +24,8 @@ VI_U::~VI_U() = default;
22void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { 24void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 25 LOG_DEBUG(Service_VI, "called");
24 26
25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User); 27 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
28 Permission::User);
26} 29}
27 30
28} // namespace Service::VI 31} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index 8e3885c73..b08e56576 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -15,20 +15,23 @@ class HLERequestContext;
15} 15}
16 16
17namespace Service::NVFlinger { 17namespace Service::NVFlinger {
18class HosBinderDriverServer;
18class NVFlinger; 19class NVFlinger;
19} 20} // namespace Service::NVFlinger
20 21
21namespace Service::VI { 22namespace Service::VI {
22 23
23class VI_U final : public ServiceFramework<VI_U> { 24class VI_U final : public ServiceFramework<VI_U> {
24public: 25public:
25 explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_); 26 explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
27 NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
26 ~VI_U() override; 28 ~VI_U() override;
27 29
28private: 30private:
29 void GetDisplayService(Kernel::HLERequestContext& ctx); 31 void GetDisplayService(Kernel::HLERequestContext& ctx);
30 32
31 NVFlinger::NVFlinger& nv_flinger; 33 NVFlinger::NVFlinger& nv_flinger;
34 NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
32}; 35};
33 36
34} // namespace Service::VI 37} // namespace Service::VI
diff --git a/src/video_core/framebuffer_config.h b/src/video_core/framebuffer_config.h
index b1d455e30..93349bb78 100644
--- a/src/video_core/framebuffer_config.h
+++ b/src/video_core/framebuffer_config.h
@@ -6,41 +6,22 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/math_util.h" 8#include "common/math_util.h"
9#include "core/hle/service/nvflinger/buffer_transform_flags.h"
10#include "core/hle/service/nvflinger/pixel_format.h"
9 11
10namespace Tegra { 12namespace Tegra {
13
11/** 14/**
12 * Struct describing framebuffer configuration 15 * Struct describing framebuffer configuration
13 */ 16 */
14struct FramebufferConfig { 17struct FramebufferConfig {
15 enum class PixelFormat : u32 {
16 A8B8G8R8_UNORM = 1,
17 RGB565_UNORM = 4,
18 B8G8R8A8_UNORM = 5,
19 };
20
21 enum class TransformFlags : u32 {
22 /// No transform flags are set
23 Unset = 0x00,
24 /// Flip source image horizontally (around the vertical axis)
25 FlipH = 0x01,
26 /// Flip source image vertically (around the horizontal axis)
27 FlipV = 0x02,
28 /// Rotate source image 90 degrees clockwise
29 Rotate90 = 0x04,
30 /// Rotate source image 180 degrees
31 Rotate180 = 0x03,
32 /// Rotate source image 270 degrees clockwise
33 Rotate270 = 0x07,
34 };
35
36 VAddr address{}; 18 VAddr address{};
37 u32 offset{}; 19 u32 offset{};
38 u32 width{}; 20 u32 width{};
39 u32 height{}; 21 u32 height{};
40 u32 stride{}; 22 u32 stride{};
41 PixelFormat pixel_format{}; 23 Service::android::PixelFormat pixel_format{};
42 24 Service::android::BufferTransformFlags transform_flags{};
43 TransformFlags transform_flags{};
44 Common::Rectangle<int> crop_rect; 25 Common::Rectangle<int> crop_rect;
45}; 26};
46 27
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 26b8ea233..97c029140 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -8,6 +8,7 @@
8 8
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/nvdrv/nvdata.h"
11#include "video_core/cdma_pusher.h" 12#include "video_core/cdma_pusher.h"
12#include "video_core/framebuffer_config.h" 13#include "video_core/framebuffer_config.h"
13 14
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 795c97831..f8f29013a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -323,12 +323,12 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
323 323
324 GLint internal_format; 324 GLint internal_format;
325 switch (framebuffer.pixel_format) { 325 switch (framebuffer.pixel_format) {
326 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: 326 case Service::android::PixelFormat::Rgba8888:
327 internal_format = GL_RGBA8; 327 internal_format = GL_RGBA8;
328 texture.gl_format = GL_RGBA; 328 texture.gl_format = GL_RGBA;
329 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; 329 texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
330 break; 330 break;
331 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: 331 case Service::android::PixelFormat::Rgb565:
332 internal_format = GL_RGB565; 332 internal_format = GL_RGB565;
333 texture.gl_format = GL_RGB; 333 texture.gl_format = GL_RGB;
334 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5; 334 texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
@@ -464,8 +464,8 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
464 const auto& texcoords = screen_info.display_texcoords; 464 const auto& texcoords = screen_info.display_texcoords;
465 auto left = texcoords.left; 465 auto left = texcoords.left;
466 auto right = texcoords.right; 466 auto right = texcoords.right;
467 if (framebuffer_transform_flags != Tegra::FramebufferConfig::TransformFlags::Unset) { 467 if (framebuffer_transform_flags != Service::android::BufferTransformFlags::Unset) {
468 if (framebuffer_transform_flags == Tegra::FramebufferConfig::TransformFlags::FlipV) { 468 if (framebuffer_transform_flags == Service::android::BufferTransformFlags::FlipV) {
469 // Flip the framebuffer vertically 469 // Flip the framebuffer vertically
470 left = texcoords.right; 470 left = texcoords.right;
471 right = texcoords.left; 471 right = texcoords.left;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 35706cf05..aa206878b 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -46,7 +46,7 @@ struct TextureInfo {
46 GLsizei height; 46 GLsizei height;
47 GLenum gl_format; 47 GLenum gl_format;
48 GLenum gl_type; 48 GLenum gl_type;
49 Tegra::FramebufferConfig::PixelFormat pixel_format; 49 Service::android::PixelFormat pixel_format;
50}; 50};
51 51
52/// Structure used for storing information about the display target for the Switch screen 52/// Structure used for storing information about the display target for the Switch screen
@@ -135,7 +135,7 @@ private:
135 std::vector<u8> gl_framebuffer_data; 135 std::vector<u8> gl_framebuffer_data;
136 136
137 /// Used for transforming the framebuffer orientation 137 /// Used for transforming the framebuffer orientation
138 Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; 138 Service::android::BufferTransformFlags framebuffer_transform_flags{};
139 Common::Rectangle<int> framebuffer_crop_rect; 139 Common::Rectangle<int> framebuffer_crop_rect;
140}; 140};
141 141
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 0ec85682b..d893c1952 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -94,11 +94,11 @@ std::size_t GetSizeInBytes(const Tegra::FramebufferConfig& framebuffer) {
94 94
95VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) { 95VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
96 switch (framebuffer.pixel_format) { 96 switch (framebuffer.pixel_format) {
97 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: 97 case Service::android::PixelFormat::Rgba8888:
98 return VK_FORMAT_A8B8G8R8_UNORM_PACK32; 98 return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
99 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: 99 case Service::android::PixelFormat::Rgb565:
100 return VK_FORMAT_R5G6B5_UNORM_PACK16; 100 return VK_FORMAT_R5G6B5_UNORM_PACK16;
101 case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: 101 case Service::android::PixelFormat::Bgra8888:
102 return VK_FORMAT_B8G8R8A8_UNORM; 102 return VK_FORMAT_B8G8R8A8_UNORM;
103 default: 103 default:
104 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", 104 UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}",
@@ -1390,9 +1390,9 @@ void VKBlitScreen::SetVertexData(BufferData& data, const Tegra::FramebufferConfi
1390 auto right = texcoords.right; 1390 auto right = texcoords.right;
1391 1391
1392 switch (framebuffer_transform_flags) { 1392 switch (framebuffer_transform_flags) {
1393 case Tegra::FramebufferConfig::TransformFlags::Unset: 1393 case Service::android::BufferTransformFlags::Unset:
1394 break; 1394 break;
1395 case Tegra::FramebufferConfig::TransformFlags::FlipV: 1395 case Service::android::BufferTransformFlags::FlipV:
1396 // Flip the framebuffer vertically 1396 // Flip the framebuffer vertically
1397 left = texcoords.right; 1397 left = texcoords.right;
1398 right = texcoords.left; 1398 right = texcoords.left;
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index a36015c8c..5f428d35d 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -190,13 +190,13 @@ PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format)
190 } 190 }
191} 191}
192 192
193PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { 193PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format) {
194 switch (format) { 194 switch (format) {
195 case Tegra::FramebufferConfig::PixelFormat::A8B8G8R8_UNORM: 195 case Service::android::PixelFormat::Rgba8888:
196 return PixelFormat::A8B8G8R8_UNORM; 196 return PixelFormat::A8B8G8R8_UNORM;
197 case Tegra::FramebufferConfig::PixelFormat::RGB565_UNORM: 197 case Service::android::PixelFormat::Rgb565:
198 return PixelFormat::R5G6B5_UNORM; 198 return PixelFormat::R5G6B5_UNORM;
199 case Tegra::FramebufferConfig::PixelFormat::B8G8R8A8_UNORM: 199 case Service::android::PixelFormat::Bgra8888:
200 return PixelFormat::B8G8R8A8_UNORM; 200 return PixelFormat::B8G8R8A8_UNORM;
201 default: 201 default:
202 UNIMPLEMENTED_MSG("Unimplemented format={}", format); 202 UNIMPLEMENTED_MSG("Unimplemented format={}", format);
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 33e8d24ab..5704cf16a 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -460,7 +460,7 @@ PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
460 460
461PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format); 461PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
462 462
463PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format); 463PixelFormat PixelFormatFromGPUPixelFormat(Service::android::PixelFormat format);
464 464
465SurfaceType GetFormatType(PixelFormat pixel_format); 465SurfaceType GetFormatType(PixelFormat pixel_format);
466 466