buffer_queue.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. LOG_WARNING(Service, "Adding graphics buffer {}", slot);
  20. free_buffers.push_back(slot);
  21. queue.push_back({
  22. .slot = slot,
  23. .status = Buffer::Status::Free,
  24. .igbp_buffer = igbp_buffer,
  25. .transform = {},
  26. .crop_rect = {},
  27. .swap_interval = 0,
  28. .multi_fence = {},
  29. });
  30. buffer_wait_event.writable->Signal();
  31. }
  32. std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
  33. u32 height) {
  34. if (free_buffers.empty()) {
  35. return std::nullopt;
  36. }
  37. auto f_itr = free_buffers.begin();
  38. auto itr = queue.end();
  39. while (f_itr != free_buffers.end()) {
  40. auto slot = *f_itr;
  41. itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
  42. // Only consider free buffers. Buffers become free once again after they've been
  43. // Acquired and Released by the compositor, see the NVFlinger::Compose method.
  44. if (buffer.status != Buffer::Status::Free) {
  45. return false;
  46. }
  47. if (buffer.slot != slot) {
  48. return false;
  49. }
  50. // Make sure that the parameters match.
  51. return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height;
  52. });
  53. if (itr != queue.end()) {
  54. free_buffers.erase(f_itr);
  55. break;
  56. }
  57. ++f_itr;
  58. }
  59. if (itr == queue.end()) {
  60. return std::nullopt;
  61. }
  62. itr->status = Buffer::Status::Dequeued;
  63. return {{itr->slot, &itr->multi_fence}};
  64. }
  65. const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
  66. auto itr = std::find_if(queue.begin(), queue.end(),
  67. [&](const Buffer& buffer) { return buffer.slot == slot; });
  68. ASSERT(itr != queue.end());
  69. ASSERT(itr->status == Buffer::Status::Dequeued);
  70. return itr->igbp_buffer;
  71. }
  72. void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
  73. const Common::Rectangle<int>& crop_rect, u32 swap_interval,
  74. Service::Nvidia::MultiFence& multi_fence) {
  75. auto itr = std::find_if(queue.begin(), queue.end(),
  76. [&](const Buffer& buffer) { return buffer.slot == slot; });
  77. ASSERT(itr != queue.end());
  78. ASSERT(itr->status == Buffer::Status::Dequeued);
  79. itr->status = Buffer::Status::Queued;
  80. itr->transform = transform;
  81. itr->crop_rect = crop_rect;
  82. itr->swap_interval = swap_interval;
  83. itr->multi_fence = multi_fence;
  84. queue_sequence.push_back(slot);
  85. }
  86. void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
  87. const auto itr = std::find_if(queue.begin(), queue.end(),
  88. [slot](const Buffer& buffer) { return buffer.slot == slot; });
  89. ASSERT(itr != queue.end());
  90. ASSERT(itr->status != Buffer::Status::Free);
  91. itr->status = Buffer::Status::Free;
  92. itr->multi_fence = multi_fence;
  93. itr->swap_interval = 0;
  94. free_buffers.push_back(slot);
  95. buffer_wait_event.writable->Signal();
  96. }
  97. std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
  98. auto itr = queue.end();
  99. // Iterate to find a queued buffer matching the requested slot.
  100. while (itr == queue.end() && !queue_sequence.empty()) {
  101. const u32 slot = queue_sequence.front();
  102. itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) {
  103. return buffer.status == Buffer::Status::Queued && buffer.slot == slot;
  104. });
  105. queue_sequence.pop_front();
  106. }
  107. if (itr == queue.end()) {
  108. return std::nullopt;
  109. }
  110. itr->status = Buffer::Status::Acquired;
  111. return *itr;
  112. }
  113. void BufferQueue::ReleaseBuffer(u32 slot) {
  114. auto itr = std::find_if(queue.begin(), queue.end(),
  115. [&](const Buffer& buffer) { return buffer.slot == slot; });
  116. ASSERT(itr != queue.end());
  117. ASSERT(itr->status == Buffer::Status::Acquired);
  118. itr->status = Buffer::Status::Free;
  119. free_buffers.push_back(slot);
  120. buffer_wait_event.writable->Signal();
  121. }
  122. void BufferQueue::Disconnect() {
  123. queue.clear();
  124. queue_sequence.clear();
  125. id = 1;
  126. layer_id = 1;
  127. }
  128. u32 BufferQueue::Query(QueryType type) {
  129. LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type));
  130. switch (type) {
  131. case QueryType::NativeWindowFormat:
  132. return static_cast<u32>(PixelFormat::RGBA8888);
  133. }
  134. UNIMPLEMENTED();
  135. return 0;
  136. }
  137. std::shared_ptr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
  138. return buffer_wait_event.writable;
  139. }
  140. std::shared_ptr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
  141. return buffer_wait_event.readable;
  142. }
  143. } // namespace Service::NVFlinger