summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp35
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h10
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp215
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.h59
-rw-r--r--src/core/hle/service/nvnflinger/hwc_layer.h27
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp42
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h2
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp4
-rw-r--r--src/core/hle/service/vi/display/vi_display.h15
-rw-r--r--src/core/hle/service/vi/vi.cpp5
11 files changed, 360 insertions, 57 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 570acb193..eb8f643a2 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -775,6 +775,9 @@ add_library(core STATIC
775 hle/service/nvnflinger/graphic_buffer_producer.h 775 hle/service/nvnflinger/graphic_buffer_producer.h
776 hle/service/nvnflinger/hos_binder_driver_server.cpp 776 hle/service/nvnflinger/hos_binder_driver_server.cpp
777 hle/service/nvnflinger/hos_binder_driver_server.h 777 hle/service/nvnflinger/hos_binder_driver_server.h
778 hle/service/nvnflinger/hardware_composer.cpp
779 hle/service/nvnflinger/hardware_composer.h
780 hle/service/nvnflinger/hwc_layer.h
778 hle/service/nvnflinger/nvnflinger.cpp 781 hle/service/nvnflinger/nvnflinger.cpp
779 hle/service/nvnflinger/nvnflinger.h 782 hle/service/nvnflinger/nvnflinger.h
780 hle/service/nvnflinger/parcel.h 783 hle/service/nvnflinger/parcel.h
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index c1ebbd62d..abe95303e 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -1,6 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <boost/container/small_vector.hpp>
5
4#include "common/assert.h" 6#include "common/assert.h"
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6#include "core/core.h" 8#include "core/core.h"
@@ -38,19 +40,30 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
38void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} 40void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
39void nvdisp_disp0::OnClose(DeviceFD fd) {} 41void nvdisp_disp0::OnClose(DeviceFD fd) {}
40 42
41void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, 43void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers) {
42 u32 height, u32 stride, android::BufferTransformFlags transform, 44 std::vector<Tegra::FramebufferConfig> output_layers;
43 const Common::Rectangle<int>& crop_rect, 45 std::vector<Service::Nvidia::NvFence> output_fences;
44 std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { 46 output_layers.reserve(sorted_layers.size());
45 const DAddr addr = nvmap.GetHandleAddress(buffer_handle); 47 output_fences.reserve(sorted_layers.size());
46 LOG_TRACE(Service, 48
47 "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", 49 for (auto& layer : sorted_layers) {
48 addr, offset, width, height, stride, format); 50 output_layers.emplace_back(Tegra::FramebufferConfig{
51 .address = nvmap.GetHandleAddress(layer.buffer_handle),
52 .offset = layer.offset,
53 .width = layer.width,
54 .height = layer.height,
55 .stride = layer.stride,
56 .pixel_format = layer.format,
57 .transform_flags = layer.transform,
58 .crop_rect = layer.crop_rect,
59 });
49 60
50 const Tegra::FramebufferConfig framebuffer{addr, offset, width, height, 61 for (size_t i = 0; i < layer.acquire_fence.num_fences; i++) {
51 stride, format, transform, crop_rect}; 62 output_fences.push_back(layer.acquire_fence.fences[i]);
63 }
64 }
52 65
53 system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences); 66 system.GPU().RequestComposite(std::move(output_layers), std::move(output_fences));
54 system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs()); 67 system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
55 system.GetPerfStats().EndSystemFrame(); 68 system.GetPerfStats().EndSystemFrame();
56 system.GetPerfStats().BeginSystemFrame(); 69 system.GetPerfStats().BeginSystemFrame();
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 5f13a50a2..1082b85c2 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -8,8 +8,7 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/math_util.h" 9#include "common/math_util.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h" 10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11#include "core/hle/service/nvnflinger/buffer_transform_flags.h" 11#include "core/hle/service/nvnflinger/hwc_layer.h"
12#include "core/hle/service/nvnflinger/pixel_format.h"
13 12
14namespace Service::Nvidia::NvCore { 13namespace Service::Nvidia::NvCore {
15class Container; 14class Container;
@@ -35,11 +34,8 @@ public:
35 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; 34 void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override;
36 void OnClose(DeviceFD fd) override; 35 void OnClose(DeviceFD fd) override;
37 36
38 /// Performs a screen flip, drawing the buffer pointed to by the handle. 37 /// Performs a screen flip, compositing each buffer.
39 void flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, 38 void Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers);
40 u32 stride, android::BufferTransformFlags transform,
41 const Common::Rectangle<int>& crop_rect,
42 std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences);
43 39
44 Kernel::KEvent* QueryEvent(u32 event_id) override; 40 Kernel::KEvent* QueryEvent(u32 event_id) override;
45 41
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
new file mode 100644
index 000000000..c720dd1f8
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -0,0 +1,215 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <boost/container/small_vector.hpp>
5
6#include "common/microprofile.h"
7#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
8#include "core/hle/service/nvnflinger/buffer_item.h"
9#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
10#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
11#include "core/hle/service/nvnflinger/hardware_composer.h"
12#include "core/hle/service/nvnflinger/hwc_layer.h"
13#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
14#include "core/hle/service/vi/display/vi_display.h"
15#include "core/hle/service/vi/layer/vi_layer.h"
16
17namespace Service::Nvnflinger {
18
19namespace {
20
21s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
22 if (swap_interval <= 0) {
23 // As an extension, treat nonpositive swap interval as speed multiplier.
24 if (out_speed_scale) {
25 *out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval);
26 }
27
28 swap_interval = 1;
29 }
30
31 if (swap_interval >= 5) {
32 // As an extension, treat high swap interval as precise speed control.
33 if (out_speed_scale) {
34 *out_speed_scale = static_cast<f32>(swap_interval) / 100.f;
35 }
36
37 swap_interval = 1;
38 }
39
40 return swap_interval;
41}
42
43} // namespace
44
45HardwareComposer::HardwareComposer() = default;
46HardwareComposer::~HardwareComposer() = default;
47
48u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
49 Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) {
50 boost::container::small_vector<HwcLayer, 2> composition_stack;
51
52 m_frame_number += frame_advance;
53
54 // Release any necessary framebuffers.
55 for (auto& [layer_id, framebuffer] : m_framebuffers) {
56 if (framebuffer.release_frame_number > m_frame_number) {
57 // Not yet ready to release this framebuffer.
58 continue;
59 }
60
61 if (!framebuffer.is_acquired) {
62 // Already released.
63 continue;
64 }
65
66 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
67 // TODO: support release fence
68 // This is needed to prevent screen tearing
69 layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
70 framebuffer.is_acquired = false;
71 }
72 }
73
74 // Set default speed limit to 100%.
75 *out_speed_scale = 1.0f;
76
77 // Determine the number of vsync periods to wait before composing again.
78 std::optional<s32> swap_interval{};
79 bool has_acquired_buffer{};
80
81 // Acquire all necessary framebuffers.
82 for (size_t i = 0; i < display.GetNumLayers(); i++) {
83 auto& layer = display.GetLayer(i);
84 auto layer_id = layer.GetLayerId();
85
86 // Try to fetch the framebuffer (either new or stale).
87 const auto result = this->CacheFramebufferLocked(layer, layer_id);
88
89 // If we failed, skip this layer.
90 if (result == CacheStatus::NoBufferAvailable) {
91 continue;
92 }
93
94 // If we acquired a new buffer, we need to present.
95 if (result == CacheStatus::BufferAcquired) {
96 has_acquired_buffer = true;
97 }
98
99 const auto& buffer = m_framebuffers[layer_id];
100 const auto& item = buffer.item;
101 const auto& igbp_buffer = *item.graphic_buffer;
102
103 // TODO: get proper Z-index from layer
104 composition_stack.emplace_back(HwcLayer{
105 .buffer_handle = igbp_buffer.BufferId(),
106 .offset = igbp_buffer.Offset(),
107 .format = igbp_buffer.ExternalFormat(),
108 .width = igbp_buffer.Width(),
109 .height = igbp_buffer.Height(),
110 .stride = igbp_buffer.Stride(),
111 .z_index = 0,
112 .transform = static_cast<android::BufferTransformFlags>(item.transform),
113 .crop_rect = item.crop,
114 .acquire_fence = item.fence,
115 });
116
117 // We need to compose again either before this frame is supposed to
118 // be released, or exactly on the vsync period it should be released.
119 const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval);
120
121 // TODO: handle cases where swap intervals are relatively prime. So far,
122 // only swap intervals of 0, 1 and 2 have been observed, but if 3 were
123 // to be introduced, this would cause an issue.
124 if (swap_interval) {
125 swap_interval = std::min(*swap_interval, item_swap_interval);
126 } else {
127 swap_interval = item_swap_interval;
128 }
129 }
130
131 // If any new buffers were acquired, we can present.
132 if (has_acquired_buffer) {
133 // Sort by Z-index.
134 std::stable_sort(composition_stack.begin(), composition_stack.end(),
135 [&](auto& l, auto& r) { return l.z_index < r.z_index; });
136
137 // Composite.
138 nvdisp.Composite(composition_stack);
139 }
140
141 // Render MicroProfile.
142 MicroProfileFlip();
143
144 // Advance by at least one frame.
145 return swap_interval.value_or(1);
146}
147
148void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
149 // Check if we are tracking a slot with this layer_id.
150 const auto it = m_framebuffers.find(layer_id);
151 if (it == m_framebuffers.end()) {
152 return;
153 }
154
155 // Try to release the buffer item.
156 auto* const layer = display.FindLayer(layer_id);
157 if (layer && it->second.is_acquired) {
158 layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence());
159 }
160
161 // Erase the slot.
162 m_framebuffers.erase(it);
163}
164
165bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) {
166 // Attempt the update.
167 const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false);
168 if (status != android::Status::NoError) {
169 return false;
170 }
171
172 // We succeeded, so set the new release frame info.
173 framebuffer.release_frame_number =
174 NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
175 framebuffer.is_acquired = true;
176
177 return true;
178}
179
180HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer,
181 LayerId layer_id) {
182 // Check if this framebuffer is already present.
183 const auto it = m_framebuffers.find(layer_id);
184 if (it != m_framebuffers.end()) {
185 // If it's currently still acquired, we are done.
186 if (it->second.is_acquired) {
187 return CacheStatus::CachedBufferReused;
188 }
189
190 // Try to acquire a new item.
191 if (this->TryAcquireFramebufferLocked(layer, it->second)) {
192 // We got a new item.
193 return CacheStatus::BufferAcquired;
194 } else {
195 // We didn't acquire a new item, but we can reuse the slot.
196 return CacheStatus::CachedBufferReused;
197 }
198 }
199
200 // Framebuffer is not present, so try to create it.
201 Framebuffer framebuffer{};
202
203 if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
204 // Move the buffer item into a new slot.
205 m_framebuffers.emplace(layer_id, std::move(framebuffer));
206
207 // We succeeded.
208 return CacheStatus::BufferAcquired;
209 }
210
211 // We couldn't acquire the buffer item, so don't create a slot.
212 return CacheStatus::NoBufferAvailable;
213}
214
215} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.h b/src/core/hle/service/nvnflinger/hardware_composer.h
new file mode 100644
index 000000000..ddab94ac9
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/hardware_composer.h
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <boost/container/flat_map.hpp>
8
9#include "core/hle/service/nvnflinger/buffer_item.h"
10
11namespace Service::Nvidia::Devices {
12class nvdisp_disp0;
13}
14
15namespace Service::VI {
16class Display;
17class Layer;
18} // namespace Service::VI
19
20namespace Service::Nvnflinger {
21
22using LayerId = u64;
23
24class HardwareComposer {
25public:
26 explicit HardwareComposer();
27 ~HardwareComposer();
28
29 u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
30 Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance);
31 void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
32
33private:
34 // TODO: do we want to track frame number in vi instead?
35 u64 m_frame_number{0};
36
37private:
38 using ReleaseFrameNumber = u64;
39
40 struct Framebuffer {
41 android::BufferItem item{};
42 ReleaseFrameNumber release_frame_number{};
43 bool is_acquired{false};
44 };
45
46 enum class CacheStatus : u32 {
47 NoBufferAvailable,
48 BufferAcquired,
49 CachedBufferReused,
50 };
51
52 boost::container::flat_map<LayerId, Framebuffer> m_framebuffers{};
53
54private:
55 bool TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer);
56 CacheStatus CacheFramebufferLocked(VI::Layer& layer, LayerId layer_id);
57};
58
59} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/hwc_layer.h b/src/core/hle/service/nvnflinger/hwc_layer.h
new file mode 100644
index 000000000..3af668a25
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/hwc_layer.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/math_util.h"
7#include "core/hle/service/nvdrv/nvdata.h"
8#include "core/hle/service/nvnflinger/buffer_transform_flags.h"
9#include "core/hle/service/nvnflinger/pixel_format.h"
10#include "core/hle/service/nvnflinger/ui/fence.h"
11
12namespace Service::Nvnflinger {
13
14struct HwcLayer {
15 u32 buffer_handle;
16 u32 offset;
17 android::PixelFormat format;
18 u32 width;
19 u32 height;
20 u32 stride;
21 s32 z_index;
22 android::BufferTransformFlags transform;
23 Common::Rectangle<int> crop_rect;
24 android::Fence acquire_fence;
25};
26
27} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 51133853c..a4e848882 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -18,6 +18,7 @@
18#include "core/hle/service/nvnflinger/buffer_item_consumer.h" 18#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
19#include "core/hle/service/nvnflinger/buffer_queue_core.h" 19#include "core/hle/service/nvnflinger/buffer_queue_core.h"
20#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" 20#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
21#include "core/hle/service/nvnflinger/hardware_composer.h"
21#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" 22#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
22#include "core/hle/service/nvnflinger/nvnflinger.h" 23#include "core/hle/service/nvnflinger/nvnflinger.h"
23#include "core/hle/service/nvnflinger/ui/graphic_buffer.h" 24#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@@ -279,45 +280,19 @@ void Nvnflinger::Compose() {
279 SCOPE_EXIT({ display.SignalVSyncEvent(); }); 280 SCOPE_EXIT({ display.SignalVSyncEvent(); });
280 281
281 // Don't do anything for displays without layers. 282 // Don't do anything for displays without layers.
282 if (!display.HasLayers()) 283 if (!display.HasLayers()) {
283 continue;
284
285 // TODO(Subv): Support more than 1 layer.
286 VI::Layer& layer = display.GetLayer(0);
287
288 android::BufferItem buffer{};
289 const auto status = layer.GetConsumer().AcquireBuffer(&buffer, {}, false);
290
291 if (status != android::Status::NoError) {
292 continue; 284 continue;
293 } 285 }
294 286
295 const auto& igbp_buffer = *buffer.graphic_buffer;
296
297 if (!system.IsPoweredOn()) { 287 if (!system.IsPoweredOn()) {
298 return; // We are likely shutting down 288 return; // We are likely shutting down
299 } 289 }
300 290
301 // Now send the buffer to the GPU for drawing.
302 // TODO(Subv): Support more than just disp0. The display device selection is probably based
303 // on which display we're drawing (Default, Internal, External, etc)
304 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); 291 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
305 ASSERT(nvdisp); 292 ASSERT(nvdisp);
306 293
307 Common::Rectangle<int> crop_rect{ 294 swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp,
308 static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()), 295 swap_interval);
309 static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())};
310
311 nvdisp->flip(igbp_buffer.BufferId(), igbp_buffer.Offset(), igbp_buffer.ExternalFormat(),
312 igbp_buffer.Width(), igbp_buffer.Height(), igbp_buffer.Stride(),
313 static_cast<android::BufferTransformFlags>(buffer.transform), crop_rect,
314 buffer.fence.fences, buffer.fence.num_fences);
315
316 MicroProfileFlip();
317
318 swap_interval = buffer.swap_interval;
319
320 layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence());
321 } 296 }
322} 297}
323 298
@@ -334,15 +309,16 @@ s64 Nvnflinger::GetNextTicks() const {
334 speed_scale = 0.01f; 309 speed_scale = 0.01f;
335 } 310 }
336 } 311 }
312
313 // Adjust by speed limit determined during composition.
314 speed_scale /= compose_speed_scale;
315
337 if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) { 316 if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
338 // Run at intended presentation rate during video playback. 317 // Run at intended presentation rate during video playback.
339 speed_scale = 1.f; 318 speed_scale = 1.f;
340 } 319 }
341 320
342 // As an extension, treat nonpositive swap interval as framerate multiplier. 321 const f32 effective_fps = 60.f / static_cast<f32>(swap_interval);
343 const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
344 : 60.f / static_cast<f32>(swap_interval);
345
346 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps)); 322 return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
347} 323}
348 324
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index 369439142..c984d55a0 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -46,6 +46,7 @@ class BufferQueueProducer;
46namespace Service::Nvnflinger { 46namespace Service::Nvnflinger {
47 47
48class FbShareBufferManager; 48class FbShareBufferManager;
49class HardwareComposer;
49class HosBinderDriverServer; 50class HosBinderDriverServer;
50 51
51class Nvnflinger final { 52class Nvnflinger final {
@@ -143,6 +144,7 @@ private:
143 u32 next_buffer_queue_id = 1; 144 u32 next_buffer_queue_id = 1;
144 145
145 s32 swap_interval = 1; 146 s32 swap_interval = 1;
147 f32 compose_speed_scale = 1.0f;
146 148
147 bool is_abandoned = false; 149 bool is_abandoned = false;
148 150
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index dab1905cc..7f2af9acc 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/service/nvnflinger/buffer_queue_consumer.h" 16#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
17#include "core/hle/service/nvnflinger/buffer_queue_core.h" 17#include "core/hle/service/nvnflinger/buffer_queue_core.h"
18#include "core/hle/service/nvnflinger/buffer_queue_producer.h" 18#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
19#include "core/hle/service/nvnflinger/hardware_composer.h"
19#include "core/hle/service/nvnflinger/hos_binder_driver_server.h" 20#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
20#include "core/hle/service/vi/display/vi_display.h" 21#include "core/hle/service/vi/display/vi_display.h"
21#include "core/hle/service/vi/layer/vi_layer.h" 22#include "core/hle/service/vi/layer/vi_layer.h"
@@ -43,6 +44,7 @@ Display::Display(u64 id, std::string name_,
43 KernelHelpers::ServiceContext& service_context_, Core::System& system_) 44 KernelHelpers::ServiceContext& service_context_, Core::System& system_)
44 : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_}, 45 : display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
45 service_context{service_context_} { 46 service_context{service_context_} {
47 hardware_composer = std::make_unique<Nvnflinger::HardwareComposer>();
46 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id)); 48 vsync_event = service_context.CreateEvent(fmt::format("Display VSync Event {}", id));
47} 49}
48 50
@@ -81,8 +83,6 @@ void Display::SignalVSyncEvent() {
81 83
82void Display::CreateLayer(u64 layer_id, u32 binder_id, 84void Display::CreateLayer(u64 layer_id, u32 binder_id,
83 Service::Nvidia::NvCore::Container& nv_core) { 85 Service::Nvidia::NvCore::Container& nv_core) {
84 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
85
86 auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile()); 86 auto [core, producer, consumer] = CreateBufferQueue(service_context, nv_core.GetNvMapFile());
87 87
88 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer)); 88 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(consumer));
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 8eb8a5155..220292cff 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -11,9 +11,14 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13 13
14namespace Core {
15class System;
16}
17
14namespace Kernel { 18namespace Kernel {
15class KEvent; 19class KEvent;
16} 20class KReadableEvent;
21} // namespace Kernel
17 22
18namespace Service::android { 23namespace Service::android {
19class BufferQueueProducer; 24class BufferQueueProducer;
@@ -24,8 +29,9 @@ class ServiceContext;
24} 29}
25 30
26namespace Service::Nvnflinger { 31namespace Service::Nvnflinger {
32class HardwareComposer;
27class HosBinderDriverServer; 33class HosBinderDriverServer;
28} 34} // namespace Service::Nvnflinger
29 35
30namespace Service::Nvidia::NvCore { 36namespace Service::Nvidia::NvCore {
31class Container; 37class Container;
@@ -118,6 +124,10 @@ public:
118 /// 124 ///
119 const Layer* FindLayer(u64 layer_id) const; 125 const Layer* FindLayer(u64 layer_id) const;
120 126
127 Nvnflinger::HardwareComposer& GetComposer() const {
128 return *hardware_composer;
129 }
130
121private: 131private:
122 u64 display_id; 132 u64 display_id;
123 std::string name; 133 std::string name;
@@ -125,6 +135,7 @@ private:
125 KernelHelpers::ServiceContext& service_context; 135 KernelHelpers::ServiceContext& service_context;
126 136
127 std::vector<std::unique_ptr<Layer>> layers; 137 std::vector<std::unique_ptr<Layer>> layers;
138 std::unique_ptr<Nvnflinger::HardwareComposer> hardware_composer;
128 Kernel::KEvent* vsync_event{}; 139 Kernel::KEvent* vsync_event{};
129 bool is_abandoned{}; 140 bool is_abandoned{};
130}; 141};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 73058db9a..d508ed28c 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -195,8 +195,9 @@ private:
195 void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) { 195 void GetSharedBufferMemoryHandleId(HLERequestContext& ctx) {
196 IPC::RequestParser rp{ctx}; 196 IPC::RequestParser rp{ctx};
197 const u64 buffer_id = rp.PopRaw<u64>(); 197 const u64 buffer_id = rp.PopRaw<u64>();
198 const u64 aruid = ctx.GetPID();
198 199
199 LOG_INFO(Service_VI, "called. buffer_id={:#x}", buffer_id); 200 LOG_INFO(Service_VI, "called. buffer_id={:#x}, aruid={:#x}", buffer_id, aruid);
200 201
201 struct OutputParameters { 202 struct OutputParameters {
202 s32 nvmap_handle; 203 s32 nvmap_handle;
@@ -206,7 +207,7 @@ private:
206 OutputParameters out{}; 207 OutputParameters out{};
207 Nvnflinger::SharedMemoryPoolLayout layout{}; 208 Nvnflinger::SharedMemoryPoolLayout layout{};
208 const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId( 209 const auto result = nvnflinger.GetSystemBufferManager().GetSharedBufferMemoryHandleId(
209 &out.size, &out.nvmap_handle, &layout, buffer_id, 0); 210 &out.size, &out.nvmap_handle, &layout, buffer_id, aruid);
210 211
211 ctx.WriteBuffer(&layout, sizeof(layout)); 212 ctx.WriteBuffer(&layout, sizeof(layout));
212 213