Loading...
Searching...
No Matches
I420.hpp
1#pragma once
2#include <Gfx/Graph/encoders/GPUVideoEncoder.hpp>
3
4namespace score::gfx
5{
6
22{
23 // %1 = colorMatrixOut() shader defining convert_from_rgb(vec3)
24 static constexpr const char* y_frag = R"_(#version 450
25 layout(location = 0) in vec2 v_texcoord;
26 layout(location = 0) out vec4 fragColor;
27 layout(binding = 3) uniform sampler2D src_tex;
28 )_" "%1" R"_(
29 vec2 flip_y(vec2 tc) {
30 #if defined(QSHADER_MSL) || defined(QSHADER_HLSL)
31 return tc;
32 #else
33 return vec2(tc.x, 1.0 - tc.y);
34 #endif
35 }
36 void main() {
37 vec3 rgb = texture(src_tex, flip_y(v_texcoord)).rgb;
38 vec3 yuv = convert_from_rgb(rgb);
39 fragColor = vec4(yuv.x, 0.0, 0.0, 1.0);
40 }
41 )_";
42
43 static constexpr const char* u_frag = R"_(#version 450
44 layout(location = 0) in vec2 v_texcoord;
45 layout(location = 0) out vec4 fragColor;
46 layout(binding = 3) uniform sampler2D src_tex;
47 )_" "%1" R"_(
48 vec2 flip_y(vec2 tc) {
49 #if defined(QSHADER_MSL) || defined(QSHADER_HLSL)
50 return tc;
51 #else
52 return vec2(tc.x, 1.0 - tc.y);
53 #endif
54 }
55 void main() {
56 vec3 rgb = texture(src_tex, flip_y(v_texcoord)).rgb;
57 vec3 yuv = convert_from_rgb(rgb);
58 fragColor = vec4(yuv.y, 0.0, 0.0, 1.0);
59 }
60 )_";
61
62 static constexpr const char* v_frag = R"_(#version 450
63 layout(location = 0) in vec2 v_texcoord;
64 layout(location = 0) out vec4 fragColor;
65 layout(binding = 3) uniform sampler2D src_tex;
66 )_" "%1" R"_(
67 vec2 flip_y(vec2 tc) {
68 #if defined(QSHADER_MSL) || defined(QSHADER_HLSL)
69 return tc;
70 #else
71 return vec2(tc.x, 1.0 - tc.y);
72 #endif
73 }
74 void main() {
75 vec3 rgb = texture(src_tex, flip_y(v_texcoord)).rgb;
76 vec3 yuv = convert_from_rgb(rgb);
77 fragColor = vec4(yuv.z, 0.0, 0.0, 1.0);
78 }
79 )_";
80
81 struct PlaneResources
82 {
83 QRhiTexture* texture{};
84 QRhiTextureRenderTarget* rt{};
85 QRhiRenderPassDescriptor* rp{};
86 QRhiShaderResourceBindings* srb{};
87 QRhiGraphicsPipeline* pipeline{};
88 QRhiReadbackResult readback{};
89
90 void destroy()
91 {
92 delete pipeline;
93 delete srb;
94 delete rp;
95 delete rt;
96 delete texture;
97 pipeline = nullptr;
98 srb = nullptr;
99 rp = nullptr;
100 rt = nullptr;
101 texture = nullptr;
102 }
103 };
104
105 PlaneResources m_planes[3]; // Y, U, V
106 QRhiSampler* m_sampler{};
107 int m_width{};
108 int m_height{};
109
110 void initPlane(
111 QRhi& rhi, const RenderState& state, QRhiTexture* inputRGBA,
112 PlaneResources& plane, int w, int h, const char* fragTemplate,
113 const QString& colorConversion)
114 {
115 plane.texture = rhi.newTexture(
116 QRhiTexture::R8, QSize{w, h}, 1,
117 QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
118 plane.texture->create();
119
120 plane.rt = rhi.newTextureRenderTarget({plane.texture});
121 plane.rp = plane.rt->newCompatibleRenderPassDescriptor();
122 plane.rt->setRenderPassDescriptor(plane.rp);
123 plane.rt->create();
124
125 plane.srb = rhi.newShaderResourceBindings();
126 plane.srb->setBindings({
127 QRhiShaderResourceBinding::sampledTexture(
128 3, QRhiShaderResourceBinding::FragmentStage, inputRGBA, m_sampler),
129 });
130 plane.srb->create();
131
132 auto [vs, fs] = makeShaders(
133 state, QString::fromLatin1(vertex_shader),
134 QString::fromLatin1(fragTemplate).arg(colorConversion));
135 plane.pipeline = rhi.newGraphicsPipeline();
136 plane.pipeline->setShaderStages({
137 {QRhiShaderStage::Vertex, vs},
138 {QRhiShaderStage::Fragment, fs},
139 });
140 plane.pipeline->setVertexInputLayout({});
141 plane.pipeline->setShaderResourceBindings(plane.srb);
142 plane.pipeline->setRenderPassDescriptor(plane.rp);
143 plane.pipeline->create();
144 }
145
146 void execPlane(QRhi& rhi, QRhiCommandBuffer& cb, PlaneResources& plane, int w, int h)
147 {
148 cb.beginPass(plane.rt, Qt::black, {1.0f, 0});
149 cb.setGraphicsPipeline(plane.pipeline);
150 cb.setShaderResources(plane.srb);
151 cb.setViewport(QRhiViewport(0, 0, w, h));
152 cb.draw(3);
153
154 auto* batch = rhi.nextResourceUpdateBatch();
155 batch->readBackTexture(QRhiReadbackDescription{plane.texture}, &plane.readback);
156 cb.endPass(batch);
157 }
158
159 void init(
160 QRhi& rhi, const RenderState& state, QRhiTexture* inputRGBA, int width,
161 int height, const QString& colorConversion = colorMatrixOut()) override
162 {
163 m_width = width;
164 m_height = height;
165
166 m_sampler = rhi.newSampler(
167 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
168 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
169 m_sampler->create();
170
171 initPlane(rhi, state, inputRGBA, m_planes[0], width, height, y_frag, colorConversion);
172 initPlane(rhi, state, inputRGBA, m_planes[1], width / 2, height / 2, u_frag, colorConversion);
173 initPlane(rhi, state, inputRGBA, m_planes[2], width / 2, height / 2, v_frag, colorConversion);
175
176 void exec(QRhi& rhi, QRhiCommandBuffer& cb) override
177 {
178 execPlane(rhi, cb, m_planes[0], m_width, m_height);
179 execPlane(rhi, cb, m_planes[1], m_width / 2, m_height / 2);
180 execPlane(rhi, cb, m_planes[2], m_width / 2, m_height / 2);
182
183 int planeCount() const override { return 3; }
184
185 const QRhiReadbackResult& readback(int plane) const override
186 {
187 return m_planes[plane].readback;
188 }
189
190 void release() override
191 {
192 for(auto& p : m_planes)
193 p.destroy();
194 delete m_sampler;
195 m_sampler = nullptr;
196 }
197};
198
199} // 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->I420 encoder (planar 4:2:0).
Definition I420.hpp:22
void exec(QRhi &rhi, QRhiCommandBuffer &cb) override
Definition I420.hpp:167
const QRhiReadbackResult & readback(int plane) const override
Get the readback result for a given plane. Valid after endOffscreenFrame.
Definition I420.hpp:176
int planeCount() const override
Number of readback planes (1 for UYVY, 2 for NV12, 3 for I420).
Definition I420.hpp:174
void release() override
Release all GPU resources.
Definition I420.hpp:181