Loading...
Searching...
No Matches

GPU RGBA -> p216 encoder (semi-planar 4:2:2, 16-bit). More...

Inheritance diagram for score::gfx::P216Encoder:
score::gfx::GPUVideoEncoder

Detailed Description

GPU RGBA -> p216 encoder (semi-planar 4:2:2, 16-bit).

The 16-bit sibling of P010Encoder: same two-plane semi-planar shape, but the chroma plane keeps FULL vertical resolution (4:2:2, not 4:2:0) and each sample uses all 16 bits of its word rather than sitting in the high 10. Matches AV_PIX_FMT_P216LE and NDI's NDIlib_FourCC_video_type_P216.

Two planes, both 2*width bytes per row over height rows:

  • Y : one 16-bit luma per pixel, width x height;
  • UV: one interleaved (Cb, Cr) pair per chroma site, width/2 x height. So the two planes are the same size, and a consumer that wants them contiguous (NDI: p_uv = p_y + stride * yres) gets a framestore of 2 * 2*width * height bytes.

Feed a >8-bit source texture (RGBA16F) if you want the extra bits to mean anything: from an RGBA8 scene this produces valid P216 whose values are 8-bit quantities scaled into 16-bit words. Consumers cannot tell, and it is still the right thing to send when the wire format is 16-bit, but the precision has to come from the render target.

Two implementations selected at compile time, exactly as P010Encoder does and for the same reason (see its comment for the qtbase reference):

  • Qt >= 6.10: native R16 (Y) / RG16 (UV) targets, read back tightly.
  • Qt < 6.10: the GL backend reads 16-bit single/dual-channel textures back as 8-bit RGBA, so the 16-bit bytes are packed into RGBA8 here.

Both paths expose the same readback byte layout, so consumers are agnostic. Requires width % 2 == 0.

Public Member Functions

void setupPlane (QRhi &rhi, const RenderState &state, QRhiTexture *inputRGBA, QRhiTexture::Format fmt, int w, int h, const char *frag, const QString &colorConversion, QRhiTexture *&tex, QRhiTextureRenderTarget *&rt, QRhiRenderPassDescriptor *&rp, QRhiShaderResourceBindings *&srb, QRhiGraphicsPipeline *&pipeline)
 
void init (QRhi &rhi, const RenderState &state, QRhiTexture *inputRGBA, int width, int height, const QString &colorConversion) override
 
void exec (QRhi &rhi, QRhiCommandBuffer &cb) override
 
int planeCount () const override
 Number of readback planes (1 for UYVY, 2 for NV12, 3 for I420).
 
const QRhiReadbackResult & readback (int plane) const override
 Get the readback result for a given plane. Valid after endOffscreenFrame.
 
QRhiTexture * planeTexture (int plane) const noexcept
 
void setReadbackEnabled (bool e) noexcept override
 
void release () override
 Release all GPU resources.
 
- Public Member Functions inherited from score::gfx::GPUVideoEncoder
virtual QRhiTexture * outputTexture () const noexcept
 

Public Attributes

QRhiTexture * m_yTexture {}
 
QRhiTextureRenderTarget * m_yRT {}
 
QRhiRenderPassDescriptor * m_yRP {}
 
QRhiShaderResourceBindings * m_ySRB {}
 
QRhiGraphicsPipeline * m_yPipeline {}
 
QRhiReadbackResult m_yReadback {}
 
QRhiTexture * m_uvTexture {}
 
QRhiTextureRenderTarget * m_uvRT {}
 
QRhiRenderPassDescriptor * m_uvRP {}
 
QRhiShaderResourceBindings * m_uvSRB {}
 
QRhiGraphicsPipeline * m_uvPipeline {}
 
QRhiReadbackResult m_uvReadback {}
 
QRhiSampler * m_sampler {}
 
int m_width {}
 
int m_height {}
 
bool m_readbackEnabled {true}
 

Static Public Attributes

static constexpr const char * y_frag
 
static constexpr const char * uv_frag
 
- Static Public Attributes inherited from score::gfx::GPUVideoEncoder
static constexpr const char * vertex_shader
 
static constexpr const char * rgb_to_yuv_glsl
 
static constexpr const char * y_flip_glsl
 Fragment shader Y-flip: on GL, flip v_texcoord.y. On Metal/HLSL, no flip.
 

Member Function Documentation

