Loading...
Searching...
No Matches
OffscreenDevice.hpp
1#pragma once
2
3#include <Gfx/GfxParameter.hpp>
4#include <Gfx/Graph/BackgroundNode.hpp>
5
6#include <ossia/network/base/device.hpp>
7#include <ossia/network/base/protocol.hpp>
8#include <ossia/network/generic/generic_node.hpp>
9
10#include <ossia-qt/invoke.hpp>
11
12namespace Gfx
13{
14
15// Headless device used when SCORE_FORCE_OFFSCREEN_WINDOW selects this
16// window device by name. Wraps a BackgroundNode — which already drives
17// beginOffscreenFrame/endOffscreenFrame — without the ScenarioDocumentView
18// dependency of background_device. Exposes only the parameters required by
19// offscreen tests (size, rendersize) and holds the shared_readback used by
20// WindowDevice::grabTo to write frames to disk.
21class offscreen_device : public ossia::net::device_base
22{
23 // unique_ptr ownership: BackgroundNode is not a QObject child of any
24 // parent in this class (it inherits NodeModel, not QObject), so nothing
25 // else would delete it -- and every offscreen device cycle would leak it
26 // along with the rhi resources its ~BackgroundNode → destroyOutput
27 // releases.
28 std::unique_ptr<score::gfx::BackgroundNode> m_node;
29 gfx_node_base m_root;
30 QObject m_qtContext;
31
32 ossia::net::parameter_base* size_param{};
33 ossia::net::parameter_base* rendersize_param{};
34
35public:
36 offscreen_device(std::unique_ptr<gfx_protocol_base> proto, std::string name)
37 : ossia::net::device_base{std::move(proto)}
38 , m_node{std::make_unique<score::gfx::BackgroundNode>()}
39 , m_root{*this, *static_cast<gfx_protocol_base*>(m_protocol.get()), m_node.get(), name}
40 {
41 this->m_capabilities.change_tree = true;
42 m_node->shared_readback = std::make_shared<QRhiReadbackResult>();
43
44 {
45 auto size_node = std::make_unique<ossia::net::generic_node>("size", *this, m_root);
46 size_param = size_node->create_parameter(ossia::val_type::VEC2F);
47 size_param->push_value(ossia::vec2f{1280.f, 720.f});
48 m_node->setSize(QSize{1280, 720});
49 size_param->add_callback([this](const ossia::value& v) {
50 if(auto val = v.target<ossia::vec2f>())
51 {
52 ossia::qt::run_async(&m_qtContext, [node = m_node.get(), v = *val] {
53 node->setSize({(int)v[0], (int)v[1]});
54 });
55 }
56 });
57 m_root.add_child(std::move(size_node));
58 }
59
60 {
61 auto size_node
62 = std::make_unique<ossia::net::generic_node>("rendersize", *this, m_root);
63 ossia::net::set_description(
64 *size_node, "Set to [0, 0] to use the viewport's size");
65 rendersize_param = size_node->create_parameter(ossia::val_type::VEC2F);
66 rendersize_param->push_value(ossia::vec2f{0.f, 0.f});
67 rendersize_param->add_callback([this](const ossia::value& v) {
68 if(auto val = v.target<ossia::vec2f>())
69 {
70 ossia::qt::run_async(&m_qtContext, [node = m_node.get(), v = *val] {
71 node->setRenderSize({(int)v[0], (int)v[1]});
72 });
73 }
74 });
75 m_root.add_child(std::move(size_node));
76 }
77 }
78
79 ~offscreen_device()
80 {
81 // Remove our output from the render graph synchronously, while both the
82 // BackgroundNode and its QRhi are still alive. This output is owned by the
83 // device (not the graph), so on shutdown it is torn down here before
84 // Graph::~Graph runs — and the graph's async REMOVE_NODE queue is never
85 // drained again. Without this, the graph is left with a dangling output
86 // pointer + a RenderList over a freed QRhi (SIGSEGV in ~Graph teardown).
87 if(auto* proto = static_cast<gfx_protocol_base*>(m_protocol.get());
88 proto && proto->context && proto->context->ui)
89 proto->context->ui->destroyOutput(m_node.get());
90
91 m_protocol->stop();
92 m_root.clear_children();
93 m_protocol.reset();
94 // m_node destroyed by unique_ptr → ~BackgroundNode → destroyOutput
95 // (releases RT/RPD/depth tex/colour tex + the offscreen rhi).
96 }
97
98 score::gfx::BackgroundNode* node() const noexcept { return m_node.get(); }
99
100 const gfx_node_base& get_root_node() const override { return m_root; }
101 gfx_node_base& get_root_node() override { return m_root; }
102};
103
104}
Definition GfxParameter.hpp:71
Definition GfxParameter.hpp:52
Definition OffscreenDevice.hpp:22
Binds the rendering pipeline to ossia processes.
Definition AssetTable.cpp:7
Definition BackgroundNode.hpp:16