buffer_queue.cpp 6.3 KB

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