◆ exec()

void score::gfx::P216Encoder::exec ( QRhi &  rhi,
QRhiCommandBuffer &  cb 
)
inlineoverridevirtual

Execute the conversion pass. Call inside beginOffscreenFrame/endOffscreenFrame. Renders the conversion shader and schedules GPU->CPU readback(s).

Implements score::gfx::GPUVideoEncoder.

◆ init()

void score::gfx::P216Encoder::init ( QRhi &  rhi,
const RenderState &  state,
QRhiTexture *  inputRGBA,
int  width,
int  height,
const QString &  colorConversion 
)
inlineoverridevirtual

Create render targets, textures, samplers, and the graphics pipeline.

Parameters
rhiThe QRhi instance.
stateThe render state (for shader compilation).
inputRGBAThe scene RGBA texture to read from.
widthSource width in pixels.
heightSource height in pixels.
colorConversionGLSL code from colorMatrixOut() defining convert_from_rgb(). If empty, defaults to BT.709 full range.

Implements score::gfx::GPUVideoEncoder.

◆ planeCount()

int score::gfx::P216Encoder::planeCount ( ) const
inlineoverridevirtual

Number of readback planes (1 for UYVY, 2 for NV12, 3 for I420).

Implements score::gfx::GPUVideoEncoder.

◆ planeTexture()

QRhiTexture * score::gfx::P216Encoder::planeTexture ( int  plane) const
inlinenoexcept

The plane textures, for consumers that read them back themselves (a contiguous framestore, a GPU-direct download). Plane 0 is Y, 1 is UV.

◆ readback()

const QRhiReadbackResult & score::gfx::P216Encoder::readback ( int  plane) const
inlineoverridevirtual

Get the readback result for a given plane. Valid after endOffscreenFrame.

Implements score::gfx::GPUVideoEncoder.

◆ release()

void score::gfx::P216Encoder::release ( )
inlineoverridevirtual

Release all GPU resources.

Implements score::gfx::GPUVideoEncoder.

◆ setReadbackEnabled()

void score::gfx::P216Encoder::setReadbackEnabled ( bool  )
inlineoverridevirtualnoexcept

Enable/disable the GPU->CPU readback scheduled in exec(). Default enabled (readback runs). Disable when a GPU-direct download reads outputTexture() directly, so exec() doesn't also pay the readback (no double transfer).

Reimplemented from score::gfx::GPUVideoEncoder.

Member Data Documentation

◆ uv_frag

constexpr const char* score::gfx::P216Encoder::uv_frag
staticconstexpr
Initial value:
= R"_(#version 450
layout(location = 0) in vec2 v_texcoord;
layout(location = 0) out vec4 fragColor;
layout(binding = 3) uniform sampler2D src_tex;
)_" "%1" R"_(
vec2 flip_y(vec2 tc) {
return tc;
return vec2(tc.x, 1.0 - tc.y);
}
void main() {
vec3 rgb = texture(src_tex, flip_y(v_texcoord)).rgb;
vec3 yuv = convert_from_rgb(rgb);
fragColor = vec4(clamp(yuv.y, 0.0, 1.0), clamp(yuv.z, 0.0, 1.0), 0.0, 1.0);
}
)_"

◆ y_frag

constexpr const char* score::gfx::P216Encoder::y_frag
staticconstexpr
Initial value:
= R"_(#version 450
layout(location = 0) in vec2 v_texcoord;
layout(location = 0) out vec4 fragColor;
layout(binding = 3) uniform sampler2D src_tex;
)_" "%1" R"_(
vec2 flip_y(vec2 tc) {
// Only OpenGL. The rest of the engine puts its geometry through
// renderer.clipSpaceCorrMatrix, which negates Y on Vulkan; this pass draws
// a hardcoded triangle in raw NDC and does not, so the correction it needs
// is not the same one. Flipping on Vulkan as well handed libav, GStreamer,
// NDI and every other consumer an upside-down picture.
return tc;
return vec2(tc.x, 1.0 - tc.y);
}
void main() {
vec3 rgb = texture(src_tex, flip_y(v_texcoord)).rgb;
vec3 yuv = convert_from_rgb(rgb);
fragColor = vec4(clamp(yuv.x, 0.0, 1.0), 0.0, 0.0, 1.0);
}
)_"

The documentation for this struct was generated from the following file: