Loading...
Searching...
No Matches
YUY2.hpp
1#pragma once
2#include <Gfx/Graph/encoders/GPUVideoEncoder.hpp>
3
4namespace score::gfx
5{
6
15{
16 // %1 = colorMatrixOut() shader defining convert_from_rgb(vec3)
17 static constexpr const char* frag = R"_(#version 450
18 layout(location = 0) in vec2 v_texcoord;
19 layout(location = 0) out vec4 fragColor;
20 layout(binding = 3) uniform sampler2D src_tex;
21 )_" "%1" R"_(
22
23 vec2 flip_y(vec2 tc) {
24 // Only OpenGL. The rest of the engine puts its geometry through
25 // renderer.clipSpaceCorrMatrix, which negates Y on Vulkan; this pass draws
26 // a hardcoded triangle in raw NDC and does not, so the correction it needs
27 // is not the same one. Flipping on Vulkan as well handed libav, GStreamer,
28 // NDI and every other consumer an upside-down picture.
29 #if defined(QSHADER_SPIRV) || defined(QSHADER_MSL) || defined(QSHADER_HLSL)
30 return tc;
31 #else
32 return vec2(tc.x, 1.0 - tc.y);
33 #endif
34 }
35
36 void main() {
37 float srcW = float(textureSize(src_tex, 0).x);
38 float srcY = flip_y(v_texcoord).y;
39
40 float halfW = srcW * 0.5;
41 float outPixel = v_texcoord.x * halfW - 0.5;
42 float srcX0 = (floor(outPixel) * 2.0 + 0.5) / srcW;
43 float srcX1 = (floor(outPixel) * 2.0 + 1.5) / srcW;
44
45 vec3 rgb0 = texture(src_tex, vec2(srcX0, srcY)).rgb;
46 vec3 rgb1 = texture(src_tex, vec2(srcX1, srcY)).rgb;
47
48 vec3 yuv0 = convert_from_rgb(rgb0);
49 vec3 yuv1 = convert_from_rgb(rgb1);
50
51 float u = (yuv0.y + yuv1.y) * 0.5;
52 float v = (yuv0.z + yuv1.z) * 0.5;
53
54 // YUY2: Y0, Cb, Y1, Cr
55 fragColor = vec4(yuv0.x, u, yuv1.x, v);
56 }
57 )_";
58
59 QRhiTexture* m_outTexture{};
60 QRhiTextureRenderTarget* m_renderTarget{};
61 QRhiRenderPassDescriptor* m_rpDesc{};
62 QRhiSampler* m_sampler{};
63 QRhiShaderResourceBindings* m_srb{};
64 QRhiGraphicsPipeline* m_pipeline{};
65 QRhiReadbackResult m_readback{};
66 int m_width{};
67 int m_height{};
68
69 void init(
70 QRhi& rhi, const RenderState& state, QRhiTexture* inputRGBA, int width,
71 int height, const QString& colorConversion = colorMatrixOut()) override
72 {
73 m_width = width;
74 m_height = height;
75
76 m_outTexture = rhi.newTexture(
77 QRhiTexture::RGBA8, QSize{width / 2, height}, 1,
78 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
79 m_outTexture->create();
80
81 m_renderTarget = rhi.newTextureRenderTarget({m_outTexture});
82 m_rpDesc = m_renderTarget->newCompatibleRenderPassDescriptor();
83 m_renderTarget->setRenderPassDescriptor(m_rpDesc);
84 m_renderTarget->create();
85
86 m_sampler = rhi.newSampler(
87 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
88 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
89 m_sampler->create();
90
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 auto [vertS, fragS] = makeShaders(
99 state, QString::fromLatin1(vertex_shader),
100 QString::fromLatin1(frag).arg(colorConversion));
101
102 m_pipeline = rhi.newGraphicsPipeline();
103 m_pipeline->setShaderStages({
104 {QRhiShaderStage::Vertex, vertS},
105 {QRhiShaderStage::Fragment, fragS},
106 });
107 m_pipeline->setVertexInputLayout({});
108 m_pipeline->setShaderResourceBindings(m_srb);
109 m_pipeline->setRenderPassDescriptor(m_rpDesc);
110 m_pipeline->create();
111 }
112
113 void exec(QRhi& rhi, QRhiCommandBuffer& cb) override
114 {
115 cb.beginPass(m_renderTarget, Qt::black, {0.0f, 0});
116 cb.setGraphicsPipeline(m_pipeline);
117 cb.setShaderResources(m_srb);
118 cb.setViewport(QRhiViewport(0, 0, m_width / 2, m_height));
119 cb.draw(3);
120
121 auto* readbackBatch = rhi.nextResourceUpdateBatch();
122 readbackBatch->readBackTexture(QRhiReadbackDescription{m_outTexture}, &m_readback);
123 cb.endPass(readbackBatch);
125
126 int planeCount() const override { return 1; }
127 const QRhiReadbackResult& readback(int) const override { return m_readback; }
128
129 void release() override
130 {
131 delete m_pipeline; m_pipeline = nullptr;
132 delete m_srb; m_srb = nullptr;
133 delete m_sampler; m_sampler = nullptr;
134 delete m_rpDesc; m_rpDesc = nullptr;
135 delete m_renderTarget; m_renderTarget = nullptr;
136 delete m_outTexture; m_outTexture = nullptr;
137 }
138};
139
140} // namespace score::gfx
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
std::pair< QShader, QShader > makeShaders(const RenderState &v, QString vert, QString frag, int multiViewCount)
Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
Definition score-plugin-gfx/Gfx/Graph/Utils.cpp:1238
Base class for GPU-side video format conversion (RGBA to YUV).
Definition GPUVideoEncoder.hpp:30
static constexpr const char * vertex_shader
Definition GPUVideoEncoder.hpp:74
GPU RGBA->YUY2 encoder (packed 4:2:2, NTV2_FBF_8BIT_YCBCR_YUY2).
Definition YUY2.hpp:15
void init(QRhi &rhi, const RenderState &state, QRhiTexture *inputRGBA, int width, int height, const QString &colorConversion=colorMatrixOut()) override
Definition YUY2.hpp:66
void release() override
Release all GPU resources.
Definition YUY2.hpp:126
const QRhiReadbackResult & readback(int) const override
Get the readback result for a given plane. Valid after endOffscreenFrame.
Definition YUY2.hpp:124
int planeCount() const override
Number of readback planes (1 for UYVY, 2 for NV12, 3 for I420).
Definition YUY2.hpp:123
void exec(QRhi &rhi, QRhiCommandBuffer &cb) override
Definition YUY2.hpp:110