66#include < Managers/AssetManager.h>
77#include < Windows/GameWindow.h>
88#include < chrono>
9+ #include < new>
910
1011#ifdef __APPLE__
1112#include < mach/mach.h>
@@ -16,17 +17,21 @@ using namespace std::chrono_literals;
1617
1718namespace ZEngine
1819{
19- static std::atomic_bool s_request_terminate = false ;
20- static EngineContextPtr g_engine_ctx = nullptr ;
21- static Applications::GameApplicationPtr g_app = nullptr ;
22- static Applications::AppRenderPipelinePtr g_appRenderPipeline = nullptr ;
23- static std::thread g_render_thread = {};
24-
25- static const uint8_t k_mailbox_buffer_size = 3 ;
26- static std::atomic_int g_write_idx = 0 ;
27- static std::atomic_int g_pending_idx = -1 ;
28- static std::mutex g_mailbox_mut;
29- static std::condition_variable g_mailbox_ready_cv = {};
20+
21+ struct alignas (std::hardware_destructive_interference_size) PaddedAtomicInt
22+ {
23+ std::atomic_uint32_t value;
24+ };
25+
26+ static std::atomic_bool s_request_terminate = false ;
27+ static EngineContextPtr g_engine_ctx = nullptr ;
28+ static Applications::GameApplicationPtr g_app = nullptr ;
29+ static Applications::AppRenderPipelinePtr g_appRenderPipeline = nullptr ;
30+ static std::thread g_render_thread = {};
31+
32+ static PaddedAtomicInt g_head{0 };
33+ static PaddedAtomicInt g_tail{0 };
34+ static constexpr uint8_t k_mailbox_buffer_size = 3 ;
3035 static Applications::RenderPayload g_mailbox_payloads[k_mailbox_buffer_size] = {};
3136
3237 void Engine::Initialize (ZEngine::Core::Memory::ArenaAllocator* arena, Windows::WindowConfigurationPtr window_cfg_ptr, Applications::GameApplicationPtr app)
@@ -73,7 +78,7 @@ namespace ZEngine
7378
7479 void Engine::Dispose ()
7580 {
76- s_request_terminate = false ;
81+ s_request_terminate. store ( false , std::memory_order_release) ;
7782 Managers::AssetManager::Shutdown ();
7883 g_engine_ctx->Device ->Dispose ();
7984
@@ -82,11 +87,7 @@ namespace ZEngine
8287
8388 bool Engine::OnEngineClosed (Event::EngineClosedEvent& event)
8489 {
85- {
86- std::lock_guard l (g_mailbox_mut);
87- s_request_terminate.store (true , std::memory_order_release);
88- g_mailbox_ready_cv.notify_all ();
89- }
90+ s_request_terminate.store (true , std::memory_order_release);
9091 return true ;
9192 }
9293
@@ -125,18 +126,17 @@ namespace ZEngine
125126
126127 g_app->Update (dt);
127128
128- {
129- std::unique_lock l (g_mailbox_mut);
130- g_mailbox_ready_cv.wait (l, [&] { return s_request_terminate.load (std::memory_order_acquire) || g_pending_idx.load (std::memory_order_acquire) == -1 ; });
129+ uint32_t head = g_head.value .load (std::memory_order_relaxed);
131130
132- if (s_request_terminate.load (std::memory_order_acquire))
133- {
134- break ;
135- }
131+ uint32_t next = (head + 1 ) % k_mailbox_buffer_size;
136132
137- int next_payload_idx = g_write_idx. load (std::memory_order_relaxed );
133+ uint32_t tail = g_tail. value . load (std::memory_order_acquire );
138134
139- auto & r_payload = g_mailbox_payloads[next_payload_idx];
135+ // Buffer full, drop frame (non-blocking)
136+ if (next == tail)
137+ continue ;
138+ {
139+ auto & r_payload = g_mailbox_payloads[head];
140140 r_payload.UIOverlay .DrawDataIndex = 0 ;
141141 r_payload.RenderUIOverlay = false ;
142142
@@ -152,10 +152,8 @@ namespace ZEngine
152152
153153 g_app->PrepareScene (r_payload);
154154
155- g_pending_idx.store (next_payload_idx, std::memory_order_release);
156- g_write_idx.store ((g_write_idx + 1 ) % k_mailbox_buffer_size, std::memory_order_relaxed);
155+ g_head.value .store (next, std::memory_order_release);
157156 }
158- g_mailbox_ready_cv.notify_one ();
159157 }
160158 }
161159
@@ -174,23 +172,23 @@ namespace ZEngine
174172#endif
175173 while (true )
176174 {
177- int idx = - 1 ;
175+ if (s_request_terminate. load (std::memory_order_acquire))
178176 {
179- std::unique_lock l (g_mailbox_mut) ;
180- g_mailbox_ready_cv. wait (l, [&] { return s_request_terminate. load (std::memory_order_acquire) || g_pending_idx. load (std::memory_order_acquire) != - 1 ; });
177+ break ;
178+ }
181179
182- if (s_request_terminate.load (std::memory_order_acquire))
183- {
184- break ;
185- }
180+ uint32_t tail = g_tail.value .load (std::memory_order_relaxed);
186181
187- idx = g_pending_idx.load (std::memory_order_acquire);
188- g_pending_idx.store (-1 , std::memory_order_release);
189- }
182+ uint32_t head = g_head.value .load (std::memory_order_acquire);
190183
191- ZENGINE_VALIDATE_ASSERT (idx > -1 , " Invalid payload index" )
184+ // Buffer empty
185+ if (tail == head)
186+ {
187+ std::this_thread::sleep_for (std::chrono::microseconds (50 ));
188+ continue ;
189+ }
192190
193- Applications::RenderPayload& r_payload = g_mailbox_payloads[idx ];
191+ Applications::RenderPayload& r_payload = g_mailbox_payloads[tail ];
194192
195193 auto pipeline = g_app->RenderPipeline ;
196194
@@ -208,7 +206,9 @@ namespace ZEngine
208206 }
209207 pipeline->EndFrame ();
210208
211- g_mailbox_ready_cv.notify_one ();
209+ uint32_t next = (tail + 1 ) % k_mailbox_buffer_size;
210+
211+ g_tail.value .store (next, std::memory_order_release);
212212 }
213213 }
214214
@@ -218,9 +218,6 @@ namespace ZEngine
218218 g_render_thread = std::thread (Engine::RenderThreadRun);
219219 MainThreadRun ();
220220
221- if (s_request_terminate.load (std::memory_order_acquire))
222- {
223- Deinitialize ();
224- }
221+ Deinitialize ();
225222 }
226223} // namespace ZEngine
0 commit comments