Loading...
Searching...
No Matches
score::gfx Namespace Reference

Graphics rendering pipeline for ossia score. More...

Detailed Description

Graphics rendering pipeline for ossia score.

Compile-time detection and dispatch for the QRhi indirect APIs that are newer than this project's Qt floor:

Qt 6.12: QRhi::DrawIndirect / DrawIndirectMulti, QRhiCommandBuffer::drawIndirect / drawIndexedIndirect Qt 6.13: QRhi::DispatchIndirect / DrawIndirectCount, QRhiCommandBuffer::dispatchIndirect, drawIndirectCount / drawIndexedIndirectCount

Detection is by member/enumerator rather than QT_VERSION_CHECK(6, 13, 0): the ossia SDK pins the Qt 6.12 branch and cherry-picks the dev (6.13) indirect changes on top (sdk common/clone-qt.sh: refs/changes/11/738611, 12/738612, 69/761469). On those builds QT_VERSION says 6.12 while the 6.13 API is present, so a version gate would silently compile the features out of the reference builds. A stock 6.12 lacks the API entirely, and CI's floor is 6.4. Member/enumerator detection is right on all three tiers; version macros are right on only two.

SCORE_GFX_SIMULATE_QT612: this compile flag forces every 6.13-era detection below to false even when the API exists, so the "Qt 6.12: multi-draw indirect but no count, no indirect dispatch" tier can be built and run against a newer Qt when no stock 6.12 build is reachable. The runtime equivalents are the SCORE_GFX_NO_GPU_INDIRECT* environment kill switches in RenderList.cpp.

This namespace provides a rendering pipeline for GPU visuals, by the way of a rendering graph. The implementation uses the Qt RHI:

https://www.qt.io/blog/graphics-in-qt-6.0-qrhi-qt-quick-qt-quick-3d

It is mainly designed for rendering a succession of visual effects, not rendering arbitrary 3D. Shaders are written in the usual glslang -> spirv-cross fashion, with GLSL version 450. They are then translated automatically to SPIRV, Metal, GLSL or D3D11 shaders.

The overall design is as follows :

  • Elements to render are represented as nodes to a graph: score::gfx::Node
  • Input ports are the uniforms and input textures & audio data.
  • Output ports generally are just the texture we are rendering to.
  • score::gfx::Graph contains all the nodes, and relationships between these nodes.
  • For each output sink (a window surface, an NDI or Spout output...), a score::gfx::RenderList is created. It contains all the nodes to render for a given output.
  • For each score::gfx::Node, the score::gfx::RenderList creates a score::gfx::NodeRenderer which contains the actual GPU resource handles for the sink.

Given the following graph :

[ video ] -> [ shader 1 ] -> [ screen 1 ]
\
-> [ shader 2] -> [ Spout output ]

Two render lists are created, the first being

[ video ] -> [ shader 1 ] -> [ screen 1 ]

and the second being

[ video ] -> [ shader 1 ] -> [ shader 2] -> [ Spout output ]

Rendering for these two RenderList is entirely independent - they can render at different sizes and potentially use different graphic APIs, e.g. one OpenGL and the other Vulkan. This is also done to enable threaded rendering for each of these.

