Loading...
Searching...
No Matches
GfxContext.hpp
1#pragma once
2#include <span>
3#include <Process/Dataflow/CableData.hpp>
4
5#include <Gfx/AssetTable.hpp>
6#include <Gfx/Graph/Node.hpp>
7#include <Gfx/Graph/RenderClock.hpp>
8
9#include <score/tools/Timers.hpp>
10
11#include <ossia/dataflow/nodes/media.hpp>
12#include <ossia/dataflow/token_request.hpp>
13#include <ossia/detail/buffer_pool.hpp>
14#include <ossia/detail/flat_set.hpp>
15#include <ossia/detail/hash_map.hpp>
16#include <ossia/detail/mutex.hpp>
17#include <ossia/detail/small_flat_map.hpp>
18#include <ossia/detail/variant.hpp>
19#include <ossia/gfx/port_index.hpp>
20#include <ossia/network/value/value.hpp>
21
22#include <concurrentqueue.h>
23#include <score_plugin_gfx_export.h>
24class QTimer;
25namespace score {
26class HighResolutionTimer;
27class Timers;
28}
29namespace score::gfx
30{
31struct Graph;
32class OutputNode;
33}
34namespace score
35{
36struct DocumentContext;
37}
38namespace Gfx
39{
40using port_index = ossia::gfx::port_index;
42{
43 port_index first{};
44 port_index second{};
45 Process::CableType type{};
46
47 // type takes part in identity: the exec thread republishes the full edge
48 // set every tick and endTick dedups against prev_edges, so a comparison that
49 // ignored the cable type would make an Immediate/Delayed flip invisible. As
50 // it stands a type flip diffs as remove(old) + add(new) in the incremental
51 // path.
52 bool operator==(const EdgeSpec& other) const noexcept
53 {
54 return first == other.first && second == other.second && type == other.type;
55 }
56 bool operator!=(const EdgeSpec& other) const noexcept { return !(*this == other); }
57 bool operator<(const EdgeSpec& other) const noexcept
58 {
59 if(first != other.first)
60 return first < other.first;
61 if(second != other.second)
62 return second < other.second;
63 return type < other.type;
64 }
65};
66
68class SCORE_PLUGIN_GFX_EXPORT GfxContext : public QObject
69{
70 friend class GfxExecutionAction;
71
72public:
73 using NodePtr = std::unique_ptr<score::gfx::Node>;
74
75 explicit GfxContext(const score::DocumentContext& ctx);
77
78 int32_t register_node(NodePtr node);
79 int32_t register_preview_node(NodePtr node);
80 void connect_preview_node(EdgeSpec e);
81 void disconnect_preview_node(EdgeSpec e);
82 void unregister_node(int32_t idx);
83 void unregister_preview_node(int32_t idx);
84
85 // Synchronously tear down an output node's render list and drop it from the
86 // graph. Used by device-owned outputs (e.g. the offscreen BackgroundNode)
87 // whose destructor runs during shutdown before the async node-command queue
88 // is drained — without this the graph is left with a dangling output pointer
89 // and a RenderList referencing an already-freed QRhi.
90 void destroyOutput(score::gfx::OutputNode* node);
91
94 std::span<score::gfx::OutputNode* const> outputs() const noexcept;
95
96 void recompute_edges();
97 void recompute_graph();
98 void recompute_connections();
99 void recomputeTimers();
100 void recomputeGraphTopology();
101 void incrementalEdgeUpdate(
102 const ossia::flat_set<EdgeSpec>& old_edges,
103 const ossia::flat_set<EdgeSpec>& cur_edges);
104
105 void update_inputs();
106 void updateGraph();
107
131 void renderFrames(int frames);
132
134 double stepRate() const noexcept { return m_stepRate; }
135 void setStepRate(double fps) noexcept { m_stepRate = fps; }
136
137 void send_message(score::gfx::Message&& msg) noexcept
138 {
139 tick_messages.enqueue(std::move(msg));
140 }
141
151 AssetTable& assets() noexcept { return m_assets; }
152 const AssetTable& assets() const noexcept { return m_assets; }
153
154private:
155 void run_commands();
156 void add_preview_output(score::gfx::OutputNode& out);
157 void remove_preview_output();
158 void add_edge(EdgeSpec e);
159 void remove_edge(EdgeSpec e);
160 void remove_node(std::vector<std::unique_ptr<score::gfx::Node>>& nursery, int32_t id);
161
162 void on_no_vsync_timer(score::HighResolutionTimer* self);
163 void on_watchdog_timer(score::HighResolutionTimer* self);
164 const score::DocumentContext& m_context;
165 std::atomic_int32_t index{1};
166 ossia::hash_map<int32_t, NodePtr> nodes;
167
168 score::gfx::Graph* m_graph{};
169 QThread m_thread;
170
171 double m_stepRate{60.};
172 int64_t m_stepFrame{};
173
174 struct NodeCommand
175 {
176 enum
177 {
178 ADD_NODE,
179 ADD_PREVIEW_NODE,
180 REMOVE_NODE,
181 REMOVE_PREVIEW_NODE,
182 RELINK
183 } cmd{};
184 int32_t index{};
185 std::unique_ptr<score::gfx::Node> node;
186 };
187
188 struct EdgeCommand
189 {
190 enum
191 {
192 CONNECT_PREVIEW_NODE,
193 DISCONNECT_PREVIEW_NODE
194 } cmd{};
195 EdgeSpec edge;
196 };
197
198 using Command = ossia::variant<NodeCommand, EdgeCommand>;
199 moodycamel::ConcurrentQueue<Command> tick_commands;
200 moodycamel::ConcurrentQueue<score::gfx::Message> tick_messages;
201 std::vector<std::pair<score::gfx::Message, int>> m_deferredMessages;
202
203 std::mutex edges_lock;
204 ossia::flat_set<EdgeSpec> new_edges TS_GUARDED_BY(edges_lock);
205 ossia::flat_set<EdgeSpec> edges TS_GUARDED_BY(edges_lock);
206 ossia::flat_set<EdgeSpec> preview_edges TS_GUARDED_BY(edges_lock);
207 std::atomic_bool edges_changed{};
208 bool m_fullRebuildThisFrame{};
209
210 score::HighResolutionTimer* m_no_vsync_timer{};
211 score::HighResolutionTimer* m_watchdog_timer{};
212 // Rate == 0 with vsync off: zero-interval timer, renders back-to-back.
213 QTimer* m_freewheel_timer{};
214
215 // Per-output render clocks (the render-clock / genlock abstraction).
216 // Each TimerClock owns one shared HighResolutionTimer at a given
217 // manualRenderingRate and the coalesced set of outputs driven by it
218 // (clock #2, the default); the single DisplayVSyncClock wraps the
219 // swap-chain vsync callback (clock #1).
220 std::vector<std::unique_ptr<score::gfx::TimerClock>> m_renderClocks;
221 std::unique_ptr<score::gfx::DisplayVSyncClock> m_vsyncClock;
222
223 ossia::object_pool<std::vector<score::gfx::gfx_input>> m_buffers;
224
225 AssetTable m_assets;
226
227 score::Timers m_timers;
228};
229
230}
Cross-RenderList content-hash dedup for decoded asset bytes.
Definition AssetTable.hpp:71
Definition GfxContext.hpp:69
double stepRate() const noexcept
Step used by renderFrames(), in frames per second.
Definition GfxContext.hpp:134
AssetTable & assets() noexcept
Session-wide content-hash decode cache.
Definition GfxContext.hpp:151
Definition GfxExecContext.hpp:18
Definition Timers.hpp:14
Definition Timers.hpp:38
Base class for sink nodes (QWindow, spout, syphon, NDI output, ...)
Definition OutputNode.hpp:54
Binds the rendering pipeline to ossia processes.
Definition AssetTable.cpp:7
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
Base toolkit upon which the software is built.
Definition Application.cpp:116
Definition GfxContext.hpp:42
Definition DocumentContext.hpp:18
Represents a graph of renderers.
Definition score-plugin-gfx/Gfx/Graph/Graph.hpp:22
Definition score-plugin-gfx/Gfx/Graph/Node.hpp:49