Loading...
Searching...
No Matches

GPU RGBA -> p010le encoder (semi-planar 4:2:0, 10-bit). More...

Inheritance diagram for score::gfx::P010Encoder:
score::gfx::GPUVideoEncoder

Detailed Description

GPU RGBA -> p010le encoder (semi-planar 4:2:0, 10-bit).

Each 10-bit sample (0..1023) sits in the high 10 bits of its 16-bit word (low 6 bits zero), matching AV_PIX_FMT_P010LE / GStreamer P010_10LE. Two planes: Y full-res, interleaved UV half-res. Feed a >8-bit source texture (RGBA16F) for real 10-bit precision.

Two implementations selected at compile time (see YUV422P10Encoder for the full rationale and the qtbase commit reference):

  • Qt >= 6.10: native R16 (Y) / RG16 (UV) targets; QRhi reads them back tightly. Bilinear sampling averages the 2x2 chroma block.
  • Qt < 6.10: the GL backend reads 16-bit single/dual-channel textures back as 8-bit RGBA, so we pack the bytes into RGBA8 ourselves.

Both paths expose the same readback byte layout (Y = 2w bytes/row over h rows, UV = 2w bytes/row over h/2 rows, U then V interleaved per site), 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=colorMatrixOut()) 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.
 
void release () override
 Release all GPU resources.
 
- Public Member Functions inherited from score::gfx::GPUVideoEncoder
virtual QRhiTexture * outputTexture () const noexcept
 
virtual void setReadbackEnabled (bool) 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 {}
 

Static Public Attributes

static constexpr const char * pack_fn
 
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::P010Encoder::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::P010Encoder::init ( QRhi &  rhi,
const RenderState state,
QRhiTexture *  inputRGBA,
int  width,
int  height,
const QString &  colorConversion = colorMatrixOut() 
)
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::P010Encoder::planeCount ( ) const
inlineoverridevirtual

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

Implements score::gfx::GPUVideoEncoder.

◆ readback()

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

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

Implements score::gfx::GPUVideoEncoder.

◆ release()

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

Release all GPU resources.

Implements score::gfx::GPUVideoEncoder.

Member Data Documentation

◆ pack_fn

constexpr const char* score::gfx::P010Encoder::pack_fn
staticconstexpr
Initial value:
= R"_(
// 10-bit value -> high 10 bits of a 16-bit UNORM word (low 6 bits zero).
float pack10hi(float v) {
return round(clamp(v, 0.0, 1.0) * 1023.0) * 64.0 / 65535.0;
}
)_"

◆ uv_frag

constexpr const char* score::gfx::P010Encoder::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"_(
)_" "%2" 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(pack10hi(yuv.y), pack10hi(yuv.z), 0.0, 1.0);
}
)_"

◆ y_frag

constexpr const char* score::gfx::P010Encoder::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"_(
)_" "%2" 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(pack10hi(yuv.x), 0.0, 0.0, 1.0);
}
)_"

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