Loading...
Searching...
No Matches
RGBA.hpp
1#pragma once
2#include <Gfx/Graph/decoders/GPUVideoDecoder.hpp>
3extern "C" {
4#include <libavformat/avformat.h>
5}
6
7namespace score::gfx
8{
10{
11 static const constexpr auto rgb_filter = R"_(#version 450
12
13)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
14
15 layout(binding=3) uniform sampler2D y_tex;
16
17 layout(location = 0) in vec2 v_texcoord;
18 layout(location = 0) out vec4 fragColor;
19
20 vec4 processTexture(vec4 tex) {
21 vec4 processed = tex;
22 { %1 }
23 return processed;
24 }
25
26 void main ()
27 {
28 fragColor = processTexture(texture(y_tex, v_texcoord));
29 })_";
30
32 QRhiTexture::Format fmt, int bytes_per_pixel, Video::ImageFormat& d,
33 QString f = "", bool invertY = false)
34 : format{fmt}
35 , bytes_per_pixel{bytes_per_pixel}
36 , decoder{d}
37 , filter{std::move(f)}
38 , invertY{invertY}
39 {
40 }
41 QRhiTexture::Format format;
42 int bytes_per_pixel{}; // bpp/8 !
43 bool invertY{}; // Mainly useful for Spout texture import
44 Video::ImageFormat& decoder;
45 QString filter;
46
47 std::pair<QShader, QShader> init(RenderList& r) override
48 {
49 auto& rhi = *r.state.rhi;
50 const auto w = decoder.width, h = decoder.height;
51
52 {
53 // Create a texture
54 auto tex = rhi.newTexture(format, QSize{w, h}, 1, QRhiTexture::Flag{});
55 tex->create();
56
57 // Create a sampler
58 auto sampler = rhi.newSampler(
59 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
60 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
61 sampler->create();
62
63 // Store both
64 samplers.push_back({sampler, tex});
65 }
66
68 r.state, vertexShader(invertY), QString(rgb_filter).arg(filter));
69 }
70
71 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
72 {
73 // Nothing particular, we just upload the whole buffer
74 setPixels(res, frame.data[0], frame.linesize[0]);
75 }
76
77 void
78 setPixels(QRhiResourceUpdateBatch& res, uint8_t* pixels, int stride) const noexcept
79 {
80 const auto w = decoder.width, h = decoder.height;
81 auto y_tex = samplers[0].texture;
82
83 QRhiTextureUploadEntry entry{
84 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
85
86 QRhiTextureUploadDescription desc{entry};
87 res.uploadTexture(y_tex, desc);
88 }
89};
90
92{
93 static const constexpr auto rgb_filter = R"_(#version 450
94
95)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
96
97 %1
98 layout(location = 0) in vec2 v_texcoord;
99 layout(location = 0) out vec4 fragColor;
100
101 vec4 processTexture(vec4 tex) {
102 vec4 processed = tex;
103 { %2 }
104 return processed;
105 }
106
107 void main ()
108 {
109 vec4 tex = vec4(1.);
110 %3
111 fragColor = processTexture(tex);
112 })_";
113
115 QRhiTexture::Format fmt, int bytes_per_pixel, QString planes,
116 Video::ImageFormat& d, QString f = "")
117 : format{fmt}
118 , bytes_per_pixel{bytes_per_pixel}
119 , planes{planes}
120 , decoder{d}
121 , filter{std::move(f)}
122 {
123 }
124 QRhiTexture::Format format;
125 int bytes_per_pixel{}; // bpp/8 !
126 QString planes{};
127 Video::ImageFormat& decoder;
128 QString filter;
129
130 std::pair<QShader, QShader> init(RenderList& r) override
131 {
132 auto& rhi = *r.state.rhi;
133 const auto w = decoder.width, h = decoder.height;
134
135 QString samplers_code;
136 QString read_texture_code;
137
138 const int binding_orig = 3;
139 for(int i = 0; i < planes.size(); i++)
140 {
141 samplers_code += QString(" layout(binding=%1) uniform sampler2D t%2;\n")
142 .arg(binding_orig + i)
143 .arg(i);
144 read_texture_code
145 += QString(" tex.%1 = texture(t%2, v_texcoord).r;\n")
146 .arg(planes[i])
147 .arg(i);
148
149 // Create a texture
150 auto tex = rhi.newTexture(format, QSize{w, h}, 1, QRhiTexture::Flag{});
151 tex->create();
152
153 // Create a sampler
154 auto sampler = rhi.newSampler(
155 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
156 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
157 sampler->create();
158
159 // Store both
160 samplers.push_back({sampler, tex});
161 }
162
164 r.state, vertexShader(),
165 QString(rgb_filter).arg(samplers_code).arg(filter).arg(read_texture_code));
166 }
167
168 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
169 {
170 // Nothing particular, we just upload the whole buffer
171 for(int i = 0; i < planes.size(); i++)
172 {
173 setPixels(res, samplers[i].texture, frame.data[i], frame.linesize[i]);
174 }
175 }
176
177 void setPixels(
178 QRhiResourceUpdateBatch& res, QRhiTexture* tex, uint8_t* pixels,
179 int stride) const noexcept
180 {
181 const auto w = decoder.width, h = decoder.height;
182
183 QRhiTextureUploadEntry entry{
184 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
185
186 QRhiTextureUploadDescription desc{entry};
187 res.uploadTexture(tex, desc);
188 }
189};
190
192{
193 static const constexpr auto rgb_filter = R"_(#version 450
194
195)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
196
197 layout(binding=3) uniform sampler2DRect y_tex;
198
199 layout(location = 0) in vec2 v_texcoord;
200 layout(location = 0) out vec4 fragColor;
201
202 vec4 processTexture(vec4 tex) {
203 vec4 processed = tex;
204 { %1 }
205 return processed;
206 }
207
208 void main ()
209 {
210 fragColor = processTexture(texture(y_tex, v_texcoord));
211 })_";
212
213 static constexpr const char* vertex = R"_(#version 450
214layout(location = 0) in vec2 position;
215layout(location = 1) in vec2 texcoord;
216
217layout(location = 0) out vec2 v_texcoord;
218
219)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
220
221out gl_PerVertex { vec4 gl_Position; };
222
223void main()
224{
225 v_texcoord = texcoord * mat.texSz.xy;
226 gl_Position = renderer.clipSpaceCorrMatrix * vec4(position.x * mat.scale.x, position.y * mat.scale.y, 0.0, 1.);
227#if defined(QSHADER_HLSL) || defined(QSHADER_MSL)
228 gl_Position.y = - gl_Position.y;
229#endif
230}
231)_";
232
234 QRhiTexture::Format fmt, int bytes_per_pixel, Video::ImageFormat& d,
235 QString f = "")
236 : format{fmt}
237 , bytes_per_pixel{bytes_per_pixel}
238 , decoder{d}
239 , filter{std::move(f)}
240 {
241 }
242 QRhiTexture::Format format;
243 int bytes_per_pixel{}; // bpp/8 !
244 Video::ImageFormat& decoder;
245 QString filter;
246
247 std::pair<QShader, QShader> init(RenderList& r) override
248 {
249 auto& rhi = *r.state.rhi;
250 const auto w = decoder.width, h = decoder.height;
251
252 {
253 // Create a texture
254 auto tex = rhi.newTexture(format, QSize{w, h}, 1, QRhiTexture::Flag{});
255 tex->create();
256
257 // Create a sampler
258 auto sampler = rhi.newSampler(
259 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
260 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
261 sampler->create();
262
263 // Store both
264 samplers.push_back({sampler, tex});
265 }
266
267 return score::gfx::makeShaders(r.state, vertex, QString(rgb_filter).arg(filter));
268 }
269
270 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
271 {
272 // Nothing particular, we just upload the whole buffer
273 setPixels(res, frame.data[0], frame.linesize[0]);
274 }
275
276 void
277 setPixels(QRhiResourceUpdateBatch& res, uint8_t* pixels, int stride) const noexcept
278 {
279 const auto w = decoder.width, h = decoder.height;
280 auto y_tex = samplers[0].texture;
281
282 QRhiTextureUploadEntry entry{
283 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
284
285 QRhiTextureUploadDescription desc{entry};
286 res.uploadTexture(y_tex, desc);
287 }
288};
289
291{
292 static const constexpr auto rgb_filter = R"_(#version 450
293
294)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
295
296 layout(binding=3) uniform sampler2D y_tex;
297
298 layout(location = 0) in vec2 v_texcoord;
299 layout(location = 0) out vec4 fragColor;
300
301 vec4 processTexture(vec4 tex) {
302 vec4 processed = tex;
303 { %1 }
304 return processed;
305 }
306
307 void main ()
308 {
309 float w = mat.texSz.x;
310 float h = mat.texSz.y;
311 int x = int(floor(v_texcoord.x * w) * 3.);
312 int y = int(v_texcoord.y * h);
313 float r = texelFetch(y_tex, ivec2(x + 0, y), 0).r;
314 float g = texelFetch(y_tex, ivec2(x + 1, y), 0).r;
315 float b = texelFetch(y_tex, ivec2(x + 2, y), 0).r;
316 fragColor = processTexture(vec4(r, g, b, 1.));
317 })_";
318
319 RGB24Decoder(Video::ImageFormat& d, QString f = "")
320 : bytes_per_pixel{3}
321 , decoder{d}
322 , filter{std::move(f)}
323 {
324 }
325 int bytes_per_pixel{}; // bpp/8 !
326 Video::ImageFormat& decoder;
327 QString filter;
328
329 std::pair<QShader, QShader> init(RenderList& r) override
330 {
331 auto& rhi = *r.state.rhi;
332 const auto w = decoder.width, h = decoder.height;
333
334 {
335 // Create a texture
336 auto tex = rhi.newTexture(QRhiTexture::R8, QSize{w * 3, h}, 1, QRhiTexture::sRGB);
337 tex->create();
338
339 // Create a sampler
340 auto sampler = rhi.newSampler(
341 QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
342 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
343 sampler->create();
344
345 // Store both
346 samplers.push_back({sampler, tex});
347 }
348
350 r.state, vertexShader(), QString(rgb_filter).arg(filter));
351 }
352
353 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
354 {
355 // Nothing particular, we just upload the whole buffer
356 setPixels(res, frame.data[0], frame.linesize[0]);
357 }
358
359 void
360 setPixels(QRhiResourceUpdateBatch& res, uint8_t* pixels, int stride) const noexcept
361 {
362 const auto w = decoder.width, h = decoder.height;
363 auto y_tex = samplers[0].texture;
364
365 QRhiTextureUploadEntry entry{
366 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
367
368 QRhiTextureUploadDescription desc{entry};
369 res.uploadTexture(y_tex, desc);
370 }
371};
372
374{
375 static const constexpr auto rgb_filter = R"_(#version 450
376
377)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
378
379 layout(binding=3) uniform sampler2D y_tex;
380
381 layout(location = 0) in vec2 v_texcoord;
382 layout(location = 0) out vec4 fragColor;
383
384 vec4 processTexture(vec4 tex) {
385 vec4 processed = tex;
386 { %1 }
387 return processed;
388 }
389
390 void main ()
391 {
392 float w = mat.texSz.x;
393 float h = mat.texSz.y;
394 int x = int(floor(v_texcoord.x * w) * 3.);
395 int y = int(v_texcoord.y * h);
396 float r = texelFetch(y_tex, ivec2(x + 0, y), 0).r;
397 float g = texelFetch(y_tex, ivec2(x + 1, y), 0).r;
398 float b = texelFetch(y_tex, ivec2(x + 2, y), 0).r;
399 fragColor = processTexture(vec4(r, g, b, 1.));
400 })_";
401
402 RGB48Decoder(Video::ImageFormat& d, QString f = "")
403 : decoder{d}
404 , filter{std::move(f)}
405 {
406 }
407 Video::ImageFormat& decoder;
408 QString filter;
409
410 std::pair<QShader, QShader> init(RenderList& r) override
411 {
412 auto& rhi = *r.state.rhi;
413 const auto w = decoder.width, h = decoder.height;
414
415 {
416 auto tex = rhi.newTexture(QRhiTexture::R16, QSize{w * 3, h}, 1, QRhiTexture::Flag{});
417 tex->create();
418
419 auto sampler = rhi.newSampler(
420 QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
421 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
422 sampler->create();
423
424 samplers.push_back({sampler, tex});
425 }
426
428 r.state, vertexShader(), QString(rgb_filter).arg(filter));
429 }
430
431 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
432 {
433 const auto w = decoder.width, h = decoder.height;
434 auto y_tex = samplers[0].texture;
435
436 // 3 R16 samples per pixel = 6 bytes per pixel
437 QRhiTextureUploadEntry entry{
438 0, 0, createTextureUpload(frame.data[0], w * 3, h, 2, frame.linesize[0])};
439
440 QRhiTextureUploadDescription desc{entry};
441 res.uploadTexture(y_tex, desc);
442 }
443};
444
445}
446
Processes and renders a video frame on the GPU.
Definition GPUVideoDecoder.hpp:43
static QRhiTextureSubresourceUploadDescription createTextureUpload(uint8_t *pixels, int w, int h, int bytesPerPixel, int stride)
Utility method to create a QRhiTextureSubresourceUploadDescription.
Definition GPUVideoDecoder.cpp:22
List of nodes to be rendered to an output.
Definition RenderList.hpp:19
RenderState & state
RenderState corresponding to this RenderList.
Definition RenderList.hpp:94
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
Definition VideoInterface.hpp:26
Definition RGBA.hpp:10
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:47
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:71
Definition RGBA.hpp:192
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:270
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:247
Definition RGBA.hpp:92
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:168
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:130
Definition RGBA.hpp:291
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:353
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:329
Definition RGBA.hpp:374
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:410
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:431