We provide the most essential nodes for building interesting visual effects:

  • A window output node (score::gfx::ScreenNode).
  • Shader filters using Interactive Shader Format (https://isf.video).
  • Video (score::gfx::VideoNode) and image (score::gfx::ImagesNode) renderers.
  • The video renderer tries to do as much of the decoding as possible on the GPU: for instance YUV420, HAP, ... are decoded on the GPU. Otherwises it falls back on libavcodec to guarantee compatibility with a wide range of video formats.

Other plug-ins may provide other useful things, such as NDI I/O or particle effects.

See GfxPlugins for information on how to create your custom nodes, visual effects and video decoders.

Namespaces

namespace  RhiClearBuffer
 Fill (a sub-range of) a QRhiBuffer with a 4-byte pattern.
 

Classes

struct  ArrayParseResult
 
struct  AudioTexture
 Data model for audio data being sent to the GPU. More...
 
struct  AudioTextureUpload
 
struct  BackgroundNode
 
struct  BasicMesh
 
struct  BayerDecoder
 Demosaics a single-channel colour-filter-array frame into RGB. More...
 
struct  BayerExternalOESDecoder
 
struct  BGRAComputeEncoder
 Compute-shader RGBA -> BGRA (NTV2_FBF_ARGB byte order) encoder targeting an external SSBO. More...
 
struct  BGRAEncoder
 Cross-backend RGBA -> BGRA byte-order encoder. More...
 
struct  BitField
 One channel's placement inside the packed container. More...
 
struct  BufferCopyRegion
 Region-based GPU buffer copy for strided / gather patterns. More...
 
struct  BufferView
 
struct  CameraUBOData
 
struct  CaptureAdjust
 Sensor-side corrections, in the order the shader applies them. More...
 
class  CaptureAdjustSlot
 Cross-thread handoff for CaptureAdjust. More...
 
struct  CaptureMaterialUBO
 The capture path's material block: the shared one, plus corrections. More...
 
struct  ComputeEncoder
 Base interface for compute-shader RGBA -> AJA-format encoders. More...
 
struct  CudaFunctions
 Runtime-loaded CUDA driver-API table. Owns the libcuda handle. More...
 
class  CustomMesh
 
struct  DecodedImage
 
struct  DefaultShaderMaterial
 Utility to represent a shader material following score conventions. More...
 
class  DirectVideoNodeRenderer
 Renderer for intra-only video codecs with instant seeking. More...
 
struct  DirectVideoOutputBackend
 Vendor playout backend. Constructed with its vendor-specific settings (video format, pixel format, channel, link, HDR, ...); open() then brings the device up. The node queries geometry/format/planes and drives playout through the registrar + GPU-direct candidates + pacing hooks. More...
 
class  DirectVideoOutputNode
 
class  DisplayVSyncClock
 Wraps ScreenNode's swap-chain vsync callback path (clock #1, push). More...
 
struct  DMACaptureBackend
 Vendor seam for a DMA capture card's input path. More...
 
struct  DMACaptureInputNode
 ProcessNode base for DMA capture-card inputs. One Image output port; its renderer is the generic DMACaptureRenderer. More...
 
struct  DrawCall
 
struct  DummyMesh
 
struct  DXVDecoder
 Decodes DXV DXT1/DXT5 (Resolume) format to GPU. More...
 
struct  DXVYCoCgDecoder
 Decodes DXV YCG6/YG10 (YCoCg) format to GPU. More...
 
struct  Edge
 Connection between two score::gfx::Port. More...
 
struct  EmptyDecoder
 Default decoder when we do not know what to render. More...
 
struct  EnvParamsUBO
 
class  ExternalGenlockClock
 Hardware-genlock render clock (opt-in): a card's output VBI. More...
 
struct  FallbackBindingPlan
 
struct  FlatScene
 
class  FlattenedSceneFilterNode
 Per-pass filter on a flattened scene: geometry_spec → geometry_spec. More...
 
struct  FlattenVisitor
 
struct  FullScreenImageNode
 
struct  GaussianSplatNode
 Gaussian Splat rendering node. More...
 
class  GaussianSplatRenderer
 Renderer for GaussianSplatNode. More...
 
class  GenericNodeRenderer
 Generic renderer. More...
 
struct  geometry
 
struct  geometry_input_port_vis
 
class  GeometryFilterNode
 Data model for geometry filters. More...
 
struct  GeometryFilterNodeRenderer
 
class  GPUBufferScatter
 GPU-side buffer format conversion (scatter). More...
 
class  GpuResourceRegistry
 Per-RenderList arena store for GPU-resident scene data. More...
 
class  GpuTimings
 Named-bucket GPU timing collector. More...
 
class  GPUVideoDecoder
 Processes and renders a video frame on the GPU. More...
 
struct  GPUVideoEncoder
 Base class for GPU-side video format conversion (RGBA to YUV). More...
 
struct  Graph
 Represents a graph of renderers. More...
 
struct  GraphicsSSBO
 One SSBO attached to a graphics pipeline. More...
 
struct  GraphicsStorageImage
 One storage image attached to a graphics pipeline. More...
 
struct  GraphicsStorageResources
 Aggregate of all graphics-visible storage resources for a node. More...
 
struct  GraphicsUBO
 One UBO sourced from an upstream Buffer port (uniform_input). More...
 
struct  HAPDecoder
 Base class for HAP ((c) Vidvox) decoding. More...
 
struct  HAPDefaultDecoder
 Decodes HAP basic format. More...
 
struct  HAPMDecoder
 Decodes HAP-M (HAP + alpha channel) More...
 
struct  HWTransferDecoder
 Fallback hardware decoder that transfers HW frames to CPU via av_hwframe_transfer_data(), then delegates to a software GPU decoder. More...
 
struct  I420Encoder
 GPU RGBA->I420 encoder (planar 4:2:0). More...
 
struct  Image
 Image data and metadata. More...
 
struct  image
 
struct  ImagesNode
 A node that renders an image to screen. More...
 
struct  InstanceKey
 
struct  InstanceKeyHash
 
struct  is_output
 
struct  isf_input_port_count_vis
 
struct  isf_input_port_vis
 
struct  isf_input_size_vis
 
class  ISFNode
 Data model for Interactive Shader Format filters. More...
 
class  KmsOutputNode
 OutputNode scanning out directly through DRM/KMS. More...
 
struct  KmsOutputSettings
 
struct  LayoutResult
 
struct  MaterialExtensionsGPU
 
struct  MaterialGPU
 
struct  MatrixShape
 
class  MergeGeometriesNode
 Concatenates up to N upstream geometry_specs into one. More...
 
struct  Mesh
 Data model for meshes. More...
 
struct  MeshBuffers
 
struct  MeshUBO
 
struct  Message
 
struct  ModelCameraUBO
 UBO shared across all entities shown with the same camera. More...
 
struct  ModelDisplayNode
 A node that renders a model to screen. More...
 
struct  MultiWindowNode
 
class  MultiWindowRenderer
 
struct  no_delay_edges
 
class  Node
 Root data model for visual nodes. More...
 
class  NodeModel
 Common base class for most single-pass, simple nodes. More...
 
class  NodeRenderer
 Renderer for a given node. More...
 
struct  NV12Decoder
 Decodes NV12 videos. More...
 
struct  NV12Encoder
 GPU RGBA->NV12 encoder (semi-planar 4:2:0). More...
 
struct  NV12ExternalOESDecoder
 
struct  NV16Decoder
 Decodes NV16 semi-planar 4:2:2 8-bit videos. More...
 
struct  NV24Decoder
 Decodes NV24 / NV42 semi-planar 4:4:4 8-bit videos. More...
 
struct  OutputConfiguration
 
class  OutputNode
 Base class for sink nodes (QWindow, spout, syphon, NDI output, ...) More...
 
class  OutputNodeRenderer
 
struct  OutputUBO
 UBO shared across all entities shown on the same output. More...
 
struct  P010Decoder
 Decodes P010 videos. More...
 
struct  P010Encoder
 GPU RGBA -> p010le encoder (semi-planar 4:2:0, 10-bit). More...
 
struct  P016Decoder
 Decodes P016 videos. More...
 
struct  P210Decoder
 Decodes P210 semi-planar 4:2:2 10-bit videos. More...
 
struct  P410Decoder
 Decodes P410 semi-planar 4:4:4 10-bit videos. More...
 
struct  PackedBitfieldLayout
 
struct  PackedBitfieldYUVDecoder
 
struct  PackedBitfieldYUVLayout
 
struct  PackedDecoder
 
struct  PackedRectDecoder
 
struct  PackedRGBEncoder
 Generic packed-pixel RGB/byte encoder for AJA framebuffer formats. More...
 
struct  Pass
 
struct  PersistSampler
 
struct  Pipeline
 Useful abstraction for storing a graphics pipeline and associated resource bindings. More...
 
struct  PixelFormatInfo
 
struct  PlainMesh
 A mesh with only position attributes. More...
 
struct  PlainTriangle
 A triangle mesh with only positions. More...
 
struct  PlanarDecoder
 
struct  Port
 Port of a score::gfx::Node. More...
 
struct  port_counts
 
struct  port_indices
 
class  PreviewNode
 
class  PreviewRenderer
 
class  PreviewRendererInvertY
 
class  ProcessNode
 Common base class for nodes that map to score processes. More...
 
struct  ProcessUBO
 UBO specific to individual processes / nodes. More...
 
struct  R210Decoder
 Decodes 10-bit RGB packed in r210 (DeckLink bmdFormat10BitRGB). More...
 
struct  RawCameraData
 
struct  RawLightData
 
struct  RawLocalTransform
 
struct  ReadbackTarget
 
struct  RefcountedFrame
 
class  RenderClock
 Abstract render clock. More...
 
struct  RenderedCSFNode
 
struct  RenderedFlattenedSceneFilterNode
 
struct  RenderedISFNode
 
struct  RenderedMergeGeometriesNode
 
struct  RenderedRawRasterPipelineNode
 
struct  RenderedSceneFilterNode
 
struct  RenderedScenePreprocessorNode
 
class  RenderList
 List of nodes to be rendered to an output. More...
 
struct  RenderState
 Global state associated to a rendering context. More...
 
struct  RenderTargetSpecs
 
struct  RGB24Decoder
 
struct  RGB48Decoder
 
struct  RGBA64Decoder
 
struct  Sampler
 Stores a sampler and the texture currently associated with it. More...
 
class  SceneFilterNode
 Tree-level filter on a scene_spec. More...
 
class  ScenePreprocessorNode
 Bridge from scene_spec (hierarchical, CPU) to geometry_spec (flat, GPU-resident). More...
 
struct  SceneUBO
 
class  ScopedGpuTimer
 RAII helper that brackets a named pass region for GPU frame-debug. More...
 
struct  ScreenNode
 This node is used for rendering to a score::gfx::Window. More...
 
struct  ShaderCache
 Cache of baked QShader instances. More...
 
struct  ShadowCascadesUBO
 
struct  SimpleRenderedISFNode
 
struct  SimpleRenderedVSANode
 
struct  SkeletonGPU
 
struct  Std430TypeInfo
 
struct  TexgenNode
 
struct  TextNode
 A node that renders text to screen. More...
 
class  TextureCache
 
struct  TexturedMesh
 A mesh with positions and texture coordinates. More...
 
struct  TexturedQuad
 A quad mesh with positions and texture coordinates. More...
 
struct  TexturedTriangle
 A triangle mesh with positions and texture coordinates. More...
 
struct  TextureRenderTarget
 Useful abstraction for storing all the data related to a render target. More...
 
class  TextureShare
 GPU-only triple-buffered texture sharing between two QRhi instances in different threads. More...
 
class  TextureShareBackend
 Backend-specific implementation interface for GPU-only texture sharing. More...
 
class  TextureShareBackendBase
 
class  TimerClock
 Wraps GfxContext's shared wall-timer (clock #2, the default). More...
 
struct  Timings
 Messages sent from the execution thread to the rendering thread. More...
 
class  TripleBufferIndex
 
struct  UYVY422Decoder
 Decodes UYVY422 video, mostly used for NDI. More...
 
struct  UYVYComputeEncoder
 Compute-shader RGBA -> UYVY (2vuy) encoder targeting an external SSBO. More...
 
struct  UYVYEncoder
 GPU RGBA->UYVY encoder (packed 4:2:2). More...
 
struct  V210ComputeEncoder
 Compute-shader RGBA -> v210 encoder targeting an external SSBO. More...
 
struct  V210Decoder
 Decodes 10-bit 4:2:2 YCbCr packed in v210 (SMPTE ST 2110-20 / SDI native). More...
 
struct  V210Encoder
 Cross-backend RGBA -> v210 encoder. More...
 
class  VertexFallbackPool
 
struct  VertexFallbackSpec
 
struct  VideoFrameReader
 
struct  VideoFrameShare
 
struct  VideoMaterialUBO
 UBO shared across all video objects. More...
 
class  VideoNode
 Model for rendering a video. More...
 
class  VideoNodeBase
 
class  VideoNodeRenderer
 
struct  VUYADecoder
 Decodes VUYA / VUYX packed 4:4:4 8-bit videos. More...
 
class  Window
 A platform window in which the content is going to be rendered. More...
 
struct  WorldTransformEmit
 
struct  WorldTransformMat4
 
struct  XV30Decoder
 Decodes XV30 packed 4:4:4 10-bit videos. More...
 
struct  Y210Decoder
 Decodes Y210 packed 4:2:2 10-bit videos. More...
 
struct  YUV420Decoder
 Decodes YUV420 videos. More...
 
struct  YUV420P10Decoder
 Decodes YUV420 videos. More...
 
struct  YUV420P12Decoder
 Decodes YUV420 videos. More...
 
struct  YUV422Decoder
 Decodes YUV422 videos. More...
 
struct  YUV422P10Decoder
 Decodes YUV422 videos. More...
 
struct  YUV422P10Encoder
 GPU RGBA -> yuv422p10le encoder (planar 4:2:2, 10-bit). More...
 
struct  YUV422P12Decoder
 Decodes YUV422 videos. More...
 
struct  YUV440Decoder
 Decodes YUV440P planar 4:4:0 8-bit videos. More...
 
struct  YUV444Decoder
 Decodes YUV444P videos. More...
 
struct  YUV444P10Decoder
 Decodes YUV444P10 videos. More...
 
struct  YUV444P12Decoder
 Decodes YUV444P12 videos. More...
 
struct  YUVA420Decoder
 Decodes YUVA420P videos. More...
 
struct  YUVA444Decoder
 Decodes YUVA444P videos. More...
 
struct  YUVA444P10Decoder
 Decodes YUVA444P10 videos. More...
 
struct  YUVA444P12Decoder
 Decodes YUVA444P12 videos. More...
 
struct  YUVPlanarEncoder
 Generic 3-plane planar YCbCr encoder (8 or 10 bit, 4:2:2 or 4:2:0). More...
 
struct  YUY2Encoder
 GPU RGBA->YUY2 encoder (packed 4:2:2, NTV2_FBF_8BIT_YCBCR_YUY2). More...
 
struct  YUYV422Decoder
 Decodes YUYV422 video. More...
 

Typedefs

using Vertex = score::gfx::Node *
 
using GraphImpl = boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, Vertex, Process::CableType >
 
using VertexMap = ossia::hash_map< score::gfx::Node *, GraphImpl::vertex_descriptor >
 
using FunctionMessage = std::function< void(score::gfx::Node &)>
 
using gfx_input = ossia::variant< ossia::monostate, ossia::value, ossia::audio_vector, ossia::render_target_spec, ossia::transform3d, FunctionMessage, ossia::buffer_spec >
 
using PassMap = ossia::small_vector< std::pair< Edge *, Pass >, 2 >
 
using PassOutput = ossia::variant< PersistSampler, TextureRenderTarget >
 

Enumerations

enum class  CameraProjectionMode : int { Perspective = 0 , Orthographic = 1 , Fulldome = 2 }
 
enum  ImageMode { Single , Clamped , Tiled , Mirrored }
 
enum  GraphicsApi {
  Null , OpenGL , Vulkan , D3D11 ,
  Metal , D3D12
}
 Available graphics APIs to use.
 
enum class  SharedDeviceMode { Owned , Cached }
 Who owns the imported Vulkan device behind a RenderState. More...
 
enum class  BufferCopyBarrier { Auto , None }
 Copy the contents of one GPU buffer to another. More...
 
enum class  ReadbackPath { Unsupported , HostCopy , Import }
 
enum  ScaleMode { Original , BlackBars , Fill , Stretch }
 How to resize a texture to adapt it to a viewport.
 
enum  PlaybackMode { AutoPlayback , Direct , FrameQueue }
 How to choose the video renderer.
 
enum class  Types : int8_t {
  Empty , Int , Float , Vec2 ,
  Vec3 , Vec4 , Image , Audio ,
  Camera , Geometry , Buffer , Scene
}
 
enum class  Flag : uint32_t {
  GrabsFromSource = (1 << 0) , SamplableDepth = (1 << 1) , TextureArray = (1 << 2) , StorageImage = (1 << 3) ,
  IndirectDraw = (1 << 4) , MultiView = (1 << 5) , DepthOnly = (1 << 6) , UniformBuffer = (1 << 7) ,
  ThreeDimensional = (1 << 8) , Cubemap = (1 << 9)
}
 

Functions

void packCameraUBO (CameraUBOData &out, const ossia::camera_component &cam, const QMatrix4x4 &worldTransform, QSize renderSize, float timeSeconds, float aspectOverride)
 
constexpr int64_t cameraAuxByteSize (std::size_t cameraCount) noexcept
 
void writeMat4 (float dst[16], const QMatrix4x4 &src)
 
void setReverseZPerspective (QMatrix4x4 &out, float fovYDeg, float aspect, float nearPlane, float farPlane)
 
void setReverseZOrthographic (QMatrix4x4 &out, float halfWidth, float halfHeight, float nearPlane, float farPlane)
 
void applyTo (const CaptureAdjust &a, CaptureMaterialUBO &ubo) noexcept
 Fills the correction half of ubo. The geometry half is the caller's.
 
void adjustCaptureReference (const CaptureAdjust &a, float rgb[3]) noexcept
 The corrections, on the CPU, in the same order the shader applies them.
 
bool buftrace_enabled ()
 
std::unique_ptr< GPUVideoDecodercreateGPUVideoDecoder (Video::ImageFormat &format, const std::string &filter={})
 Creates the appropriate GPUVideoDecoder for a given pixel format.
 
bool nv12ExternalOesUsable (QRhi::Implementation backend) noexcept
 
QByteArray toExternalSamplerEssl (QByteArray glsl)
 
QString packedBitfieldFilter (const PackedBitfieldLayout &l)
 
std::unique_ptr< GPUVideoDecodermakePackedBitfieldDecoder (const PackedBitfieldLayout &l, Video::ImageFormat &d)
 Convenience: the decoder for a packed-bitfield format.
 
std::unique_ptr< GPUVideoDecodermakeWireDecoder (score::gfx::interop::VideoPixelFormat fmt, Video::ImageFormat &d)
 
std::unique_ptr< GPUVideoEncodermakeWireEncoder (score::gfx::interop::VideoPixelFormat fmt)
 
std::unique_ptr< ComputeEncodermakeWireComputeEncoder (score::gfx::interop::VideoPixelFormat fmt)
 
bool wireComputeSupports (score::gfx::interop::VideoPixelFormat fmt, int width)
 
template<typename Graph_T , typename IO >
void print_graph (Graph_T &g, IO &stream)
 
std::string hwCodecName (const char *codec_name, AVHWDeviceType device)
 Delegates to Video::hwCodecName (score-plugin-gfx wrapper)
 
bool codecSupportsHWPixelFormat (AVCodecID codec_id, AVPixelFormat pix_fmt)
 Delegates to Video::codecSupportsHWPixelFormat (score-plugin-gfx wrapper)
 
AVPixelFormat selectHardwareAcceleration (score::gfx::GraphicsApi api, AVCodecID codec_id, QRhi *rhi=nullptr)
 Picks the best HW accel for the given API/codec, using QRhi for vendor detection.
 
std::unique_ptr< TextureShareBackendcreateTextureShareBackend (QRhi *producer, QRhi *consumer)
 
int64_t glslTypeSizeBytes (std::string_view type) noexcept
 Byte size of a single GLSL primitive type as used for SSBO element strides in this codebase.
 
int64_t std430ArrayStride (std::string_view type) noexcept
 std430 array stride for a GLSL primitive type when laid out as T array[] inside a shader storage block.
 
int64_t std430LayoutSize (const std::vector< isf::storage_input::layout_field > &layout) noexcept
 Compute the std430 element size of a layout (vector of {name,type} field entries), each field rounded up to 16 bytes per the array-of-struct alignment rule. Used by AUXILIARY blocks and by the user-defined struct lookup in glslTypeSizeBytes.
 
int64_t glslTypeSizeBytes (std::string_view type, const isf::descriptor &d) noexcept
 Same as glslTypeSizeBytes, but resolves user-defined types from the descriptor's TYPES section. Falls back to the built-in size table for primitives, then to descriptor.types lookup for struct names. The std430 size of a struct is the sum of its fields' sizes, each rounded up to a 16-byte boundary (matching the array-of-struct alignment rule already used by std430LayoutSize for AUXILIARY blocks). Returns 16 (the lenient default) for unresolved names.
 
int64_t std430ArrayStride (std::string_view type, const isf::descriptor &d) noexcept
 Same as std430ArrayStride, but resolves user-defined struct names against the descriptor's TYPES section. Falls back to glslTypeSizeBytes(type, d) for non-vec3 primitives and structs.
 
QRhiShaderResourceBinding::StageFlags visibilityToStages (std::string_view visibility) noexcept
 Decode an isf::storage_input::visibility string to Qt RHI stage flags.
 
void collectGraphicsStorageResources (const isf::descriptor &desc, int firstBinding, GraphicsStorageResources &out)
 Walk desc.inputs once and populate out with the storage buffers and images declared by the shader.
 
void ensureStorageResources (QRhi &rhi, QRhiResourceUpdateBatch &res, const RenderList &renderer, const isf::descriptor &desc, GraphicsStorageResources &store, QSize renderSize)
 Create missing buffers and textures.
 
QVarLengthArray< QRhiShaderResourceBinding, 8 > buildExtraBindings (const GraphicsStorageResources &store)
 Produce the QRhiShaderResourceBinding list for the graphics pipeline.
 
void bindUpstreamBuffers (RenderList &renderer, const std::vector< Port * > &inputPorts, GraphicsStorageResources &store, QRhiShaderResourceBindings *srb=nullptr)
 Wire read-only SSBOs to upstream geometry buffers.
 
void bindUpstreamImagesFromGeometry (GraphicsStorageResources &store, const ossia::geometry &geometry, QRhiShaderResourceBindings *srb=nullptr)
 Wire read-only csf_image_input storage images to an upstream geometry's published auxiliary_textures.
 
void bindUpstreamBuffersFromGeometry (QRhi &rhi, QRhiResourceUpdateBatch &res, GraphicsStorageResources &store, const ossia::geometry &geometry, QRhiShaderResourceBindings *srb=nullptr)
 Wire INPUTS storage_input / uniform_input bindings to upstream geometry's published auxiliary_buffers list (name-match).
 
void swapPersistentSSBOsState (GraphicsStorageResources &store)
 Swap current/prev pointers in store without touching any SRB.
 
void reapplyStorageBindings (const GraphicsStorageResources &store, QRhiShaderResourceBindings &srb)
 Re-apply the current persistent-storage state to a single SRB.
 
void swapPersistentSSBOs (GraphicsStorageResources &store, QRhiShaderResourceBindings &srb)
 Swap current/prev for all persistent SSBOs and storage images, then update the SRB.
 
template<typename F >
void walk_descriptor_inputs (const isf::descriptor &desc, port_counts start, F &&fn)
 
template<typename F >
void walk_descriptor_inputs (const isf::descriptor &desc, F &&fn)
 
void noteZeroCountSlotsSkipped (int skipped) noexcept
 
uint64_t zeroCountSlotsSkippedTotal () noexcept
 
void drawMeshWithOptionalIndirect (const Mesh &mesh, const MeshBuffers &bufs, QRhiCommandBuffer &cb) noexcept
 Draw a mesh, using indirect multi-draw when available in MeshBuffers.
 
bool bufferSizeIsExpressible (int64_t byte_size) noexcept
 
bool drawCommandPaints (const ossia::geometry::draw_command &cmd) noexcept
 
 Q_DECLARE_OPERATORS_FOR_FLAGS (Mesh::Flags)
 
void defaultPassesInit (PassMap &passes, const std::vector< Edge * > &edges, RenderList &renderer, const Mesh &mesh, const QShader &v, const QShader &f, QRhiBuffer *processUBO, QRhiBuffer *matUBO, std::span< const Sampler > samplers, std::span< QRhiShaderResourceBinding > additionalBindings)
 
void defaultRenderPass (RenderList &renderer, const Mesh &mesh, const MeshBuffers &bufs, QRhiCommandBuffer &cb, Edge &edge, PassMap &passes)
 
void quadRenderPass (RenderList &renderer, const MeshBuffers &bufs, QRhiCommandBuffer &cb, Edge &edge, PassMap &passes)
 
QRhiGraphicsPipeline::CompareOp toCompareOp (std::string_view s) noexcept
 
float depthClearForCompare (QRhiGraphicsPipeline::CompareOp compare) noexcept
 
float depthClearForState (const isf::pipeline_state &state) noexcept
 
QRhiGraphicsPipeline::CullMode toCullMode (std::string_view s) noexcept
 
QRhiGraphicsPipeline::FrontFace toFrontFace (std::string_view s) noexcept
 
QRhiGraphicsPipeline::PolygonMode toPolygonMode (std::string_view s) noexcept
 
QRhiGraphicsPipeline::Topology toTopology (std::string_view s) noexcept
 
QRhiGraphicsPipeline::BlendFactor toBlendFactor (std::string_view s) noexcept
 
QRhiGraphicsPipeline::BlendOp toBlendOp (std::string_view s) noexcept
 
QRhiGraphicsPipeline::StencilOp toStencilOp (std::string_view s) noexcept
 
QRhiGraphicsPipeline::ColorMask toColorMask (std::string_view s) noexcept
 
QRhiGraphicsPipeline::TargetBlend toTargetBlend (const isf::blend_attachment &b) noexcept
 
QRhiGraphicsPipeline::StencilOpState toStencilOpState (const isf::stencil_op_state &s) noexcept
 
isf::pipeline_state mergeState (isf::pipeline_state base, const isf::pipeline_state &over)
 
bool stateAffectsPipeline (const isf::pipeline_state &s) noexcept
 
void applyPipelineState (QRhiGraphicsPipeline &pip, const isf::pipeline_state &state, int colorAttachmentCount, bool depthAttachmentAvailable, bool wantsDepthByDefault) noexcept
 
std::shared_ptr< RenderStateimportRenderState (QSize sz, QRhi *rhi)
 
std::vector< SamplerinitAudioTextures (RenderList &renderer, std::list< AudioTexture > &textures)
 
QRhiTexture::Format imageTextureFormat (const QRhi &rhi) noexcept
 Texture format to use for images uploaded from the CPU.
 
QImage adaptImageFormat (QImage img, QRhiTexture::Format fmt)
 Put an image in the byte order imageTextureFormat() asks for.
 
std::shared_ptr< RenderStatecreateRenderState (GraphicsApi graphicsApi, QSize sz, QWindow *window, SharedDeviceMode deviceMode=SharedDeviceMode::Owned)
 
QRhiBuffer::UsageFlags compatibleBufferUsage (QRhi &rhi, QRhiBuffer::UsageFlags usage) noexcept
 Drop a StorageBuffer usage the backend cannot actually honour.
 
bool indirectDrawBreaksMultiView (GraphicsApi api, int multiViewCount) noexcept
 Whether a GPU indirect draw silently loses multiview on this backend.
 
bool drawIndirectCountUsable (GraphicsApi api, int multiViewCount) noexcept
 Whether the GPU-count draw path (drawIndexedIndirectCount) is usable.
 
bool viewIndexNeedsPassIndexFallback (GraphicsApi api, const QShaderVersion &version, int multiViewCount) noexcept
 Whether MULTIVIEW must be emulated with one pass per view.
 
bool clearBufferMetal (QRhi &, QRhiCommandBuffer &, QRhiBuffer *, quint32, quint32, quint32)
 
void copyBufferMetal (QRhi &, QRhiCommandBuffer &, QRhiBuffer *, QRhiBuffer *, int, int, int)
 
void copyBufferRegionsMetal (QRhi &, QRhiCommandBuffer &, QRhiBuffer *, QRhiBuffer *, const BufferCopyRegion *, int)
 
void insertComputeBarrier (QRhi &rhi, QRhiCommandBuffer &cb)
 Insert a compute-to-compute memory barrier.
 
bool dispatchComputeLayeredImages (QRhi &rhi, QRhiCommandBuffer &cb, QRhiShaderResourceBindings &srb, int x, int y, int z)
 Dispatch a compute pass, working around Qt's non-layered bind of layered (3D / cube / array) storage images on the OpenGL backend.
 
void beginBufferCopyBarrier (QRhi &rhi, QRhiCommandBuffer &cb)
 
void endBufferCopyBarrier (QRhi &rhi, QRhiCommandBuffer &cb)
 
void copyBuffer (QRhi &rhi, QRhiCommandBuffer &cb, QRhiBuffer *src, QRhiBuffer *dst, int size, int srcOffset, int dstOffset, BufferCopyBarrier barrier)
 
void copyBufferRegions (QRhi &rhi, QRhiCommandBuffer &cb, QRhiBuffer *src, QRhiBuffer *dst, const BufferCopyRegion *regions, int count, BufferCopyBarrier barrier)
 
template<typename R = QRhi>
bool rhiSupportsDrawIndirectCount (R &rhi) noexcept
 
template<typename R = QRhi>
bool rhiSupportsDispatchIndirect (R &rhi) noexcept
 QRhi::DispatchIndirect reported by the device; same convention as above.
 
template<typename CB = QRhiCommandBuffer>
bool drawIndirectCountCompat (CB &cb, bool indexed, QRhiBuffer *indirectBuffer, quint32 indirectOffset, QRhiBuffer *countBuffer, quint32 countOffset, quint32 maxDrawCount, quint32 stride) noexcept
 
template<typename CB = QRhiCommandBuffer>
bool dispatchIndirectCompat (CB &cb, QRhiBuffer *argsBuffer, quint32 argsOffset) noexcept
 
ReadbackPath readbackPath (QRhi &rhi) noexcept
 
bool canReadbackToHostMemory (QRhi &rhi) noexcept
 
std::size_t readbackHostMemoryAlignment (QRhi &rhi) noexcept
 
bool readbackTextureSupported (QRhi &rhi, QRhiTexture &src, std::size_t dstBytes) noexcept
 
ReadbackTargetcreateReadbackTarget (QRhi &rhi, void *dst, std::size_t bytes)
 
void destroyReadbackTarget (ReadbackTarget *t)
 
std::size_t readbackDstOffsetAlignment (QRhi &rhi, QRhiTexture &src) noexcept
 
bool readbackTextureToHost (QRhi &rhi, QRhiCommandBuffer &cb, QRhiTexture &src, ReadbackTarget &t, std::size_t dstOffset)
 
bool finishReadbackToHost (QRhi &rhi, ReadbackTarget &t)
 
std::shared_ptr< ossia::geometry > primitiveToGeometry (const ossia::mesh_primitive &prim)
 
MaterialGPU packMaterial (const ossia::material_component &mc)
 
MaterialExtensionsGPU packMaterialExtensions (const ossia::material_component &mc)
 
void flattenScene (const ossia::scene_spec &scene, FlatScene &out, float aspectRatio)
 
constexpr uint32_t tex_ref_none ()
 
constexpr uint32_t tex_ref_static (uint32_t bucket, uint32_t layer)
 
constexpr uint32_t tex_ref_dynamic (uint32_t slot)
 
QByteArray hlslIntrinsicCollision (const QByteArray &raw) noexcept
 The identifier a shader declares that collides with an HLSL intrinsic.
 
std::optional< DecodedImagedecodeImageFromPath (const QString &path)
 
std::optional< DecodedImagedecodeImageFromMemory (const QByteArray &bytes, const QString &mime_hint)
 
QRhiTexture * uploadImageToTexture (QRhi &rhi, QRhiResourceUpdateBatch &batch, const QImage &img, bool srgb, const QString &debug_name)
 
QRhiTexture * loadAndUploadTexture (QRhi &rhi, QRhiResourceUpdateBatch &batch, const QString &path, bool srgb)
 
QRhiTexture * loadAndUploadTexture (QRhi &rhi, QRhiResourceUpdateBatch &batch, const QByteArray &bytes, const QString &mime_hint, bool srgb)
 
TextureRenderTarget createRenderTarget (const RenderState &state, QRhiTexture *tex, int samples, bool depth, bool samplableDepth=false)
 Create a render target from a texture.
 
TextureRenderTarget createRenderTarget (const RenderState &state, QRhiTexture::Format fmt, QSize sz, int samples, bool depth, bool samplableDepth=false, QRhiTexture::Flags flags={})
 Create a render target from a texture format and size.
 
TextureRenderTarget createRenderTarget (const RenderState &state, std::span< QRhiTexture *const > colorTextures, QRhiTexture *depthTexture, int samples)
 Create a render target with multiple color attachments and optional sampleable depth.
 
void replaceBuffer (std::vector< QRhiShaderResourceBinding > &tmp, int binding, QRhiBuffer *newBuffer)
 
void replaceSampler (std::vector< QRhiShaderResourceBinding > &tmp, int binding, QRhiSampler *newSampler)
 
void replaceTexture (std::vector< QRhiShaderResourceBinding > &tmp, int binding, QRhiTexture *newTexture)
 
void replaceBuffer (QRhiShaderResourceBindings &srb, int binding, QRhiBuffer *newBuffer)
 
void replaceSampler (QRhiShaderResourceBindings &srb, int binding, QRhiSampler *newSampler)
 
void replaceTexture (QRhiShaderResourceBindings &srb, int binding, QRhiTexture *newTexture)
 
void replaceSampler (QRhiShaderResourceBindings &, QRhiSampler *oldSampler, QRhiSampler *newSampler)
 Replace a sampler.
 
void replaceSamplerAndTexture (QRhiShaderResourceBindings &, QRhiSampler *oldSampler, QRhiSampler *newSampler, QRhiTexture *newTexture)
 Replace both sampler and texture in a SRC.
 
void replaceTexture (QRhiShaderResourceBindings &, QRhiSampler *sampler, QRhiTexture *newTexture)
 Replace the texture currently bound to a sampler.
 
void replaceTexture (QRhiShaderResourceBindings &srb, QRhiTexture *old_tex, QRhiTexture *new_tex)
 Replace a texture by another in a set of bindings.
 
const ossia::geometry::attribute * findGeometryAttribute (const ossia::geometry &geom, std::string_view name, std::string_view semantic_key)
 Match a (name, semantic) request to an upstream geometry attribute.
 
bool remapPipelineVertexInputs (QRhiGraphicsPipeline &pip, const QShader &vertexShader, const ossia::geometry &geom)
 Remap a pipeline's vertex input layout using semantic matching.
 
bool remapPipelineVertexInputs (QRhiGraphicsPipeline &pip, const QShader &vertexShader, const ossia::geometry &geom, const isf::descriptor &desc)
 Same as above, but honours explicit SEMANTIC on each VERTEX_INPUTS entry from the isf descriptor when present.
 
bool remapPipelineVertexInputs (QRhiGraphicsPipeline &pip, const QShader &vertexShader, const ossia::geometry &geom, const isf::descriptor &desc, QRhi &rhi, VertexFallbackPool &pool, QRhiResourceUpdateBatch &batch, FallbackBindingPlan &outPlan)
 Fallback-aware overload: the strict-matching behaviour of the overload above, extended so VERTEX_INPUTS entries with "REQUIRED": false silently resolve to a shared identity buffer from the pool when their semantic is absent upstream.
 
Pipeline buildPipeline (const RenderList &renderer, const Mesh &mesh, const QShader &vertexS, const QShader &fragmentS, const TextureRenderTarget &rt, QRhiShaderResourceBindings *srb)
 Lower-level buildPipeline variant: bring your own SRB.
 
QRhiShaderResourceBindings * createDefaultBindings (const RenderList &renderer, const TextureRenderTarget &rt, QRhiBuffer *processUBO, QRhiBuffer *materialUBO, std::span< const Sampler > samplers, std::span< QRhiShaderResourceBinding > additionalBindings={})
 Create bindings following the score conventions for shaders and materials.
 
Pipeline buildPipeline (const RenderList &renderer, const Mesh &mesh, const QShader &vertexS, const QShader &fragmentS, const TextureRenderTarget &rt, QRhiBuffer *processUBO, QRhiBuffer *materialUBO, std::span< const Sampler > samplers, std::span< QRhiShaderResourceBinding > additionalBindings={})
 Create a render pipeline following the score conventions for shaders and materials.
 
Pipeline buildPipelineWithState (const RenderList &renderer, const Mesh &mesh, const QShader &vertexS, const QShader &fragmentS, const TextureRenderTarget &rt, QRhiBuffer *processUBO, QRhiBuffer *materialUBO, std::span< const Sampler > samplers, std::span< QRhiShaderResourceBinding > extraBindings, const isf::pipeline_state &state, int multiViewCount=0, bool useShadingRate=false)
 Create a render pipeline applying pipeline_state from an ISF descriptor.
 
std::pair< QShader, QShader > makeShaders (const RenderState &v, QString vert, QString frag, int multiViewCount=0)
 Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
 
QShader makeCompute (const RenderState &v, QString compt)
 Compile a compute shader.
 
QSize resizeTextureSize (QSize img, int min, int max) noexcept
 Resize the size of a texture to fit within GPU limits.
 
QImage resizeTexture (const QImage &img, int min, int max) noexcept
 Resize a texture to fit within GPU limits.
 
QSizeF computeScaleForMeshSizing (score::gfx::ScaleMode mode, QSizeF viewport, QSizeF texture)
 Compute the scale to apply to a texture so that it fits in a GL viewport.
 
QSizeF computeScaleForTexcoordSizing (score::gfx::ScaleMode mode, QSizeF viewport, QSizeF texture)
 Compute the scale to apply to a texture rendered to a quad the size of viewport.
 
std::vector< SamplerinitInputSamplers (const score::gfx::Node &node, RenderList &renderer, const std::vector< Port * > &ports, const isf::descriptor *desc)
 
TextureRenderTarget createDepthOnlyRenderTarget (const RenderState &state, QSize sz, int samples, bool samplableDepth=true, QRhiTexture::Format depthFmt=QRhiTexture::D32F)
 Create a depth-only render target.
 
TextureRenderTarget createLayeredRenderTarget (const RenderState &state, QRhiTexture *colorTextureArray, int renderLayer, QRhiTexture *depthTexture, int samples)
 Create a render target that targets a single layer of a texture array.
 
TextureRenderTarget createMultiViewRenderTarget (const RenderState &state, QRhiTexture *colorTextureArray, int multiViewCount, QRhiTexture *depthTextureArray, int samples)
 Create a multiview render target (single RT drawing N views at once).
 
TextureRenderTarget createDepthOnlyRenderTarget (const RenderState &state, QRhiTexture *externalDepthTexture, int samples, bool samplableDepth=true)
 Create a depth-only render target around an EXTERNAL depth texture.
 
TextureRenderTarget createLayeredRenderTarget (const RenderState &state, std::span< QRhiTexture *const > colorTextures, int renderLayer, QRhiTexture *depthTexture, int samples)
 Multi-attachment (MRT) layered render target.
 
TextureRenderTarget createMultiViewRenderTarget (const RenderState &state, std::span< QRhiTexture *const > colorTextures, int multiViewCount, QRhiTexture *depthTextureArray, int samples)
 Multi-attachment (MRT) multiview render target.
 
QRhiTexture::Format parseOutputFormat (const std::string &fmt, QRhiTexture::Format fallback) noexcept
 Map an ISF/CSF FORMAT string to a QRhiTexture::Format.
 
QRhiSampler * makeSampler (QRhi &rhi, const isf::sampler_config &cfg)
 Build a QRhiSampler from an isf::sampler_config.
 
QRhiBuffer::Type bufferTypeFor (QRhiBuffer::UsageFlags usage, QRhiBuffer::Type nonDynamic=QRhiBuffer::Immutable) noexcept
 The QRhi buffer type a usage flag is allowed to be created with.
 
void copyMatrix (const QMatrix4x4 &mat, float *ptr) noexcept
 
void copyMatrix (const QMatrix3x3 &mat, float *ptr) noexcept
 
void updateDynamicBufferWithStoredData (QRhiResourceUpdateBatch *ub, QRhiBuffer *buf, int offset, int64_t bytesize, const char *data)
 Schedule a Dynamic buffer update when we can guarantee the buffer outlives the frame.
 
void updateDynamicBufferWithStoredData (QRhiResourceUpdateBatch *ub, QRhiBuffer *buf, int offset, QByteArray b)
 
void uploadStaticBufferWithStoredData (QRhiResourceUpdateBatch *ub, QRhiBuffer *buf, int offset, int64_t bytesize, const char *data)
 Schedule a Static buffer update when we can guarantee the buffer outlives the frame.
 
void uploadStaticBufferWithStoredData (QRhiResourceUpdateBatch *ub, QRhiBuffer *buf, int offset, QByteArray b)
 
std::optional< VertexFallbackSpecresolveVertexFallback (ossia::attribute_semantic semantic, std::string_view decl_type, const std::vector< double > &user_default) noexcept
 
uint64_t hashVertexFallback (const VertexFallbackSpec &spec) noexcept
 
uint64_t hash_qstring (const QString &s) noexcept
 
uint64_t hash_qbytearray (const QByteArray &b) noexcept
 

Variables

constexpr bool rhiHasDrawIndirectCount = detail::rhi_has_indirect_count<QRhiCommandBuffer>::value
 
constexpr bool rhiHasDispatchIndirect = detail::rhi_has_dispatch_indirect<QRhiCommandBuffer>::value
 

Enumeration Type Documentation

◆ BufferCopyBarrier

enum class score::gfx::BufferCopyBarrier
strong

Copy the contents of one GPU buffer to another.

Performs a GPU-side buffer-to-buffer copy of size bytes from src + srcOffset to dst + dstOffset. Both buffers must already be created and large enough to satisfy the requested region. Must be called between beginExternal() and endExternal().

The source and destination buffers must NOT overlap (the copy is unordered when src == dst).

Per-backend behaviour:

  • Vulkan : vkCmdCopyBuffer
  • OpenGL : glCopyBufferSubData
  • D3D12 : CopyBufferRegion
  • D3D11 : CopySubresourceRegion (offsets supported via D3D11_BOX)
  • Metal : MTLBlitCommandEncoder copyFromBuffer

◆ ReadbackPath

enum class score::gfx::ReadbackPath
strong

How the backend reaches caller-owned memory. Vulkan and D3D12 import the pages and the GPU writes them directly; OpenGL and D3D11 have no import and must land in a driver buffer that is then memcpy'd, with the fence wait falling on the render thread.

This is a performance property, not a capability one, and it decides the default: against plain QRhi staging, Import is cheaper per frame, while HostCopy is a small regression.

Enumerator
HostCopy 

driver buffer + memcpy + fence on the render thread

Import 

caller pages imported; GPU writes them directly

◆ SharedDeviceMode

enum class score::gfx::SharedDeviceMode
strong

Who owns the imported Vulkan device behind a RenderState.

Owned is the default: one vkCreateDevice per RenderState, one vkDestroyDevice when it goes away. Cached takes a reference on the process-wide SharedVulkanDeviceCache instead, so a create/destroy pair is not paid every time the state is rebuilt. Only the shader previews opt in — they are rebuilt on every selection, whereas outputs and encoders are long-lived.

Function Documentation

◆ adaptImageFormat()

SCORE_PLUGIN_GFX_EXPORT QImage score::gfx::adaptImageFormat ( QImage  img,
QRhiTexture::Format  fmt 
)

Put an image in the byte order imageTextureFormat() asks for.

QRhi uploads a QImage's bits as-is, so the two have to agree. Premultiplication is preserved: only the channel order changes.

◆ adjustCaptureReference()

void score::gfx::adjustCaptureReference ( const CaptureAdjust a,
float  rgb[3] 
)
inlinenoexcept

The corrections, on the CPU, in the same order the shader applies them.

This is the specification: CaptureAdjustGLSL.hpp implements it on the GPU, and a test can only check the two agree if one of them is checkable. Keep them in step – a divergence shows up as the picture changing when the capture rung changes, which looks like a capture bug.

◆ beginBufferCopyBarrier()

void score::gfx::beginBufferCopyBarrier ( QRhi &  rhi,
QRhiCommandBuffer &  cb 
)

Emit the {compute,transfer}→transfer barrier that must precede a buffer copy. The compute half orders the copy after a compute shader that just produced the data; the transfer half orders it after the staging copies QRhi emits for a QRhiResourceUpdateBatch submitted earlier in the same command buffer. That second half is not optional: these helpers record through beginExternal(), so QRhi's own per-buffer barrier tracking never sees them and cannot order them against its own uploads. Pair with endBufferCopyBarrier(). No-op on backends that handle the transition implicitly (D3D11, Metal).

◆ bindUpstreamBuffers()

void score::gfx::bindUpstreamBuffers ( RenderList renderer,
const std::vector< Port * > &  inputPorts,
GraphicsStorageResources store,
QRhiShaderResourceBindings *  srb = nullptr 
)

Wire read-only SSBOs to upstream geometry buffers.

When a storage_input is declared as read_only AND the upstream node supplies a buffer on the port, the binding is rewired to point at the upstream's QRhiBuffer (no allocation needed). Called each frame to track port changes.

◆ bindUpstreamBuffersFromGeometry()

void score::gfx::bindUpstreamBuffersFromGeometry ( QRhi &  rhi,
QRhiResourceUpdateBatch &  res,
GraphicsStorageResources store,
const ossia::geometry &  geometry,
QRhiShaderResourceBindings *  srb = nullptr 
)

Wire INPUTS storage_input / uniform_input bindings to upstream geometry's published auxiliary_buffers list (name-match).

SSBO/UBO sibling of bindUpstreamImagesFromGeometry. ScenePreprocessor publishes scene_lights / world_transforms / per_draws / scene_materials / scene_counts / scene_light_indices / camera UBO / env UBO as named aux buffers travelling along the geometry edge — flattened-scene shaders (classic_pbr et al.) declare matching INPUTS storage_input/uniform_input blocks and the runtime resolves them by name.

Without this, INPUTS storage_input/uniform_input that go through the m_storage path stay at the 16-byte placeholder allocated by ensureStorageResources for owned SSBOs — vertices read a zero PerDraw, multiply by a zero world_transforms matrix, and collapse to origin. (Indirect-draw storage_inputs are skipped — they have no shader binding.)

For CPU-backed aux buffers a fresh QRhiBuffer is allocated and the data uploaded immediately into res; the entry's owned flag is updated so release() cleans up correctly. For GPU-backed aux buffers we just adopt the upstream handle (owned=false).

Patches the SRB in-place when a target SRB is provided; idempotent so multi-SRB callers can invoke once per SRB without re-running the lookup.

◆ bindUpstreamImagesFromGeometry()

void score::gfx::bindUpstreamImagesFromGeometry ( GraphicsStorageResources store,
const ossia::geometry &  geometry,
QRhiShaderResourceBindings *  srb = nullptr 
)

Wire read-only csf_image_input storage images to an upstream geometry's published auxiliary_textures.

Symmetric to bindUpstreamBuffers for SSBOs: when a csf_image_input is declared read_only AND the upstream geometry publishes a storage image with the same name (e.g. an upstream CSF wrote to it via image_input with write_only/read_write), this swaps the storage image's texture pointer to the upstream's published handle and frees the auto-allocated placeholder we created in ensureStorageResources.

Without this, every read_only csf_image_input INPUTS in a downstream RawRaster / ISF stage reads from its OWN zero-initialised texture instead of the upstream's actual contents — silently broken.

Called per-frame; idempotent. When srb is non-null, patches the binding in-place via replaceTexture. The lookup is purely by name match against geometry.auxiliary_textures (the same name-match pattern used by RawRaster's m_auxTextureSamplers rebind path).

◆ bufferTypeFor()

QRhiBuffer::Type score::gfx::bufferTypeFor ( QRhiBuffer::UsageFlags  usage,
QRhiBuffer::Type  nonDynamic = QRhiBuffer::Immutable 
)
inlinenoexcept

The QRhi buffer type a usage flag is allowed to be created with.

A uniform buffer must be Dynamic on D3D11: QD3D11Buffer::create() rejects anything else outright ("UniformBuffer must always be combined with Dynamic on D3D11"), leaves its ID3D11Buffer null and returns false. OpenGL ES says the same thing through the NonDynamicUniformBuffers feature. Every UBO this plugin allocates from a literal is already Dynamic; this exists for the few places that pick the usage at RUNTIME from a shader's declaration, where an unconditional Immutable would silently give a null-backed buffer on D3D11 and bind it anyway. Everything else keeps nonDynamic, which for a storage or vertex buffer is what it wants (and Dynamic + StorageBuffer is itself rejected).

◆ buildExtraBindings()

QVarLengthArray< QRhiShaderResourceBinding, 8 > score::gfx::buildExtraBindings ( const GraphicsStorageResources store)

Produce the QRhiShaderResourceBinding list for the graphics pipeline.

Call this from inside addOutputPass() after buildPipeline() has been set up. The result is concatenated with the standard bindings (sampler, material, processUBO, etc.) via the additionalBindings span in createDefaultBindings.

◆ buildPipeline()

Pipeline score::gfx::buildPipeline ( const RenderList renderer,
const Mesh mesh,
const QShader &  vertexS,
const QShader &  fragmentS,
const TextureRenderTarget rt,
QRhiShaderResourceBindings *  srb 
)

Lower-level buildPipeline variant: bring your own SRB.

The returned Pipeline::srb equals the srb you passed — no ownership transfer. Useful when the caller wants to share a pipeline across multiple Passes that each have their own SRB (layout-compatible with this one per QRhi contract); the pipeline's stored SRB is only used for layout extraction at create() time and never dereferenced at draw time.

◆ buildPipelineWithState()

Pipeline score::gfx::buildPipelineWithState ( const RenderList renderer,
const Mesh mesh,
const QShader &  vertexS,
const QShader &  fragmentS,
const TextureRenderTarget rt,
QRhiBuffer *  processUBO,
QRhiBuffer *  materialUBO,
std::span< const Sampler samplers,
std::span< QRhiShaderResourceBinding >  extraBindings,
const isf::pipeline_state &  state,
int  multiViewCount = 0,
bool  useShadingRate = false 
)

Create a render pipeline applying pipeline_state from an ISF descriptor.

Depth test / depth write and the anyNodeRequiresDepth() fallback are all driven by state here. When state is empty (all fields nullopt), behaviour matches the variant above exactly.

extraBindings is typically the result of IsfBindingsBuilder::buildExtraBindings(). multiViewCount >= 2 activates multiview rendering (requires state.caps.multiview).

When useShadingRate == true AND renderer.state.caps.variableRateShading == true, the pipeline gets QRhiGraphicsPipeline::UsesShadingRate. The shading-rate texture / per-draw rate itself is supplied elsewhere (via the render-target attachment's setShadingRateMap or the command- buffer's setShadingRate). Presets opt in; silent no-op when the backend doesn't support VRS.

◆ canReadbackToHostMemory()

bool score::gfx::canReadbackToHostMemory ( QRhi &  rhi)
noexcept

Whether this backend can read a texture straight into caller-owned host memory. Stable per QRhi; query once.

◆ collectGraphicsStorageResources()

void score::gfx::collectGraphicsStorageResources ( const isf::descriptor &  desc,
int  firstBinding,
GraphicsStorageResources out 
)

Walk desc.inputs once and populate out with the storage buffers and images declared by the shader.

Bindings are assigned sequentially starting from firstBinding. Persistent SSBOs consume TWO consecutive bindings.

No GPU resources are allocated here — call ensureStorageResources() later.

◆ compatibleBufferUsage()

QRhiBuffer::UsageFlags score::gfx::compatibleBufferUsage ( QRhi &  rhi,
QRhiBuffer::UsageFlags  usage 
)
inlinenoexcept

Drop a StorageBuffer usage the backend cannot actually honour.

QGles2Buffer::create() picks the target it will run every glBufferData / glBufferSubData through from the usage flags, and StorageBuffer outranks both VertexBuffer and IndirectBuffer (qrhigles2.cpp):

targetForDataOps = GL_ARRAY_BUFFER;
if (usage & IndexBuffer)         targetForDataOps = GL_ELEMENT_ARRAY_BUFFER;
else if (usage & StorageBuffer)  targetForDataOps = GL_SHADER_STORAGE_BUFFER;
else if (usage & IndirectBuffer) targetForDataOps = GL_DRAW_INDIRECT_BUFFER;

GL_SHADER_STORAGE_BUFFER arrived with GL 4.3 / GLES 3.1. macOS caps desktop OpenGL at 4.1, so on Apple's driver the bind and every upload against that target raise GL_INVALID_ENUM and do nothing: glGenBuffers still hands out a name, create() still returns true, and the object never receives a data store or a single byte of content. Nothing in score can see that, because the only thing it can check – create() – succeeded.

The damage lands at draw time and looks like two unrelated bugs:

  • bound as a VERTEX buffer, Apple's GL walks the storeless object and faults inside gleRunVertexSubmitImmediate, EXC_BAD_ACCESS at the attribute's own byte offset (0x0, 0x40, ...);
  • bound as an INDIRECT buffer, the draw reads zeros and rasterises nothing, silently and with an empty error string. Mesa and the NVIDIA driver expose 4.6, so the same code is correct on Linux/OpenGL, which is what makes this look platform-specific rather than backend-specific.

A buffer a shader genuinely reads as an SSBO cannot be rescued here: below 4.3 there are no SSBOs to read. So a StorageBuffer-ONLY usage is returned untouched and fails honestly. This only demotes buffers whose storage role is an ADDITIONAL one alongside a vertex / index / indirect role the backend can still serve – the mesh arena, the geometry VBOs, the MDI command buffer.

◆ createDepthOnlyRenderTarget() [1/2]

TextureRenderTarget score::gfx::createDepthOnlyRenderTarget ( const RenderState state,
QRhiTexture *  externalDepthTexture,
int  samples,
bool  samplableDepth = true 
)

Create a depth-only render target around an EXTERNAL depth texture.

Builds the RT around externalDepthTexture (caller-allocated, already created) instead of allocating its own. Use this when the depth texture is named/owned by the node (so textureForOutput() can return it).

externalDepthTexture may be a plain 2D depth texture or a TextureArray (layered / shadow-cascade depth). It becomes ret.depthTexture and is released with the RT.

◆ createDepthOnlyRenderTarget() [2/2]

TextureRenderTarget score::gfx::createDepthOnlyRenderTarget ( const RenderState state,
QSize  sz,
int  samples,
bool  samplableDepth = true,
QRhiTexture::Format  depthFmt = QRhiTexture::D32F 
)

Create a depth-only render target.

Allocates a sampleable depth texture (samplableDepth=true) or a depth renderbuffer. If the backend rejects color-less render targets, a 1x1 RGBA8 dummy color texture is allocated and stored in the TextureRenderTarget::dummyColorTexture field (owned by the RT).

The resulting TextureRenderTarget has:

  • depthTexture or depthRenderBuffer set (never both)
  • texture == nullptr (depth-only semantics)
  • dummyColorTexture may be non-null on some backends

◆ createGPUVideoDecoder()

SCORE_PLUGIN_GFX_EXPORT std::unique_ptr< GPUVideoDecoder > score::gfx::createGPUVideoDecoder ( Video::ImageFormat format,
const std::string &  filter = {} 
)

Creates the appropriate GPUVideoDecoder for a given pixel format.

This factory centralizes the pixel-format-to-decoder switch statement that was previously duplicated in VideoNodeRenderer and DirectVideoNodeRenderer.

Parameters
formatThe video frame format (width, height, pixel_format)
filterOptional GLSL filter expression to apply in the fragment shader
Returns
A unique_ptr to the created decoder, or nullptr if format is unhandled

◆ createLayeredRenderTarget() [1/2]

TextureRenderTarget score::gfx::createLayeredRenderTarget ( const RenderState state,
QRhiTexture *  colorTextureArray,
int  renderLayer,
QRhiTexture *  depthTexture,
int  samples 
)

Create a render target that targets a single layer of a texture array.

colorTextureArray must have been created with QRhiTexture::TextureArray and at least (renderLayer + 1) layers.

depthTexture may be a regular 2D texture (shared across layers) or nullptr to skip depth (use a renderbuffer instead via createRenderTarget overloads).

◆ createLayeredRenderTarget() [2/2]

TextureRenderTarget score::gfx::createLayeredRenderTarget ( const RenderState state,
std::span< QRhiTexture *const >  colorTextures,
int  renderLayer,
QRhiTexture *  depthTexture,
int  samples 
)

Multi-attachment (MRT) layered render target.

Same as the single-texture overload but attaches ALL colorTextures to the render pass (locations 0..N-1), so the number of attachments matches the pipeline blend-state count (rt.colorAttachmentCount()). Each layered color texture renders to renderLayer; plain 2D textures keep layer 0.

◆ createMultiViewRenderTarget() [1/2]

TextureRenderTarget score::gfx::createMultiViewRenderTarget ( const RenderState state,
QRhiTexture *  colorTextureArray,
int  multiViewCount,
QRhiTexture *  depthTextureArray,
int  samples 
)

Create a multiview render target (single RT drawing N views at once).

colorTextureArray must be a TextureArray with at least multiViewCount layers. depthTextureArray may be nullptr for no depth, or a TextureArray with the same layer count.

Requires state.caps.multiview == true — caller must check.

◆ createMultiViewRenderTarget() [2/2]

TextureRenderTarget score::gfx::createMultiViewRenderTarget ( const RenderState state,
std::span< QRhiTexture *const >  colorTextures,
int  multiViewCount,
QRhiTexture *  depthTextureArray,
int  samples 
)

Multi-attachment (MRT) multiview render target.

Same as the single-texture overload but attaches ALL colorTextures (each a TextureArray with >= multiViewCount layers) with per-attachment multiview, so attachments == pipeline blend targets. Requires state.caps.multiview == true.

◆ createReadbackTarget()

ReadbackTarget * score::gfx::createReadbackTarget ( QRhi &  rhi,
void *  dst,
std::size_t  bytes 
)

Registers dst (alignment-aligned, bytes rounded up to the alignment and owned by the caller) once. Returns nullptr when the backend or the specific allocation cannot be wrapped — fall back to QRhi::readBackTexture. Never call per frame.

◆ createRenderTarget() [1/2]

TextureRenderTarget score::gfx::createRenderTarget ( const RenderState state,
QRhiTexture::Format  fmt,
QSize  sz,
int  samples,
bool  depth,
bool  samplableDepth = false,
QRhiTexture::Flags  flags = {} 
)

Create a render target from a texture format and size.

This function will also create a texture.

◆ createRenderTarget() [2/2]

TextureRenderTarget score::gfx::createRenderTarget ( const RenderState state,
std::span< QRhiTexture *const >  colorTextures,
QRhiTexture *  depthTexture,
int  samples 
)

Create a render target with multiple color attachments and optional sampleable depth.

Parameters
colorTexturesAll color attachment textures (must be non-empty, first becomes primary)
depthTextureSampleable depth texture, or nullptr for no depth / renderbuffer depth

◆ dispatchComputeLayeredImages()

bool score::gfx::dispatchComputeLayeredImages ( QRhi &  rhi,
QRhiCommandBuffer &  cb,
QRhiShaderResourceBindings &  srb,
int  x,
int  y,
int  z 
)

Dispatch a compute pass, working around Qt's non-layered bind of layered (3D / cube / array) storage images on the OpenGL backend.

Qt's QRhi OpenGL backend (before the fix that shipped in 6.10) binds a 3D, cube-map OR 2D-texture-array storage image with glBindImageTexture(..., layered=GL_FALSE, layer=0). That exposes only slice/face/layer 0 to the shader, so an imageStore into an image3D, imageCube or image2DArray writes ONLY that single slice and every other slice/face/layer stays uninitialised — the classic "layered compute output reads back black on GL, fine on Vulkan" symptom. (Fixed upstream in Qt 6.10: qrhigles2.cpp binds layered = CubeMap || ThreeDimensional || TextureArray; there this call is a harmless identical re-bind.)

When srb contains at least one layered storage-image binding (3D, cube or array) AND the backend is OpenGL, this issues the dispatch itself: it flushes QRhi's own (mis-)binding via beginExternal(), re-binds each layered storage image LAYERED (all slices/faces/layers writable), dispatches, emits a full memory barrier, and returns true. The predicate is kept EXACTLY in sync with qrhigles2's own layered determination.

Returns false when the caller should issue the ordinary QRhi dispatch (non-OpenGL backend, or no layered storage image in the SRB) — every other backend and the 2D image path are left completely untouched.

Must be called inside an active compute pass, after setComputePipeline() and setShaderResources().

◆ dispatchIndirectCompat()

template<typename CB = QRhiCommandBuffer>
bool score::gfx::dispatchIndirectCompat ( CB &  cb,
QRhiBuffer *  argsBuffer,
quint32  argsOffset 
)
inlinenoexcept

dispatchIndirect when the API exists; returns false when it does not, so the caller can fall back to a CPU worst-case dispatch.

◆ drawIndirectCountCompat()

template<typename CB = QRhiCommandBuffer>
bool score::gfx::drawIndirectCountCompat ( CB &  cb,
bool  indexed,
QRhiBuffer *  indirectBuffer,
quint32  indirectOffset,
QRhiBuffer *  countBuffer,
quint32  countOffset,
quint32  maxDrawCount,
quint32  stride 
)
inlinenoexcept

drawIndirectCount / drawIndexedIndirectCount when the API exists; returns false (recorded nothing) when it does not, so the caller can fall back to the plain multi-draw / CPU rungs.

◆ drawIndirectCountUsable()

bool score::gfx::drawIndirectCountUsable ( GraphicsApi  api,
int  multiViewCount 
)
inlinenoexcept

Whether the GPU-count draw path (drawIndexedIndirectCount) is usable.

Ask this WITH caps.drawIndirectCount at every site that selects the count rung; QRhi's feature flag alone is not enough:

  • Metal implements the count draw exclusively through Indirect Command Buffers, which demand things the flag cannot express: the graphics pipeline must be created with QRhiGraphicsPipeline::UsesIndirectDraws (qrhimetal.mm icbUnavailableReason — the draw is SKIPPED with a warning otherwise), the pipeline may not sample textures at all, and the pass is interrupted/restarted so a transient DepthStencil renderbuffer loses its contents unless created with NoTransientBacking. None of those three are plumbed yet, so the count rung is declined on Metal wholesale; the plain multi-draw rung there stays correct because producers zero dead command slots. Lift this once the three prerequisites land together.
  • The multiview-on-Metal indirect break applies to the count entry points exactly as it does to drawIndexedIndirect (they share the encoder path), so the existing predicate is folded in.

◆ drawMeshWithOptionalIndirect()

void score::gfx::drawMeshWithOptionalIndirect ( const Mesh mesh,
const MeshBuffers bufs,
QRhiCommandBuffer &  cb 
)
noexcept

Draw a mesh, using indirect multi-draw when available in MeshBuffers.

When bufs.useIndirectDraw is true (and Qt >= 6.12), dispatches to cb.drawIndexedIndirect / cb.drawIndirect with the offset/count/stride stored in bufs. Otherwise falls back to the mesh's standard draw().

This is the main draw entry point for ISF / RawRaster / Scene renderers so that they can transparently support multi-draw indirect just by wiring an indirect buffer into MeshBuffers.

◆ endBufferCopyBarrier()

void score::gfx::endBufferCopyBarrier ( QRhi &  rhi,
QRhiCommandBuffer &  cb 
)

Emit the transfer→compute barrier after a batch of buffer copies so downstream compute/graphics reads observe the writes.

◆ ensureStorageResources()

void score::gfx::ensureStorageResources ( QRhi &  rhi,
QRhiResourceUpdateBatch &  res,
const RenderList renderer,
const isf::descriptor &  desc,
GraphicsStorageResources store,
QSize  renderSize 
)

Create missing buffers and textures.

Safe to call every frame — idempotent. Resizes buffers when they don't match the current layout. For persistent SSBOs, allocates both the current and prev buffers. For indirect-draw buffers, adds the IndirectBuffer usage flag.

◆ findGeometryAttribute()

const ossia::geometry::attribute * score::gfx::findGeometryAttribute ( const ossia::geometry &  geom,
std::string_view  name,
std::string_view  semantic_key 
)

Match a (name, semantic) request to an upstream geometry attribute.

Three-stage cascade shared by all shader modes:

  1. semantic_key → name_to_semantic → if known, geom.find(semantic).
  2. Custom-attribute lookup by name.
  3. display_name == name fallback (so { NAME: "position", SEMANTIC: "custom" } still finds the real position attribute when no custom one shadows it). If semantic_key is empty, name is used as the semantic key.

◆ finishReadbackToHost()

bool score::gfx::finishReadbackToHost ( QRhi &  rhi,
ReadbackTarget dst 
)

Makes the last recorded readback's bytes visible in dst. On the GL paths this waits on a fence (and memcpys from the PBO when not pinned); on D3D11 it maps the staging texture and copies it into dst; on Vulkan/D3D12 it is a no-op — the caller's frame synchronization suffices. Must be called after every recorded readback, on every backend.

◆ glslTypeSizeBytes()

int64_t score::gfx::glslTypeSizeBytes ( std::string_view  type)
noexcept

Byte size of a single GLSL primitive type as used for SSBO element strides in this codebase.

Coverage: scalars (float, int, uint, bool), vectors (vec[234], ivec[234], uvec[234]), and matrices (mat2, mat3, mat4). Sampler / image / opaque types are not covered (return the fallback). Returns 16 as a fallback for unknown / unsupported types.

Conventions:

  • Returns 12 for vec3/ivec3/uvec3 (the bare component size). Consumers that need std140 / std430 array stride must align to 16 themselves; for that case prefer std430ArrayStride below, which encapsulates the rule and keeps the two domains (bare type size vs. stride-in-SSBO) from drifting at call sites. ISF auxiliary layouts continue to align at the field level via std430LayoutSize.
  • mat2 is reported as 16 (two vec2 columns, no per-column padding).
  • mat3 is reported as 48 (three vec4-padded columns); this matches both std140 and std430 column-major layout for mat3 in storage blocks.
  • mat4 is reported as 64.

This is the single source of truth for GLSL type → element size in score-plugin-gfx; do not introduce private copies.

The vertex-attribute format → byte-size mapping (ossia::geometry::attribute enum) is a different domain – binary attribute formats, not GLSL type strings – and lives in its own helper inside RenderedCSFNode.cpp.

◆ hlslIntrinsicCollision()

SCORE_PLUGIN_GFX_EXPORT QByteArray score::gfx::hlslIntrinsicCollision ( const QByteArray &  raw)
noexcept

The identifier a shader declares that collides with an HLSL intrinsic.

The identifier a shader declares that collides with an HLSL intrinsic, or empty if there is none.

Empty when there is none. Only the names SPIRV-Cross actually emits when translating a GLSL builtin are listed: an identifier is only dangerous because the generated HLSL will also contain a CALL by that name. A wider list – every HLSL intrinsic in existence – would reject shaders that compile perfectly well, which is worse than the bug.

SPIRV-Cross rewrites GLSL builtins to their HLSL spellings but leaves the user's variable names alone, so float frac becomes float frac = frac(...) and only Direct3D rejects it. Checked before baking for D3D so the author is told which name to change, instead of getting an fxc error about a line that looks correct.

◆ imageTextureFormat()

SCORE_PLUGIN_GFX_EXPORT QRhiTexture::Format score::gfx::imageTextureFormat ( const QRhi &  rhi)
noexcept

Texture format to use for images uploaded from the CPU.

BGRA8 where the backend has it, RGBA8 otherwise. QRhiGles2 asks for GL_BGRA whenever a texture is BGRA8, and WebGL has no such format at all, so uploading one there is an INVALID_ENUM and the image never appears.

◆ indirectDrawBreaksMultiView()

bool score::gfx::indirectDrawBreaksMultiView ( GraphicsApi  api,
int  multiViewCount 
)
inlinenoexcept

Whether a GPU indirect draw silently loses multiview on this backend.

Qt's Metal backend derives gl_ViewIndex by multiplying the instance count and binding a view-mask buffer, and it does BOTH only in adjustForMultiViewDraw() – which qrhimetal.mm calls from draw() (:2499) and drawIndexed() (:2539) and from NEITHER drawIndirect() nor drawIndexedIndirect(). An indirect draw of a multiview shader therefore renders every amplified view into layer 0, with no qWarning: the warning inside adjustForMultiViewDraw cannot fire because the function is never entered. Metal's validation layer names it outright:

Vertex Function(main0): missing Buffer binding at index 24 for spvViewMask[0].

The CPU fallback in CustomMesh::drawSingleMesh issues one drawIndexed per command, which DOES go through adjustForMultiViewDraw, so declining GPU indirect restores correct multiview at the cost of N draw calls.

Scoped to Metal deliberately: Vulkan and D3D12 implement multiview in the render pass / view instancing, so the indirect entry points inherit it.

◆ insertComputeBarrier()

void score::gfx::insertComputeBarrier ( QRhi &  rhi,
QRhiCommandBuffer &  cb 
)

Insert a compute-to-compute memory barrier.

Ensures that SSBO writes from a preceding compute dispatch are visible to the next compute dispatch. Must be called between QRhiCommandBuffer::beginExternal() and endExternal(), inside a compute pass.

Per-backend behaviour:

  • Vulkan : vkCmdPipelineBarrier (COMPUTE → COMPUTE, SHADER_WRITE → SHADER_READ|WRITE)
  • OpenGL : glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT)
  • D3D12 : UAV barrier on all resources
  • D3D11 : no-op (implicit within device context)
  • Metal : no-op (implicit between command encoders; each QRhi compute pass uses a separate MTLComputeCommandEncoder)

◆ makeCompute()

QShader score::gfx::makeCompute ( const RenderState v,
QString  compt 
)

Compile a compute shader.

Note: this function will throw if the shader is invalid.

◆ makeSampler()

QRhiSampler * score::gfx::makeSampler ( QRhi &  rhi,
const isf::sampler_config &  cfg 
)

Build a QRhiSampler from an isf::sampler_config.

Fields left empty/unset in the config are filled with ossia defaults (linear filtering, no mipmaps, clamp-to-edge). When the config sets a comparison op other than "never", the returned sampler is a shadow comparison sampler.

The returned sampler is created (create() was called) and has no name assigned; callers should setName() before or after create() as needed. Ownership follows the standard QRhi convention — callers delete it.

◆ makeShaders()

std::pair< QShader, QShader > score::gfx::makeShaders ( const RenderState v,
QString  vert,
QString  frag,
int  multiViewCount = 0 
)

Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.

Note: this function will throw if a shader is invalid.

◆ makeWireComputeEncoder()

std::unique_ptr< ComputeEncoder > score::gfx::makeWireComputeEncoder ( score::gfx::interop::VideoPixelFormat  fmt)
inline

Compute-shader encoder for the GPU-direct path (writes into an imported buffer). Only the formats with a compute variant are supported.

◆ makeWireEncoder()

std::unique_ptr< GPUVideoEncoder > score::gfx::makeWireEncoder ( score::gfx::interop::VideoPixelFormat  fmt)
inline

Render (fragment-shader) encoder producing fmt's exact on-wire bytes. Returns nullptr when no GPU encoder exists for fmt.

◆ nv12ExternalOesUsable()

bool score::gfx::nv12ExternalOesUsable ( QRhi::Implementation  backend)
noexcept

True when this decoder can be used at all: a GLES backend whose driver advertises the external-image extension. Checked before the backend commits to it, because an external texture the driver will not sample is worse than the CPU path.

◆ packedBitfieldFilter()

QString score::gfx::packedBitfieldFilter ( const PackedBitfieldLayout l)
inline

Builds the PackedDecoder filter that unpacks l.

The word is rebuilt from the sampled bytes, then each field is shifted, masked and normalised by its own maximum, so a 5-bit channel spans the full 0..1 range rather than topping out at 31/255.

◆ parseOutputFormat()

QRhiTexture::Format score::gfx::parseOutputFormat ( const std::string &  fmt,
QRhiTexture::Format  fallback 
)
noexcept

Map an ISF/CSF FORMAT string to a QRhiTexture::Format.

Supported: rgba8, bgra8, r8, rg8, r16, rg16, r16f, r32f, rgba16f, rgba32f, d16, d24, d24s8, d32f. Unknown / empty strings fall back to the caller's default. Lookup is case-insensitive.

◆ readbackDstOffsetAlignment()

std::size_t score::gfx::readbackDstOffsetAlignment ( QRhi &  rhi,
QRhiTexture &  src 
)
noexcept

Required alignment of the dstOffset passed to readbackTextureToHost for a texture of this format (0 = backend unsupported). D3D12: 512 (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT); Vulkan: the texel size and 4; OpenGL: 4; D3D11: 1.

◆ readbackHostMemoryAlignment()

std::size_t score::gfx::readbackHostMemoryAlignment ( QRhi &  rhi)
noexcept

Required alignment of dst and granularity of bytes for createReadbackTarget, or 0 when unsupported. Vulkan: the device's minImportedHostPointerAlignment (4096 on NVIDIA). OpenGL: 4096 (GL_AMD_pinned_memory page requirement; the PBO fallback ignores it). D3D12: 65536 (VirtualAlloc allocation granularity). D3D11: 1 (dst is only ever a memcpy destination).

◆ readbackTextureSupported()

bool score::gfx::readbackTextureSupported ( QRhi &  rhi,
QRhiTexture &  src,
std::size_t  dstBytes 
)
noexcept

Whether readbackTextureToHost can handle this texture on this backend (format/size/pitch constraints), for a target of dstBytes — the same checks the record path performs, without recording anything. Lets a caller decide at init time instead of discovering a permanent per-frame failure.

◆ readbackTextureToHost()

bool score::gfx::readbackTextureToHost ( QRhi &  rhi,
QRhiCommandBuffer &  cb,
QRhiTexture &  src,
ReadbackTarget dst,
std::size_t  dstOffset = 0 
)

Records the texture→(dst + dstOffset) copy on cb. Must be called outside a render pass. The copy is tightly packed rows, texture storage order (top-left origin in score). dstOffset lets the copy land on an interior pointer of the registered region (device SDKs often hand out offset frame pointers inside their allocations); it must satisfy readbackDstOffsetAlignment and fit in the target. Returns false when the texture's format/size/offset cannot target this backend's path — nothing is recorded, fall back.

◆ reapplyStorageBindings()

void score::gfx::reapplyStorageBindings ( const GraphicsStorageResources store,
QRhiShaderResourceBindings &  srb 
)

Re-apply the current persistent-storage state to a single SRB.

Pairs with swapPersistentSSBOsState: after swapping store once, call this on every SRB that references the persistent bindings so the descriptor set matches the new pointers. Uses replaceBuffer's updateResources() fast path — no srb->create() rebuild — to avoid thrashing the SRB pool slot every frame on a static scene.

◆ remapPipelineVertexInputs() [1/2]

bool score::gfx::remapPipelineVertexInputs ( QRhiGraphicsPipeline &  pip,
const QShader &  vertexShader,
const ossia::geometry &  geom 
)

Remap a pipeline's vertex input layout using semantic matching.

Reflects the compiled vertex shader to find each in variable, then for each one runs findGeometryAttribute(name, name) — useful when no isf descriptor is around (legacy callers). Returns true on success, false if a required attribute can't be matched.

◆ remapPipelineVertexInputs() [2/2]

bool score::gfx::remapPipelineVertexInputs ( QRhiGraphicsPipeline &  pip,
const QShader &  vertexShader,
const ossia::geometry &  geom,
const isf::descriptor &  desc,
QRhi &  rhi,
VertexFallbackPool pool,
QRhiResourceUpdateBatch &  batch,
FallbackBindingPlan outPlan 
)

Fallback-aware overload: the strict-matching behaviour of the overload above, extended so VERTEX_INPUTS entries with "REQUIRED": false silently resolve to a shared identity buffer from the pool when their semantic is absent upstream.

pool per-RenderList shared fallback buffer pool batch any uploads for freshly-allocated fallback buffers are recorded here outPlan filled with the bindings the caller must merge into the draw's QRhiCommandBuffer::VertexInput array. Cleared on entry.

Returns false (and logs which input failed) if:

  • a REQUIRED=true input has no matching upstream attribute, OR
  • a REQUIRED=false input has no matching upstream attribute AND the declared GLSL TYPE is unsupported (mat4 / integer / sampler) OR the resolved semantic is not in the whitelist AND no explicit DEFAULT was supplied.

◆ rhiSupportsDrawIndirectCount()

template<typename R = QRhi>
bool score::gfx::rhiSupportsDrawIndirectCount ( R &  rhi)
inlinenoexcept

QRhi::DrawIndirectCount reported by the device, false when the API does not exist in this Qt (or SCORE_GFX_SIMULATE_QT612 pretends it does not).

◆ std430ArrayStride()

int64_t score::gfx::std430ArrayStride ( std::string_view  type)
noexcept

std430 array stride for a GLSL primitive type when laid out as T array[] inside a shader storage block.

Differs from glslTypeSizeBytes only for vec3-shaped vectors: per the std430 layout rules, an array of vec3 (or ivec3 / uvec3) keeps the element's vec4-aligned base alignment, so the per-element stride is 16 bytes — the trailing 4 bytes are padding the GPU does not write but consumer reads must skip. For scalars, vec2, vec4 and matrices, the stride equals the bare type size, so this returns glslTypeSizeBytes(type) unchanged.

Use this — never glslTypeSizeBytes — when sizing a CSF SoA output SSBO buffer or setting a downstream vertex binding stride that mirrors the SSBO's std430 layout: mixing the two corrupts vec3 data silently.

◆ swapPersistentSSBOs()

void score::gfx::swapPersistentSSBOs ( GraphicsStorageResources store,
QRhiShaderResourceBindings &  srb 
)

Swap current/prev for all persistent SSBOs and storage images, then update the SRB.

Call at end of frame, after all passes have run. Symmetric to the existing texture ping-pong in RenderedISFNode (the swap(passes, altPasses) at RenderedISFNode.cpp:1094).

◆ swapPersistentSSBOsState()

void score::gfx::swapPersistentSSBOsState ( GraphicsStorageResources store)

Swap current/prev pointers in store without touching any SRB.

Used by multi-pass / multi-SRB renderers that need to apply the same post-swap state to many descriptor sets: call this once per frame, then call reapplyStorageBindings on every affected SRB. Calling swapPersistentSSBOs per-SRB would double-swap and cancel out.

◆ toExternalSamplerEssl()

QByteArray score::gfx::toExternalSamplerEssl ( QByteArray  glsl)

Turn the baked GLSL into the external-sampler variant.

Two surgical edits on the baked text rather than a reconstruction: the baked shader already carries exactly the uniform blocks, locations and precision qualifiers that QRhiGles2 will wire from the reflection, and rebuilding that by hand gets it wrong: the blocks end } renderer; rather than };, so slicing to the first }; produces malformed source and a compile error at token "renderer".

