hardware_composer.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-3.0-or-later
  3. #include <boost/container/small_vector.hpp>
  4. #include "common/microprofile.h"
  5. #include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
  6. #include "core/hle/service/nvnflinger/buffer_item.h"
  7. #include "core/hle/service/nvnflinger/buffer_item_consumer.h"
  8. #include "core/hle/service/nvnflinger/buffer_queue_producer.h"
  9. #include "core/hle/service/nvnflinger/hardware_composer.h"
  10. #include "core/hle/service/nvnflinger/hwc_layer.h"
  11. #include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
  12. #include "core/hle/service/vi/display/vi_display.h"
  13. #include "core/hle/service/vi/layer/vi_layer.h"
  14. namespace Service::Nvnflinger {
  15. namespace {
  16. s32 NormalizeSwapInterval(f32* out_speed_scale, s32 swap_interval) {
  17. if (swap_interval <= 0) {
  18. // As an extension, treat nonpositive swap interval as speed multiplier.
  19. if (out_speed_scale) {
  20. *out_speed_scale = 2.f * static_cast<f32>(1 - swap_interval);
  21. }
  22. swap_interval = 1;
  23. }
  24. if (swap_interval >= 5) {
  25. // As an extension, treat high swap interval as precise speed control.
  26. if (out_speed_scale) {
  27. *out_speed_scale = static_cast<f32>(swap_interval) / 100.f;
  28. }
  29. swap_interval = 1;
  30. }
  31. return swap_interval;
  32. }
  33. } // namespace
  34. HardwareComposer::HardwareComposer() = default;
  35. HardwareComposer::~HardwareComposer() = default;
  36. u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
  37. Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) {
  38. boost::container::small_vector<HwcLayer, 2> composition_stack;
  39. m_frame_number += frame_advance;
  40. // Release any necessary framebuffers.
  41. for (auto& [layer_id, framebuffer] : m_framebuffers) {
  42. if (framebuffer.release_frame_number > m_frame_number) {
  43. // Not yet ready to release this framebuffer.
  44. continue;
  45. }
  46. if (!framebuffer.is_acquired) {
  47. // Already released.
  48. continue;
  49. }
  50. if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
  51. // TODO: support release fence
  52. // This is needed to prevent screen tearing
  53. layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
  54. framebuffer.is_acquired = false;
  55. }
  56. }
  57. // Set default speed limit to 100%.
  58. *out_speed_scale = 1.0f;
  59. // Determine the number of vsync periods to wait before composing again.
  60. std::optional<s32> swap_interval{};
  61. bool has_acquired_buffer{};
  62. // Acquire all necessary framebuffers.
  63. for (size_t i = 0; i < display.GetNumLayers(); i++) {
  64. auto& layer = display.GetLayer(i);
  65. auto layer_id = layer.GetLayerId();
  66. // Try to fetch the framebuffer (either new or stale).
  67. const auto result = this->CacheFramebufferLocked(layer, layer_id);
  68. // If we failed, skip this layer.
  69. if (result == CacheStatus::NoBufferAvailable) {
  70. continue;
  71. }
  72. // If we acquired a new buffer, we need to present.
  73. if (result == CacheStatus::BufferAcquired) {
  74. has_acquired_buffer = true;
  75. }
  76. const auto& buffer = m_framebuffers[layer_id];
  77. const auto& item = buffer.item;
  78. const auto& igbp_buffer = *item.graphic_buffer;
  79. // TODO: get proper Z-index from layer
  80. composition_stack.emplace_back(HwcLayer{
  81. .buffer_handle = igbp_buffer.BufferId(),
  82. .offset = igbp_buffer.Offset(),
  83. .format = igbp_buffer.ExternalFormat(),
  84. .width = igbp_buffer.Width(),
  85. .height = igbp_buffer.Height(),
  86. .stride = igbp_buffer.Stride(),
  87. .z_index = 0,
  88. .transform = static_cast<android::BufferTransformFlags>(item.transform),
  89. .crop_rect = item.crop,
  90. .acquire_fence = item.fence,
  91. });
  92. // We need to compose again either before this frame is supposed to
  93. // be released, or exactly on the vsync period it should be released.
  94. const s32 item_swap_interval = NormalizeSwapInterval(out_speed_scale, item.swap_interval);
  95. // TODO: handle cases where swap intervals are relatively prime. So far,
  96. // only swap intervals of 0, 1 and 2 have been observed, but if 3 were
  97. // to be introduced, this would cause an issue.
  98. if (swap_interval) {
  99. swap_interval = std::min(*swap_interval, item_swap_interval);
  100. } else {
  101. swap_interval = item_swap_interval;
  102. }
  103. }
  104. // If any new buffers were acquired, we can present.
  105. if (has_acquired_buffer) {
  106. // Sort by Z-index.
  107. std::stable_sort(composition_stack.begin(), composition_stack.end(),
  108. [&](auto& l, auto& r) { return l.z_index < r.z_index; });
  109. // Composite.
  110. nvdisp.Composite(composition_stack);
  111. }
  112. // Render MicroProfile.
  113. MicroProfileFlip();
  114. // Advance by at least one frame.
  115. return swap_interval.value_or(1);
  116. }
  117. void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
  118. // Check if we are tracking a slot with this layer_id.
  119. const auto it = m_framebuffers.find(layer_id);
  120. if (it == m_framebuffers.end()) {
  121. return;
  122. }
  123. // Try to release the buffer item.
  124. auto* const layer = display.FindLayer(layer_id);
  125. if (layer && it->second.is_acquired) {
  126. layer->GetConsumer().ReleaseBuffer(it->second.item, android::Fence::NoFence());
  127. }
  128. // Erase the slot.
  129. m_framebuffers.erase(it);
  130. }
  131. bool HardwareComposer::TryAcquireFramebufferLocked(VI::Layer& layer, Framebuffer& framebuffer) {
  132. // Attempt the update.
  133. const auto status = layer.GetConsumer().AcquireBuffer(&framebuffer.item, {}, false);
  134. if (status != android::Status::NoError) {
  135. return false;
  136. }
  137. // We succeeded, so set the new release frame info.
  138. framebuffer.release_frame_number =
  139. NormalizeSwapInterval(nullptr, framebuffer.item.swap_interval);
  140. framebuffer.is_acquired = true;
  141. return true;
  142. }
  143. HardwareComposer::CacheStatus HardwareComposer::CacheFramebufferLocked(VI::Layer& layer,
  144. LayerId layer_id) {
  145. // Check if this framebuffer is already present.
  146. const auto it = m_framebuffers.find(layer_id);
  147. if (it != m_framebuffers.end()) {
  148. // If it's currently still acquired, we are done.
  149. if (it->second.is_acquired) {
  150. return CacheStatus::CachedBufferReused;
  151. }
  152. // Try to acquire a new item.
  153. if (this->TryAcquireFramebufferLocked(layer, it->second)) {
  154. // We got a new item.
  155. return CacheStatus::BufferAcquired;
  156. } else {
  157. // We didn't acquire a new item, but we can reuse the slot.
  158. return CacheStatus::CachedBufferReused;
  159. }
  160. }
  161. // Framebuffer is not present, so try to create it.
  162. Framebuffer framebuffer{};
  163. if (this->TryAcquireFramebufferLocked(layer, framebuffer)) {
  164. // Move the buffer item into a new slot.
  165. m_framebuffers.emplace(layer_id, std::move(framebuffer));
  166. // We succeeded.
  167. return CacheStatus::BufferAcquired;
  168. }
  169. // We couldn't acquire the buffer item, so don't create a slot.
  170. return CacheStatus::NoBufferAvailable;
  171. }
  172. } // namespace Service::Nvnflinger