buffer_queue.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include "common/assert.h"
  6. #include "common/logging/log.h"
  7. #include "core/core.h"
  8. #include "core/hle/kernel/k_writable_event.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/service/nvflinger/buffer_queue.h"
  11. namespace Service::NVFlinger {
  12. BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_)
  13. : id(id_), layer_id(layer_id_), buffer_wait_event{kernel} {
  14. Kernel::KAutoObject::Create(std::addressof(buffer_wait_event));
  15. buffer_wait_event.Initialize("BufferQueue:WaitEvent");
  16. }
  17. BufferQueue::~BufferQueue() = default;
  18. void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
  19. ASSERT(slot < buffer_slots);
  20. LOG_WARNING(Service, "Adding graphics buffer {}", slot);
  21. {
  22. std::unique_lock lock{free_buffers_mutex};
  23. free_buffers.push_back(slot);
  24. }
  25. free_buffers_condition.notify_one();
  26. buffers[slot] = {
  27. .slot = slot,
  28. .status = Buffer::Status::Free,
  29. .igbp_buffer = igbp_buffer,
  30. .transform = {},
  31. .crop_rect = {},
  32. .swap_interval = 0,
  33. .multi_fence = {},
  34. };
  35. buffer_wait_event.GetWritableEvent().Signal();
  36. }
  37. std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
  38. u32 height) {
  39. // Wait for first request before trying to dequeue
  40. {
  41. std::unique_lock lock{free_buffers_mutex};
  42. free_buffers_condition.wait(lock, [this] { return !free_buffers.empty() || !is_connect; });
  43. }
  44. if (!is_connect) {
  45. // Buffer was disconnected while the thread was blocked, this is most likely due to
  46. // emulation being stopped
  47. return std::nullopt;
  48. }
  49. std::unique_lock lock{free_buffers_mutex};
  50. auto f_itr = free_buffers.begin();
  51. auto slot = buffers.size();
  52. while (f_itr != free_buffers.end()) {
  53. const Buffer& buffer = buffers[*f_itr];
  54. if (buffer.status == Buffer::Status::Free && buffer.igbp_buffer.width == width &&
  55. buffer.igbp_buffer.height == height) {
  56. slot = *f_itr;
  57. free_buffers.erase(f_itr);
  58. break;
  59. }
  60. ++f_itr;
  61. }
  62. if (slot == buffers.size()) {
  63. return std::nullopt;
  64. }
  65. buffers[slot].status = Buffer::Status::Dequeued;
  66. return {{buffers[slot].slot, &buffers[slot].multi_fence}};
  67. }
  68. const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
  69. ASSERT(slot < buffers.size());
  70. ASSERT(buffers[slot].status == Buffer::Status::Dequeued);
  71. ASSERT(buffers[slot].slot == slot);
  72. return buffers[slot].igbp_buffer;
  73. }
  74. void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
  75. const Common::Rectangle<int>& crop_rect, u32 swap_interval,
  76. Service::Nvidia::MultiFence& multi_fence) {
  77. ASSERT(slot < buffers.size());
  78. ASSERT(buffers[slot].status == Buffer::Status::Dequeued);
  79. ASSERT(buffers[slot].slot == slot);
  80. buffers[slot].status = Buffer::Status::Queued;
  81. buffers[slot].transform = transform;
  82. buffers[slot].crop_rect = crop_rect;
  83. buffers[slot].swap_interval = swap_interval;
  84. buffers[slot].multi_fence = multi_fence;
  85. std::unique_lock lock{queue_sequence_mutex};
  86. queue_sequence.push_back(slot);
  87. }
  88. void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
  89. ASSERT(slot < buffers.size());
  90. ASSERT(buffers[slot].status != Buffer::Status::Free);
  91. ASSERT(buffers[slot].slot == slot);
  92. buffers[slot].status = Buffer::Status::Free;
  93. buffers[slot].multi_fence = multi_fence;
  94. buffers[slot].swap_interval = 0;
  95. {
  96. std::unique_lock lock{free_buffers_mutex};
  97. free_buffers.push_back(slot);
  98. }
  99. free_buffers_condition.notify_one();
  100. buffer_wait_event.GetWritableEvent().Signal();
  101. }
  102. std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
  103. std::unique_lock lock{queue_sequence_mutex};
  104. std::size_t buffer_slot = buffers.size();
  105. // Iterate to find a queued buffer matching the requested slot.
  106. while (buffer_slot == buffers.size() && !queue_sequence.empty()) {
  107. const auto slot = static_cast<std::size_t>(queue_sequence.front());
  108. ASSERT(slot < buffers.size());
  109. if (buffers[slot].status == Buffer::Status::Queued) {
  110. ASSERT(buffers[slot].slot == slot);
  111. buffer_slot = slot;
  112. }
  113. queue_sequence.pop_front();
  114. }
  115. if (buffer_slot == buffers.size()) {
  116. return std::nullopt;
  117. }
  118. buffers[buffer_slot].status = Buffer::Status::Acquired;
  119. return {{buffers[buffer_slot]}};
  120. }
  121. void BufferQueue::ReleaseBuffer(u32 slot) {
  122. ASSERT(slot < buffers.size());
  123. ASSERT(buffers[slot].status == Buffer::Status::Acquired);
  124. ASSERT(buffers[slot].slot == slot);
  125. buffers[slot].status = Buffer::Status::Free;
  126. {
  127. std::unique_lock lock{free_buffers_mutex};
  128. free_buffers.push_back(slot);
  129. }
  130. free_buffers_condition.notify_one();
  131. buffer_wait_event.GetWritableEvent().Signal();
  132. }
  133. void BufferQueue::Connect() {
  134. std::unique_lock lock{queue_sequence_mutex};
  135. queue_sequence.clear();
  136. is_connect = true;
  137. }
  138. void BufferQueue::Disconnect() {
  139. buffers.fill({});
  140. {
  141. std::unique_lock lock{queue_sequence_mutex};
  142. queue_sequence.clear();
  143. }
  144. buffer_wait_event.GetWritableEvent().Signal();
  145. is_connect = false;
  146. free_buffers_condition.notify_one();
  147. }
  148. u32 BufferQueue::Query(QueryType type) {
  149. LOG_WARNING(Service, "(STUBBED) called type={}", type);
  150. switch (type) {
  151. case QueryType::NativeWindowFormat:
  152. return static_cast<u32>(PixelFormat::RGBA8888);
  153. case QueryType::NativeWindowWidth:
  154. case QueryType::NativeWindowHeight:
  155. break;
  156. }
  157. UNIMPLEMENTED_MSG("Unimplemented query type={}", type);
  158. return 0;
  159. }
  160. Kernel::KWritableEvent& BufferQueue::GetWritableBufferWaitEvent() {
  161. return buffer_wait_event.GetWritableEvent();
  162. }
  163. Kernel::KReadableEvent& BufferQueue::GetBufferWaitEvent() {
  164. return buffer_wait_event.GetReadableEvent();
  165. }
  166. } // namespace Service::NVFlinger