Loading...
Searching...
No Matches
PipelineStateHelpers.hpp
1#pragma once
2#include <isf.hpp>
3
4#include <QtGui/private/qrhi_p.h>
5
6#include <score_plugin_gfx_export.h>
7
8#include <string_view>
9
10namespace score::gfx
11{
12class Node;
13struct Port;
14
15// --- String → Qt RHI enum mappers ----------------------------------------
16//
17// All mappers are case-insensitive and accept common synonyms
18// (e.g. "lequal" / "less_equal" both map to CompareOp::LessOrEqual).
19// Unknown strings fall back to a sensible default (documented per function).
20
21// Unknown → Greater, the reverse-Z default (warns once).
22SCORE_PLUGIN_GFX_EXPORT
23QRhiGraphicsPipeline::CompareOp toCompareOp(std::string_view s) noexcept;
24
25SCORE_PLUGIN_GFX_EXPORT
26QRhiGraphicsPipeline::CullMode toCullMode(std::string_view s) noexcept;
27
28SCORE_PLUGIN_GFX_EXPORT
29QRhiGraphicsPipeline::FrontFace toFrontFace(std::string_view s) noexcept;
30
31SCORE_PLUGIN_GFX_EXPORT
32QRhiGraphicsPipeline::PolygonMode toPolygonMode(std::string_view s) noexcept;
33
34// TOPOLOGY: triangles / triangle_list, triangle_strip, triangle_fan,
35// lines / line_list, line_strip, points. Unknown → Triangles.
36SCORE_PLUGIN_GFX_EXPORT
37QRhiGraphicsPipeline::Topology toTopology(std::string_view s) noexcept;
38
39// Fill when `requested` is not Fill and the backend does not report
40// QRhi::NonFillPolygonMode; warns once per process in that case.
41SCORE_PLUGIN_GFX_EXPORT
42QRhiGraphicsPipeline::PolygonMode supportedPolygonMode(
43 QRhiGraphicsPipeline::PolygonMode requested, bool nonFillSupported) noexcept;
44
45// QRhi::TriangleFanTopology, which D3D11, D3D12 and Metal do not have: their
46// backends hit Q_UNREACHABLE (D3D11, Metal) or draw a strip (D3D12) when given
47// a TriangleFan pipeline. SCORE_GFX_NO_TRIANGLE_FAN=1 reports it unsupported
48// on any backend, so that the fallbacks can be exercised on Vulkan / OpenGL.
49SCORE_PLUGIN_GFX_EXPORT
50bool triangleFanSupported(const QRhi& rhi) noexcept;
51
52// `requested`, or Triangles in place of a TriangleFan the backend cannot draw,
53// so that the pipeline never reaches the backend's unreachable path. Callers
54// that can lower the fan to a triangle list (lowerTriangleFan, the VSA index
55// list) do so before getting here.
56SCORE_PLUGIN_GFX_EXPORT
57QRhiGraphicsPipeline::Topology
58supportedTopology(const QRhi& rhi, QRhiGraphicsPipeline::Topology requested) noexcept;
59
60// Sets supportedTopology(requested) on `ps`. When that had to replace a fan,
61// `ps` is recorded so that drawsUnsupportedFan says its draws are skipped,
62// with one warning for the pipeline: a fan drawn as a triangle list is other
63// triangles than the fan's. Any other topology clears the record.
64SCORE_PLUGIN_GFX_EXPORT
65void setSupportedTopology(
66 QRhiGraphicsPipeline& ps, QRhiGraphicsPipeline::Topology requested) noexcept;
67
68// Whether `ps` stands for a triangle fan the backend cannot draw.
69SCORE_PLUGIN_GFX_EXPORT
70bool drawsUnsupportedFan(const QRhiGraphicsPipeline& ps) noexcept;
71
72SCORE_PLUGIN_GFX_EXPORT
73QRhiGraphicsPipeline::BlendFactor toBlendFactor(std::string_view s) noexcept;
74
75SCORE_PLUGIN_GFX_EXPORT
76QRhiGraphicsPipeline::BlendOp toBlendOp(std::string_view s) noexcept;
77
78SCORE_PLUGIN_GFX_EXPORT
79QRhiGraphicsPipeline::StencilOp toStencilOp(std::string_view s) noexcept;
80
81SCORE_PLUGIN_GFX_EXPORT
82QRhiGraphicsPipeline::ColorMask toColorMask(std::string_view s) noexcept;
83
84// Depth-attachment clear value to pair with a declared DEPTH_COMPARE.
85//
86// Depth after the viewport transform is in [0, 1], so a clear value only
87// admits fragments on one side of it: 0.0 works with `greater` / `greater_equal`
88// (the project-wide reverse-Z convention documented in CameraMath.hpp) and
89// rejects every fragment under `less` / `less_equal`.
90SCORE_PLUGIN_GFX_EXPORT
91float depthClearForCompare(QRhiGraphicsPipeline::CompareOp compare) noexcept;
92
93// The same, for a shader's declared state: uses its DEPTH_COMPARE when it set
94// one, and otherwise the project-wide reverse-Z default.
95//
96// Every path that opens a pass with a depth attachment must go through this.
97// Picking the clear independently of the compare is not a cosmetic mismatch --
98// it silently discards the whole draw, because a clear of 0.0 admits nothing
99// under `less`.
100SCORE_PLUGIN_GFX_EXPORT
101float depthClearForState(const isf::pipeline_state& state) noexcept;
102
103// --- Conversion helpers ---------------------------------------------------
104
105SCORE_PLUGIN_GFX_EXPORT
106QRhiGraphicsPipeline::TargetBlend toTargetBlend(const isf::blend_attachment& b) noexcept;
107
108SCORE_PLUGIN_GFX_EXPORT
109QRhiGraphicsPipeline::StencilOpState toStencilOpState(const isf::stencil_op_state& s) noexcept;
110
111// --- Output compositing ---------------------------------------------------
112//
113// Render targets between nodes hold premultiplied colour. A shader output is
114// composited "over" what its target already holds, with the factors that
115// match what it writes (its ALPHA key); both store premultiplied colour.
116
117// Colour One / OneMinusSrcAlpha, alpha One / OneMinusSrcAlpha.
118SCORE_PLUGIN_GFX_EXPORT
119QRhiGraphicsPipeline::TargetBlend premultipliedOverBlend() noexcept;
120
121// Colour SrcAlpha / OneMinusSrcAlpha, alpha One / OneMinusSrcAlpha.
122SCORE_PLUGIN_GFX_EXPORT
123QRhiGraphicsPipeline::TargetBlend straightOverBlend() noexcept;
124
125// The blend compositing an output onto its target, from its ALPHA and
126// COMPOSITE. The destination holds premultiplied colour. A straight output
127// with multiply or screen gets the premultiplied factors (it is premultiplied
128// before blending, see isf::premultiplied_by_engine).
129// over : colour src / OneMinusSrcAlpha, alpha One / OneMinusSrcAlpha
130// add : colour src / One, alpha One / One
131// multiply : colour DstColor / OneMinusSrcAlpha (exact over an opaque
132// destination), alpha One / OneMinusSrcAlpha
133// screen : colour OneMinusDstColor / One, alpha One / OneMinusSrcAlpha
134// replace : colour src / Zero, alpha One / Zero
135// where src is SrcAlpha for straight and One for premultiplied.
136SCORE_PLUGIN_GFX_EXPORT
137QRhiGraphicsPipeline::TargetBlend
138blendFor(isf::alpha_mode alpha, isf::composite_mode composite) noexcept;
139
140// The blend of an output into the node's own cleared texture, which is then
141// copied into its consumers with blendFor(premultiplied, composite): as
142// blendFor, except multiply, which composites over (a layer multiplied onto
143// transparent black would vanish).
144SCORE_PLUGIN_GFX_EXPORT
145QRhiGraphicsPipeline::TargetBlend
146layerBlendFor(isf::alpha_mode alpha, isf::composite_mode composite) noexcept;
147
148// One blend per colour attachment: attachment i takes the ALPHA and COMPOSITE
149// of the i-th colour OUTPUT (depth OUTPUTS skipped), else the descriptor's.
150// Integer FORMATs get no blend. ownTargets: the node renders into its own
151// textures (layerBlendFor) rather than into its consumers.
152SCORE_PLUGIN_GFX_EXPORT
153QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 4> outputBlends(
154 const isf::descriptor& desc, int colorAttachmentCount, bool ownTargets = false);
155
156// The blend copying an output that the node stored premultiplied in its own
157// texture into a consumer: its COMPOSITE, or over when the shader declares
158// BLEND.
159SCORE_PLUGIN_GFX_EXPORT
160QRhiGraphicsPipeline::TargetBlend
161copyBlendFor(const isf::descriptor& desc, const isf::output_declaration* out) noexcept;
162
163// The OUTPUTS entry of a colour image outlet of an ISF / raw raster node
164// (image outlets only, in OUTPUTS order), or nullptr.
165SCORE_PLUGIN_GFX_EXPORT
166const isf::output_declaration*
167colorOutputDeclaration(const isf::descriptor& desc, const Node& node, const Port& output);
168
169// Integer colour formats cannot be blended.
170SCORE_PLUGIN_GFX_EXPORT
171bool formatSupportsBlending(QRhiTexture::Format f) noexcept;
172
173// --- pipeline_state manipulation ------------------------------------------
174
175// Merge two pipeline_states: every field that is set in `over` wins, otherwise
176// `base`'s field is kept. Used to combine the descriptor's global state with a
177// per-pass override_state.
178SCORE_PLUGIN_GFX_EXPORT
179isf::pipeline_state mergeState(isf::pipeline_state base, const isf::pipeline_state& over);
180
181// Whether a pipeline built from `state` writes depth on every backend: it
182// declares DEPTH_TEST and DEPTH_WRITE. With the test off, Vulkan and OpenGL
183// write no depth (Metal does), and the ISF quad has it off unless declared.
184SCORE_PLUGIN_GFX_EXPORT
185bool declaresDepthWrite(const isf::pipeline_state& state) noexcept;
186
187// The state of a copy that carries the depth a pass wrote with `source` into
188// another target: test and write on, with the source's compare, so that the
189// copy depth-tests against the other producers of that target as drawing the
190// pass there would have.
191SCORE_PLUGIN_GFX_EXPORT
192isf::pipeline_state depthCopyState(const isf::pipeline_state& source);
193
194// Returns true if the state has any field set (i.e. would affect a pipeline).
195SCORE_PLUGIN_GFX_EXPORT
196bool stateAffectsPipeline(const isf::pipeline_state&) noexcept;
197
198// Apply the state to a graphics pipeline.
199// - `colorAttachmentCount`: used to size per-attachment blend vectors.
200// - `depthAttachmentAvailable`: true when the target RT has a depth attachment;
201// depth-test/write are forced off otherwise.
202// - `wantsDepthByDefault`: when state.depth_test is nullopt and this is false,
203// depth test/write are force-disabled; callers pass
204// `renderer.anyNodeRequiresDepth()`.
205//
206// Only fields explicitly set in `state` are overridden. Cull, front-face,
207// polygon mode, blend, and stencil all preserve whatever the caller (or
208// `mesh.preparePipeline()`) configured before this call. The caller is
209// responsible for seeding sensible defaults (e.g. blendFor(ALPHA, COMPOSITE)) before
210// invoking this, so that shaders declaring partial pipeline_state don't
211// silently lose unrelated defaults.
212SCORE_PLUGIN_GFX_EXPORT
213void applyPipelineState(
214 const QRhi& rhi, QRhiGraphicsPipeline& pip,
215 const isf::pipeline_state& state,
216 int colorAttachmentCount,
217 bool depthAttachmentAvailable,
218 bool wantsDepthByDefault) noexcept;
219
220// Turns the stencil test of `pip` off when its target has no stencil
221// attachment, with a warning naming `what`. The engine's 3D targets are D32F
222// without stencil; a STENCIL_TEST drawn into one tests nothing on Vulkan and
223// GL, and Metal's API validation aborts on it ("MTLDepthStencilDescriptor
224// uses frontFaceStencil but MTLRenderPassDescriptor has a nil
225// stencilAttachment texture").
226SCORE_PLUGIN_GFX_EXPORT
227void dropStencilWithoutAttachment(
228 QRhiGraphicsPipeline& pip, bool stencilAttachmentAvailable,
229 std::string_view what) noexcept;
230
231}
TreeNode< DeviceExplorerNode > Node
Definition DeviceNode.hpp:74
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
STL namespace.