Loading...
Searching...
No Matches
UYVY.hpp
1#pragma once
2#include <Gfx/Graph/encoders/GPUVideoEncoder.hpp>
3
4namespace score::gfx
5{
6
17{
18 // %1 = colorMatrixOut() shader defining convert_from_rgb(vec3)
19 static constexpr const char* frag = R"_(#version 450
20 layout(location = 0) in vec2 v_texcoord;
21 layout(location = 0) out vec4 fragColor;
22 layout(binding = 3) uniform sampler2D src_tex;
23 )_" "%1" R"_(
24
25 vec2 flip_y(vec2 tc) {
26 #if defined(QSHADER_MSL) || defined(QSHADER_HLSL)
27 return tc;
28 #else
29 return vec2(tc.x, 1.0 - tc.y);
30 #endif
31 }
32
33 void main() {
34 float srcW = float(textureSize(src_tex, 0).x);
35 float srcY = flip_y(v_texcoord).y;
36
37 float halfW = srcW * 0.5;
38 float outPixel = v_texcoord.x * halfW - 0.5;
39 float srcX0 = (floor(outPixel) * 2.0 + 0.5) / srcW;
40 float srcX1 = (floor(outPixel) * 2.0 + 1.5) / srcW;
41
42 vec3 rgb0 = texture(src_tex, vec2(srcX0, srcY)).rgb;
43 vec3 rgb1 = texture(src_tex, vec2(srcX1, srcY)).rgb;
44
45 vec3 yuv0 = convert_from_rgb(rgb0);
46 vec3 yuv1 = convert_from_rgb(rgb1);
47
48 // Average chroma
49 float u = (yuv0.y + yuv1.y) * 0.5;
50 float v = (yuv0.z + yuv1.z) * 0.5;
51
52 // UYVY: U, Y0, V, Y1
53 fragColor = vec4(u, yuv0.x, v, yuv1.x);
54 }
55 )_";
56
57 QRhiTexture* m_outTexture{};
58 QRhiTextureRenderTarget* m_renderTarget{};
59 QRhiRenderPassDescriptor* m_rpDesc{};
60 QRhiSampler* m_sampler{};
61 QRhiShaderResourceBindings* m_srb{};
62 QRhiGraphicsPipeline* m_pipeline{};
63 QRhiReadbackResult m_readback{};
64 int m_width{};
65 int m_height{};
66
67 void init(
68 QRhi& rhi, const RenderState& state, QRhiTexture* inputRGBA, int width,
69 int height, const QString& colorConversion = colorMatrixOut()) override
70 {
71 m_width = width;
72 m_height = height;
73
74 // Output: RGBA8 at half width (each texel = 2 source pixels packed as UYVY)
75 m_outTexture = rhi.newTexture(
76 QRhiTexture::RGBA8, QSize{width / 2, height}, 1,
77 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
78 m_outTexture->create();
79
80 m_renderTarget = rhi.newTextureRenderTarget({m_outTexture});
81 m_rpDesc = m_renderTarget->newCompatibleRenderPassDescriptor();
82 m_renderTarget->setRenderPassDescriptor(m_rpDesc);
83 m_renderTarget->create();
84
85 m_sampler = rhi.newSampler(
86 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
87 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
88 m_sampler->create();
89
90 // Shader resource bindings — only the source texture sampler
91 m_srb = rhi.newShaderResourceBindings();
92 m_srb->setBindings({
93 QRhiShaderResourceBinding::sampledTexture(
94 3, QRhiShaderResourceBinding::FragmentStage, inputRGBA, m_sampler),
95 });
96 m_srb->create();
97
98 // Compile shaders
99 auto [vertS, fragS] = makeShaders(
100 state, QString::fromLatin1(vertex_shader),
101 QString::fromLatin1(frag).arg(colorConversion));
102
103 // Graphics pipeline
104 m_pipeline = rhi.newGraphicsPipeline();
105 m_pipeline->setShaderStages({
106 {QRhiShaderStage::Vertex, vertS},
107 {QRhiShaderStage::Fragment, fragS},
108 });
109
110 m_pipeline->setVertexInputLayout({});
111 m_pipeline->setShaderResourceBindings(m_srb);
112 m_pipeline->setRenderPassDescriptor(m_rpDesc);
113 m_pipeline->create();
115 }
116
117 void exec(QRhi& rhi, QRhiCommandBuffer& cb) override
118 {
119 cb.beginPass(m_renderTarget, Qt::black, {1.0f, 0});
120 cb.setGraphicsPipeline(m_pipeline);
121 cb.setShaderResources(m_srb);
122 cb.setViewport(QRhiViewport(0, 0, m_width / 2, m_height));
123 cb.draw(3);
124
125 auto* readbackBatch = rhi.nextResourceUpdateBatch();
126 QRhiReadbackDescription rb(m_outTexture);
127 readbackBatch->readBackTexture(rb, &m_readback);
128 cb.endPass(readbackBatch);
129 }
131 int planeCount() const override { return 1; }
133 const QRhiReadbackResult& readback(int) const override { return m_readback; }
134
135 void release() override
136 {
137 delete m_pipeline;
138 m_pipeline = nullptr;
139 delete m_srb;
140 m_srb = nullptr;
141 delete m_sampler;
142 m_sampler = nullptr;
143 delete m_rpDesc;
144 m_rpDesc = nullptr;
145 delete m_renderTarget;
146 m_renderTarget = nullptr;
147 delete m_outTexture;
148 m_outTexture = nullptr;
149 }
150};
151
152} // namespace score::gfx
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12
std::pair< QShader, QShader > makeShaders(const RenderState &v, QString vert, QString frag)
Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
Definition score-plugin-gfx/Gfx/Graph/Utils.cpp:395
Base class for GPU-side video format conversion (RGBA to YUV).
Definition GPUVideoEncoder.hpp:30
static constexpr const char * vertex_shader
Definition GPUVideoEncoder.hpp:63
GPU RGBA->UYVY encoder (packed 4:2:2).
Definition UYVY.hpp:17
void release() override
Release all GPU resources.
Definition UYVY.hpp:132
int planeCount() const override
Number of readback planes (1 for UYVY, 2 for NV12, 3 for I420).
Definition UYVY.hpp:128
void exec(QRhi &rhi, QRhiCommandBuffer &cb) override
Definition UYVY.hpp:114
const QRhiReadbackResult & readback(int) const override
Get the readback result for a given plane. Valid after endOffscreenFrame.
Definition UYVY.hpp:130