Rewrite baked GLSL so its sampler2D tex becomes samplerExternalOES tex, adding the required extension pragma. Shared because every external-image decoder needs exactly this edit: glslang rejects the external type, so the shader is baked with sampler2D and only the GL text is swapped. Returns an empty array when the input does not look like baked GLSL.

◆ viewIndexNeedsPassIndexFallback()

bool score::gfx::viewIndexNeedsPassIndexFallback ( GraphicsApi  api,
const QShaderVersion &  version,
int  multiViewCount 
)
inlinenoexcept

Whether MULTIVIEW must be emulated with one pass per view.

gl_ViewIndex becomes HLSL SV_ViewID, which requires shader model 6.1. D3D11 is pinned to SM 5.0 for good, and D3D12 drops to 5.0 whenever dxcompiler.dll is absent, so on those targets a multiview shader cannot be COMPILED at all:

Vertex shader error: View Index input is only supported in VS and PS
6.1 or higher.

ShaderCache answers this by rewriting gl_ViewIndex to the PASSINDEX uniform, which the N-pass path stamps per invocation.

That rewrite and the choice of render path MUST be driven by the same predicate. When they disagree the failure is silent and looks like a rasterizer bug: a D3D12 shader lowered to read PASSINDEX while QRhi still reports MultiView gets ONE amplified draw in which passIndex never advances past 0 – and all six cube faces come back carrying face 0's colour. Ask this function in both places.

◆ visibilityToStages()

QRhiShaderResourceBinding::StageFlags score::gfx::visibilityToStages ( std::string_view  visibility)
noexcept

Decode an isf::storage_input::visibility string to Qt RHI stage flags.

"fragment" → FragmentStage "vertex" → VertexStage "vertex+fragment" / "both" / "graphics" → Vertex | Fragment "compute" → ComputeStage "none" → 0

◆ wireComputeSupports()

bool score::gfx::wireComputeSupports ( score::gfx::interop::VideoPixelFormat  fmt,
int  width 
)
inline

Whether the compute encoder can handle (fmt, width): v210 needs width % 6, UYVY needs width % 2, BGRA is unconstrained.