buffer_queue.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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/kernel.h"
  9. #include "core/hle/kernel/readable_event.h"
  10. #include "core/hle/kernel/writable_event.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::WritableEvent::CreateEventPair(kernel, "BufferQueue NativeHandle");
  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{queue_mutex};
  23. free_buffers.push_back(slot);
  24. }
  25. 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.writable->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{queue_mutex};
  42. 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{queue_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. queue_sequence.push_back(slot);
  86. }
  87. void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
  88. ASSERT(slot < buffers.size());
  89. ASSERT(buffers[slot].status != Buffer::Status::Free);
  90. ASSERT(buffers[slot].slot == slot);
  91. buffers[slot].status = Buffer::Status::Free;
  92. buffers[slot].multi_fence = multi_fence;
  93. buffers[slot].swap_interval = 0;
  94. {
  95. std::unique_lock lock{queue_mutex};
  96. free_buffers.push_back(slot);
  97. }
  98. condition.notify_one();
  99. buffer_wait_event.writable->Signal();
  100. }
  101. std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
  102. std::size_t buffer_slot = buffers.size();
  103. // Iterate to find a queued buffer matching the requested slot.
  104. while (buffer_slot == buffers.size() && !queue_sequence.empty()) {
  105. const auto slot = static_cast<std::size_t>(queue_sequence.front());
  106. ASSERT(slot < buffers.size());
  107. if (buffers[slot].status == Buffer::Status::Queued) {
  108. ASSERT(buffers[slot].slot == slot);
  109. buffer_slot = slot;
  110. }
  111. queue_sequence.pop_front();
  112. }
  113. if (buffer_slot == buffers.size()) {
  114. return std::nullopt;
  115. }
  116. buffers[buffer_slot].status = Buffer::Status::Acquired;
  117. return {{buffers[buffer_slot]}};
  118. }
  119. void BufferQueue::ReleaseBuffer(u32 slot) {
  120. ASSERT(slot < buffers.size());
  121. ASSERT(buffers[slot].status == Buffer::Status::Acquired);
  122. ASSERT(buffers[slot].slot == slot);
  123. buffers[slot].status = Buffer::Status::Free;
  124. {
  125. std::unique_lock lock{queue_mutex};
  126. free_buffers.push_back(slot);
  127. }
  128. condition.notify_one();
  129. buffer_wait_event.writable->Signal();
  130. }
  131. void BufferQueue::Connect() {
  132. queue_sequence.clear();
  133. is_connect = true;
  134. }
  135. void BufferQueue::Disconnect() {
  136. buffers.fill({});
  137. queue_sequence.clear();
  138. buffer_wait_event.writable->Signal();
  139. is_connect = false;
  140. condition.notify_one();
  141. }
  142. u32 BufferQueue::Query(QueryType type) {
  143. LOG_WARNING(Service, "(STUBBED) called type={}", type);
  144. switch (type) {
  145. case QueryType::NativeWindowFormat:
  146. return static_cast<u32>(PixelFormat::RGBA8888);
  147. }
  148. UNIMPLEMENTED();
  149. return 0;
  150. }
  151. std::shared_ptr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
  152. return buffer_wait_event.writable;
  153. }
  154. std::shared_ptr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
  155. return buffer_wait_event.readable;
  156. }
  157. } // namespace Service::NVFlinger