diff options
| author | 2021-01-04 01:36:41 -0500 | |
|---|---|---|
| committer | 2021-01-04 01:36:41 -0500 | |
| commit | 6b354ccaee6988b91a97b1b70b4d84bd4d244cb1 (patch) | |
| tree | 5ea690f449513946d02d4777806e2abc497fe9d1 /src | |
| parent | Merge pull request #5286 from ReinUsesLisp/rename-vk-device (diff) | |
| download | yuzu-6b354ccaee6988b91a97b1b70b4d84bd4d244cb1.tar.gz yuzu-6b354ccaee6988b91a97b1b70b4d84bd4d244cb1.tar.xz yuzu-6b354ccaee6988b91a97b1b70b4d84bd4d244cb1.zip | |
buffer_queue: Protect queue_sequence list access with a mutex
fixes a data race as this is an unprotected variable manipulated by multiple threads
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.cpp | 28 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.h | 6 |
2 files changed, 21 insertions, 13 deletions
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 0e6bde9f5..c68905e19 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -26,10 +26,10 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) | |||
| 26 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); | 26 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); |
| 27 | 27 | ||
| 28 | { | 28 | { |
| 29 | std::unique_lock lock{queue_mutex}; | 29 | std::unique_lock lock{free_buffers_mutex}; |
| 30 | free_buffers.push_back(slot); | 30 | free_buffers.push_back(slot); |
| 31 | } | 31 | } |
| 32 | condition.notify_one(); | 32 | free_buffers_condition.notify_one(); |
| 33 | 33 | ||
| 34 | buffers[slot] = { | 34 | buffers[slot] = { |
| 35 | .slot = slot, | 35 | .slot = slot, |
| @@ -48,8 +48,8 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue | |||
| 48 | u32 height) { | 48 | u32 height) { |
| 49 | // Wait for first request before trying to dequeue | 49 | // Wait for first request before trying to dequeue |
| 50 | { | 50 | { |
| 51 | std::unique_lock lock{queue_mutex}; | 51 | std::unique_lock lock{free_buffers_mutex}; |
| 52 | condition.wait(lock, [this] { return !free_buffers.empty() || !is_connect; }); | 52 | free_buffers_condition.wait(lock, [this] { return !free_buffers.empty() || !is_connect; }); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | if (!is_connect) { | 55 | if (!is_connect) { |
| @@ -58,7 +58,7 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue | |||
| 58 | return std::nullopt; | 58 | return std::nullopt; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | std::unique_lock lock{queue_mutex}; | 61 | std::unique_lock lock{free_buffers_mutex}; |
| 62 | 62 | ||
| 63 | auto f_itr = free_buffers.begin(); | 63 | auto f_itr = free_buffers.begin(); |
| 64 | auto slot = buffers.size(); | 64 | auto slot = buffers.size(); |
| @@ -100,6 +100,7 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, | |||
| 100 | buffers[slot].crop_rect = crop_rect; | 100 | buffers[slot].crop_rect = crop_rect; |
| 101 | buffers[slot].swap_interval = swap_interval; | 101 | buffers[slot].swap_interval = swap_interval; |
| 102 | buffers[slot].multi_fence = multi_fence; | 102 | buffers[slot].multi_fence = multi_fence; |
| 103 | std::unique_lock lock{queue_sequence_mutex}; | ||
| 103 | queue_sequence.push_back(slot); | 104 | queue_sequence.push_back(slot); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| @@ -113,15 +114,16 @@ void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& mult | |||
| 113 | buffers[slot].swap_interval = 0; | 114 | buffers[slot].swap_interval = 0; |
| 114 | 115 | ||
| 115 | { | 116 | { |
| 116 | std::unique_lock lock{queue_mutex}; | 117 | std::unique_lock lock{free_buffers_mutex}; |
| 117 | free_buffers.push_back(slot); | 118 | free_buffers.push_back(slot); |
| 118 | } | 119 | } |
| 119 | condition.notify_one(); | 120 | free_buffers_condition.notify_one(); |
| 120 | 121 | ||
| 121 | buffer_wait_event.writable->Signal(); | 122 | buffer_wait_event.writable->Signal(); |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { | 125 | std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { |
| 126 | std::unique_lock lock{queue_sequence_mutex}; | ||
| 125 | std::size_t buffer_slot = buffers.size(); | 127 | std::size_t buffer_slot = buffers.size(); |
| 126 | // Iterate to find a queued buffer matching the requested slot. | 128 | // Iterate to find a queued buffer matching the requested slot. |
| 127 | while (buffer_slot == buffers.size() && !queue_sequence.empty()) { | 129 | while (buffer_slot == buffers.size() && !queue_sequence.empty()) { |
| @@ -147,25 +149,29 @@ void BufferQueue::ReleaseBuffer(u32 slot) { | |||
| 147 | 149 | ||
| 148 | buffers[slot].status = Buffer::Status::Free; | 150 | buffers[slot].status = Buffer::Status::Free; |
| 149 | { | 151 | { |
| 150 | std::unique_lock lock{queue_mutex}; | 152 | std::unique_lock lock{free_buffers_mutex}; |
| 151 | free_buffers.push_back(slot); | 153 | free_buffers.push_back(slot); |
| 152 | } | 154 | } |
| 153 | condition.notify_one(); | 155 | free_buffers_condition.notify_one(); |
| 154 | 156 | ||
| 155 | buffer_wait_event.writable->Signal(); | 157 | buffer_wait_event.writable->Signal(); |
| 156 | } | 158 | } |
| 157 | 159 | ||
| 158 | void BufferQueue::Connect() { | 160 | void BufferQueue::Connect() { |
| 161 | std::unique_lock lock{queue_sequence_mutex}; | ||
| 159 | queue_sequence.clear(); | 162 | queue_sequence.clear(); |
| 160 | is_connect = true; | 163 | is_connect = true; |
| 161 | } | 164 | } |
| 162 | 165 | ||
| 163 | void BufferQueue::Disconnect() { | 166 | void BufferQueue::Disconnect() { |
| 164 | buffers.fill({}); | 167 | buffers.fill({}); |
| 165 | queue_sequence.clear(); | 168 | { |
| 169 | std::unique_lock lock{queue_sequence_mutex}; | ||
| 170 | queue_sequence.clear(); | ||
| 171 | } | ||
| 166 | buffer_wait_event.writable->Signal(); | 172 | buffer_wait_event.writable->Signal(); |
| 167 | is_connect = false; | 173 | is_connect = false; |
| 168 | condition.notify_one(); | 174 | free_buffers_condition.notify_one(); |
| 169 | } | 175 | } |
| 170 | 176 | ||
| 171 | u32 BufferQueue::Query(QueryType type) { | 177 | u32 BufferQueue::Query(QueryType type) { |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index a2f60d9eb..ad7469277 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -129,8 +129,10 @@ private: | |||
| 129 | std::list<u32> queue_sequence; | 129 | std::list<u32> queue_sequence; |
| 130 | Kernel::EventPair buffer_wait_event; | 130 | Kernel::EventPair buffer_wait_event; |
| 131 | 131 | ||
| 132 | std::mutex queue_mutex; | 132 | std::mutex free_buffers_mutex; |
| 133 | std::condition_variable condition; | 133 | std::condition_variable free_buffers_condition; |
| 134 | |||
| 135 | std::mutex queue_sequence_mutex; | ||
| 134 | }; | 136 | }; |
| 135 | 137 | ||
| 136 | } // namespace Service::NVFlinger | 138 | } // namespace Service::NVFlinger |