diff options
| -rw-r--r-- | src/common/bounded_threadsafe_queue.h | 170 | ||||
| -rw-r--r-- | src/common/logging/backend.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/gpu_thread.cpp | 2 |
3 files changed, 86 insertions, 88 deletions
diff --git a/src/common/bounded_threadsafe_queue.h b/src/common/bounded_threadsafe_queue.h index eb88cc1d1..975215863 100644 --- a/src/common/bounded_threadsafe_queue.h +++ b/src/common/bounded_threadsafe_queue.h | |||
| @@ -23,60 +23,76 @@ class SPSCQueue { | |||
| 23 | 23 | ||
| 24 | public: | 24 | public: |
| 25 | bool TryPush(T&& t) { | 25 | bool TryPush(T&& t) { |
| 26 | const size_t write_index = m_write_index.load(); | 26 | return Push<PushMode::Try>(std::move(t)); |
| 27 | 27 | } | |
| 28 | // Check if we have free slots to write to. | ||
| 29 | if ((write_index - m_read_index.load()) == Capacity) { | ||
| 30 | return false; | ||
| 31 | } | ||
| 32 | |||
| 33 | // Determine the position to write to. | ||
| 34 | const size_t pos = write_index % Capacity; | ||
| 35 | |||
| 36 | // Push into the queue. | ||
| 37 | m_data[pos] = std::move(t); | ||
| 38 | |||
| 39 | // Increment the write index. | ||
| 40 | ++m_write_index; | ||
| 41 | 28 | ||
| 42 | // Notify the consumer that we have pushed into the queue. | 29 | template <typename... Args> |
| 43 | std::scoped_lock lock{cv_mutex}; | 30 | bool TryEmplace(Args&&... args) { |
| 44 | cv.notify_one(); | 31 | return Emplace<PushMode::Try>(std::forward<Args>(args)...); |
| 32 | } | ||
| 45 | 33 | ||
| 46 | return true; | 34 | void PushWait(T&& t) { |
| 35 | Push<PushMode::Wait>(std::move(t)); | ||
| 47 | } | 36 | } |
| 48 | 37 | ||
| 49 | template <typename... Args> | 38 | template <typename... Args> |
| 50 | bool TryPush(Args&&... args) { | 39 | void EmplaceWait(Args&&... args) { |
| 51 | const size_t write_index = m_write_index.load(); | 40 | Emplace<PushMode::Wait>(std::forward<Args>(args)...); |
| 41 | } | ||
| 52 | 42 | ||
| 53 | // Check if we have free slots to write to. | 43 | bool TryPop(T& t) { |
| 54 | if ((write_index - m_read_index.load()) == Capacity) { | 44 | return Pop(t); |
| 55 | return false; | 45 | } |
| 56 | } | ||
| 57 | 46 | ||
| 58 | // Determine the position to write to. | 47 | void PopWait(T& t, std::stop_token stop_token) { |
| 59 | const size_t pos = write_index % Capacity; | 48 | Wait(stop_token); |
| 49 | Pop(t); | ||
| 50 | } | ||
| 60 | 51 | ||
| 61 | // Emplace into the queue. | 52 | T PopWait(std::stop_token stop_token) { |
| 62 | std::construct_at(std::addressof(m_data[pos]), std::forward<Args>(args)...); | 53 | Wait(stop_token); |
| 54 | T t; | ||
| 55 | Pop(t); | ||
| 56 | return t; | ||
| 57 | } | ||
| 63 | 58 | ||
| 64 | // Increment the write index. | 59 | void Clear() { |
| 65 | ++m_write_index; | 60 | while (!Empty()) { |
| 61 | Pop(); | ||
| 62 | } | ||
| 63 | } | ||
| 66 | 64 | ||
| 67 | // Notify the consumer that we have pushed into the queue. | 65 | bool Empty() const { |
| 68 | std::scoped_lock lock{cv_mutex}; | 66 | return m_read_index.load() == m_write_index.load(); |
| 69 | cv.notify_one(); | 67 | } |
| 70 | 68 | ||
| 71 | return true; | 69 | size_t Size() const { |
| 70 | return m_write_index.load() - m_read_index.load(); | ||
| 72 | } | 71 | } |
| 73 | 72 | ||
| 74 | void Push(T&& t) { | 73 | private: |
| 74 | enum class PushMode { | ||
| 75 | Try, | ||
| 76 | Wait, | ||
| 77 | Count, | ||
| 78 | }; | ||
| 79 | |||
| 80 | template <PushMode Mode> | ||
| 81 | bool Push(T&& t) { | ||
| 75 | const size_t write_index = m_write_index.load(); | 82 | const size_t write_index = m_write_index.load(); |
| 76 | 83 | ||
| 77 | // Wait until we have free slots to write to. | 84 | if constexpr (Mode == PushMode::Try) { |
| 78 | while ((write_index - m_read_index.load()) == Capacity) { | 85 | // Check if we have free slots to write to. |
| 79 | std::this_thread::yield(); | 86 | if ((write_index - m_read_index.load()) == Capacity) { |
| 87 | return false; | ||
| 88 | } | ||
| 89 | } else if constexpr (Mode == PushMode::Wait) { | ||
| 90 | // Wait until we have free slots to write to. | ||
| 91 | while ((write_index - m_read_index.load()) == Capacity) { | ||
| 92 | std::this_thread::yield(); | ||
| 93 | } | ||
| 94 | } else { | ||
| 95 | static_assert(Mode < PushMode::Count, "Invalid PushMode."); | ||
| 80 | } | 96 | } |
| 81 | 97 | ||
| 82 | // Determine the position to write to. | 98 | // Determine the position to write to. |
| @@ -91,15 +107,26 @@ public: | |||
| 91 | // Notify the consumer that we have pushed into the queue. | 107 | // Notify the consumer that we have pushed into the queue. |
| 92 | std::scoped_lock lock{cv_mutex}; | 108 | std::scoped_lock lock{cv_mutex}; |
| 93 | cv.notify_one(); | 109 | cv.notify_one(); |
| 110 | |||
| 111 | return true; | ||
| 94 | } | 112 | } |
| 95 | 113 | ||
| 96 | template <typename... Args> | 114 | template <PushMode Mode, typename... Args> |
| 97 | void Push(Args&&... args) { | 115 | bool Emplace(Args&&... args) { |
| 98 | const size_t write_index = m_write_index.load(); | 116 | const size_t write_index = m_write_index.load(); |
| 99 | 117 | ||
| 100 | // Wait until we have free slots to write to. | 118 | if constexpr (Mode == PushMode::Try) { |
| 101 | while ((write_index - m_read_index.load()) == Capacity) { | 119 | // Check if we have free slots to write to. |
| 102 | std::this_thread::yield(); | 120 | if ((write_index - m_read_index.load()) == Capacity) { |
| 121 | return false; | ||
| 122 | } | ||
| 123 | } else if constexpr (Mode == PushMode::Wait) { | ||
| 124 | // Wait until we have free slots to write to. | ||
| 125 | while ((write_index - m_read_index.load()) == Capacity) { | ||
| 126 | std::this_thread::yield(); | ||
| 127 | } | ||
| 128 | } else { | ||
| 129 | static_assert(Mode < PushMode::Count, "Invalid PushMode."); | ||
| 103 | } | 130 | } |
| 104 | 131 | ||
| 105 | // Determine the position to write to. | 132 | // Determine the position to write to. |
| @@ -114,39 +141,10 @@ public: | |||
| 114 | // Notify the consumer that we have pushed into the queue. | 141 | // Notify the consumer that we have pushed into the queue. |
| 115 | std::scoped_lock lock{cv_mutex}; | 142 | std::scoped_lock lock{cv_mutex}; |
| 116 | cv.notify_one(); | 143 | cv.notify_one(); |
| 117 | } | ||
| 118 | |||
| 119 | bool TryPop(T& t) { | ||
| 120 | return Pop(t); | ||
| 121 | } | ||
| 122 | |||
| 123 | void PopWait(T& t, std::stop_token stop_token) { | ||
| 124 | Wait(stop_token); | ||
| 125 | Pop(t); | ||
| 126 | } | ||
| 127 | |||
| 128 | T PopWait(std::stop_token stop_token) { | ||
| 129 | Wait(stop_token); | ||
| 130 | T t; | ||
| 131 | Pop(t); | ||
| 132 | return t; | ||
| 133 | } | ||
| 134 | 144 | ||
| 135 | void Clear() { | 145 | return true; |
| 136 | while (!Empty()) { | ||
| 137 | Pop(); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | bool Empty() const { | ||
| 142 | return m_read_index.load() == m_write_index.load(); | ||
| 143 | } | ||
| 144 | |||
| 145 | size_t Size() const { | ||
| 146 | return m_write_index.load() - m_read_index.load(); | ||
| 147 | } | 146 | } |
| 148 | 147 | ||
| 149 | private: | ||
| 150 | void Pop() { | 148 | void Pop() { |
| 151 | const size_t read_index = m_read_index.load(); | 149 | const size_t read_index = m_read_index.load(); |
| 152 | 150 | ||
| @@ -208,20 +206,20 @@ public: | |||
| 208 | } | 206 | } |
| 209 | 207 | ||
| 210 | template <typename... Args> | 208 | template <typename... Args> |
| 211 | bool TryPush(Args&&... args) { | 209 | bool TryEmplace(Args&&... args) { |
| 212 | std::scoped_lock lock{write_mutex}; | 210 | std::scoped_lock lock{write_mutex}; |
| 213 | return spsc_queue.TryPush(std::forward<Args>(args)...); | 211 | return spsc_queue.TryEmplace(std::forward<Args>(args)...); |
| 214 | } | 212 | } |
| 215 | 213 | ||
| 216 | void Push(T&& t) { | 214 | void PushWait(T&& t) { |
| 217 | std::scoped_lock lock{write_mutex}; | 215 | std::scoped_lock lock{write_mutex}; |
| 218 | spsc_queue.Push(std::move(t)); | 216 | spsc_queue.PushWait(std::move(t)); |
| 219 | } | 217 | } |
| 220 | 218 | ||
| 221 | template <typename... Args> | 219 | template <typename... Args> |
| 222 | void Push(Args&&... args) { | 220 | void EmplaceWait(Args&&... args) { |
| 223 | std::scoped_lock lock{write_mutex}; | 221 | std::scoped_lock lock{write_mutex}; |
| 224 | spsc_queue.Push(std::forward<Args>(args)...); | 222 | spsc_queue.EmplaceWait(std::forward<Args>(args)...); |
| 225 | } | 223 | } |
| 226 | 224 | ||
| 227 | bool TryPop(T& t) { | 225 | bool TryPop(T& t) { |
| @@ -262,20 +260,20 @@ public: | |||
| 262 | } | 260 | } |
| 263 | 261 | ||
| 264 | template <typename... Args> | 262 | template <typename... Args> |
| 265 | bool TryPush(Args&&... args) { | 263 | bool TryEmplace(Args&&... args) { |
| 266 | std::scoped_lock lock{write_mutex}; | 264 | std::scoped_lock lock{write_mutex}; |
| 267 | return spsc_queue.TryPush(std::forward<Args>(args)...); | 265 | return spsc_queue.TryEmplace(std::forward<Args>(args)...); |
| 268 | } | 266 | } |
| 269 | 267 | ||
| 270 | void Push(T&& t) { | 268 | void PushWait(T&& t) { |
| 271 | std::scoped_lock lock{write_mutex}; | 269 | std::scoped_lock lock{write_mutex}; |
| 272 | spsc_queue.Push(std::move(t)); | 270 | spsc_queue.PushWait(std::move(t)); |
| 273 | } | 271 | } |
| 274 | 272 | ||
| 275 | template <typename... Args> | 273 | template <typename... Args> |
| 276 | void Push(Args&&... args) { | 274 | void EmplaceWait(Args&&... args) { |
| 277 | std::scoped_lock lock{write_mutex}; | 275 | std::scoped_lock lock{write_mutex}; |
| 278 | spsc_queue.Push(std::forward<Args>(args)...); | 276 | spsc_queue.EmplaceWait(std::forward<Args>(args)...); |
| 279 | } | 277 | } |
| 280 | 278 | ||
| 281 | bool TryPop(T& t) { | 279 | bool TryPop(T& t) { |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index e1ce9db99..f96c7c222 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -207,7 +207,7 @@ public: | |||
| 207 | if (!filter.CheckMessage(log_class, log_level)) { | 207 | if (!filter.CheckMessage(log_class, log_level)) { |
| 208 | return; | 208 | return; |
| 209 | } | 209 | } |
| 210 | message_queue.Push( | 210 | message_queue.EmplaceWait( |
| 211 | CreateEntry(log_class, log_level, filename, line_num, function, std::move(message))); | 211 | CreateEntry(log_class, log_level, filename, line_num, function, std::move(message))); |
| 212 | } | 212 | } |
| 213 | 213 | ||
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 469a59cf9..3c5317777 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -118,7 +118,7 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) { | |||
| 118 | 118 | ||
| 119 | std::unique_lock lk(state.write_lock); | 119 | std::unique_lock lk(state.write_lock); |
| 120 | const u64 fence{++state.last_fence}; | 120 | const u64 fence{++state.last_fence}; |
| 121 | state.queue.Push(std::move(command_data), fence, block); | 121 | state.queue.EmplaceWait(std::move(command_data), fence, block); |
| 122 | 122 | ||
| 123 | if (block) { | 123 | if (block) { |
| 124 | Common::CondvarWait(state.cv, lk, thread.get_stop_token(), [this, fence] { | 124 | Common::CondvarWait(state.cv, lk, thread.get_stop_token(), [this, fence] { |