Loading...
Searching...
No Matches
TripleBufferIndex.hpp
Go to the documentation of this file.
1#pragma once
2
16#include <atomic>
17#include <cstdint>
18
19namespace score::gfx
20{
21
23{
24public:
26 {
27 m_state.store(makeState(0, 1, 2, false, false), std::memory_order_relaxed);
28 }
29
30 // Called by producer when starting a new frame
31 int acquireWriteIndex() noexcept
32 {
33 uint32_t state = m_state.load(std::memory_order_acquire);
34 return writeIndex(state);
35 }
36
37 // Called by producer when frame is complete - swaps write and ready
38 void publishWriteIndex() noexcept
39 {
40 uint32_t oldState, newState;
41 do
42 {
43 oldState = m_state.load(std::memory_order_acquire);
44 int w = writeIndex(oldState);
45 int r = readyIndex(oldState);
46 int rd = readIndex(oldState);
47 newState = makeState(r, w, rd, true, true);
48 } while(!m_state.compare_exchange_weak(
49 oldState, newState, std::memory_order_release, std::memory_order_relaxed));
50 }
51
52 // Called by consumer to get latest frame - swaps ready and read if new frame available
53 // Returns the read index, or -1 if no new frame
54 int acquireReadIndex() noexcept
55 {
56 uint32_t oldState, newState;
57 do
58 {
59 oldState = m_state.load(std::memory_order_acquire);
60 if(!hasNewFrame(oldState))
61 // No new frame: keep showing the last one the consumer read — but
62 // only if a frame was EVER published. Before the first publish the
63 // read slot is still its initial value (2), a slot created with
64 // QRhi::create() and never rendered into, so returning it would hand
65 // the consumer undefined texture contents. The documented contract
66 // ("the most recently completed texture, or nullptr if none ready")
67 // requires -1 here.
68 return everReady(oldState) ? readIndex(oldState) : -1;
69
70 int w = writeIndex(oldState);
71 int r = readyIndex(oldState);
72 int rd = readIndex(oldState);
73 newState = makeState(w, rd, r, false, true);
74 } while(!m_state.compare_exchange_weak(
75 oldState, newState, std::memory_order_release, std::memory_order_relaxed));
76
77 return readyIndex(oldState); // Return the old ready (now read) index
78 }
79
80 bool hasNewFrameAvailable() const noexcept
81 {
82 return hasNewFrame(m_state.load(std::memory_order_acquire));
83 }
84
85private:
86 // State packing: [everReady:1][write:2][ready:2][read:2][hasNew:1] in the
87 // lowest 8 bits. everReady latches true on the first publish and gates the
88 // "keep the last frame" fallback in acquireReadIndex against the initial,
89 // never-written read slot.
90 static constexpr uint32_t
91 makeState(int w, int r, int rd, bool hasNew, bool ever) noexcept
92 {
93 return (uint32_t(ever) << 7) | (uint32_t(w) << 5) | (uint32_t(r) << 3)
94 | (uint32_t(rd) << 1) | (hasNew ? 1 : 0);
95 }
96 static constexpr int writeIndex(uint32_t state) noexcept { return (state >> 5) & 3; }
97 static constexpr int readyIndex(uint32_t state) noexcept { return (state >> 3) & 3; }
98 static constexpr int readIndex(uint32_t state) noexcept { return (state >> 1) & 3; }
99 static constexpr bool hasNewFrame(uint32_t state) noexcept { return state & 1; }
100 static constexpr bool everReady(uint32_t state) noexcept { return (state >> 7) & 1; }
101
102 std::atomic<uint32_t> m_state;
103};
104
105} // namespace score::gfx
Definition TripleBufferIndex.hpp:23
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11