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(
142 " layout(binding=%1) uniform sampler2D tconst mat4 "
143 "colorspace_matrix = %2;;\n")
144 .arg(binding_orig + i)
145 .arg(i);
146 read_texture_code += QString(
147 " tex.%1 = texture(tconst mat4 colorspace_matrix = "
148 "%2;, v_texcoord).r;\n")
149 .arg(planes[i])
150 .arg(i);
151
152 // Create a texture
153 auto tex = rhi.newTexture(format, QSize{w, h}, 1, QRhiTexture::Flag{});
154 tex->create();
155
156 // Create a sampler
157 auto sampler = rhi.newSampler(
158 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
159 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
160 sampler->create();
161
162 // Store both
163 samplers.push_back({sampler, tex});
164 }
165
167 r.state, vertexShader(),
168 QString(rgb_filter).arg(samplers_code).arg(filter).arg(read_texture_code));
169 }
170
171 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
172 {
173 // Nothing particular, we just upload the whole buffer
174 for(int i = 0; i < planes.size(); i++)
175 {
176 setPixels(res, samplers[i].texture, frame.data[i], frame.linesize[i]);
177 }
178 }
179
180 void setPixels(
181 QRhiResourceUpdateBatch& res, QRhiTexture* tex, uint8_t* pixels,
182 int stride) const noexcept
183 {
184 const auto w = decoder.width, h = decoder.height;
185
186 QRhiTextureUploadEntry entry{
187 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
188
189 QRhiTextureUploadDescription desc{entry};
190 res.uploadTexture(tex, desc);
191 }
192};
193
195{
196 static const constexpr auto rgb_filter = R"_(#version 450
197
198)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
199
200 layout(binding=3) uniform sampler2DRect y_tex;
201
202 layout(location = 0) in vec2 v_texcoord;
203 layout(location = 0) out vec4 fragColor;
204
205 vec4 processTexture(vec4 tex) {
206 vec4 processed = tex;
207 { %1 }
208 return processed;
209 }
210
211 void main ()
212 {
213 fragColor = processTexture(texture(y_tex, v_texcoord));
214 })_";
215
216 static constexpr const char* vertex = R"_(#version 450
217layout(location = 0) in vec2 position;
218layout(location = 1) in vec2 texcoord;
219
220layout(location = 0) out vec2 v_texcoord;
221
222)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
223
224out gl_PerVertex { vec4 gl_Position; };
225
226void main()
227{
228 v_texcoord = texcoord * mat.texSz.xy;
229 gl_Position = renderer.clipSpaceCorrMatrix * vec4(position.x * mat.scale.x, position.y * mat.scale.y, 0.0, 1.);
230#if defined(QSHADER_HLSL) || defined(QSHADER_MSL)
231 gl_Position.y = - gl_Position.y;
232#endif
233}
234)_";
235
237 QRhiTexture::Format fmt, int bytes_per_pixel, Video::ImageFormat& d,
238 QString f = "")
239 : format{fmt}
240 , bytes_per_pixel{bytes_per_pixel}
241 , decoder{d}
242 , filter{std::move(f)}
243 {
244 }
245 QRhiTexture::Format format;
246 int bytes_per_pixel{}; // bpp/8 !
247 Video::ImageFormat& decoder;
248 QString filter;
249
250 std::pair<QShader, QShader> init(RenderList& r) override
251 {
252 auto& rhi = *r.state.rhi;
253 const auto w = decoder.width, h = decoder.height;
254
255 {
256 // Create a texture
257 auto tex = rhi.newTexture(format, QSize{w, h}, 1, QRhiTexture::Flag{});
258 tex->create();
259
260 // Create a sampler
261 auto sampler = rhi.newSampler(
262 QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
263 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
264 sampler->create();
265
266 // Store both
267 samplers.push_back({sampler, tex});
268 }
269
270 return score::gfx::makeShaders(r.state, vertex, QString(rgb_filter).arg(filter));
271 }
272
273 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
274 {
275 // Nothing particular, we just upload the whole buffer
276 setPixels(res, frame.data[0], frame.linesize[0]);
277 }
278
279 void
280 setPixels(QRhiResourceUpdateBatch& res, uint8_t* pixels, int stride) const noexcept
281 {
282 const auto w = decoder.width, h = decoder.height;
283 auto y_tex = samplers[0].texture;
284
285 QRhiTextureUploadEntry entry{
286 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
287
288 QRhiTextureUploadDescription desc{entry};
289 res.uploadTexture(y_tex, desc);
290 }
291};
292
294{
295 static const constexpr auto rgb_filter = R"_(#version 450
296
297)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
298
299 layout(binding=3) uniform sampler2D y_tex;
300
301 layout(location = 0) in vec2 v_texcoord;
302 layout(location = 0) out vec4 fragColor;
303
304 vec4 processTexture(vec4 tex) {
305 vec4 processed = tex;
306 { %1 }
307 return processed;
308 }
309
310 void main ()
311 {
312 float w = mat.texSz.x;
313 float h = mat.texSz.y;
314 int x = int(floor(v_texcoord.x * w) * 3.);
315 int y = int(v_texcoord.y * h);
316 float r = texelFetch(y_tex, ivec2(x + 0, y), 0).r;
317 float g = texelFetch(y_tex, ivec2(x + 1, y), 0).r;
318 float b = texelFetch(y_tex, ivec2(x + 2, y), 0).r;
319 fragColor = processTexture(vec4(r, g, b, 1.));
320 })_";
321
322 RGB24Decoder(Video::ImageFormat& d, QString f = "")
323 : bytes_per_pixel{3}
324 , decoder{d}
325 , filter{std::move(f)}
326 {
327 }
328 QRhiTexture::Format format;
329 int bytes_per_pixel{}; // bpp/8 !
330 Video::ImageFormat& decoder;
331 QString filter;
332
333 std::pair<QShader, QShader> init(RenderList& r) override
334 {
335 auto& rhi = *r.state.rhi;
336 const auto w = decoder.width, h = decoder.height;
337
338 {
339 // Create a texture
340 auto tex = rhi.newTexture(QRhiTexture::R8, QSize{w * 3, h}, 1, QRhiTexture::sRGB);
341 tex->create();
342
343 // Create a sampler
344 auto sampler = rhi.newSampler(
345 QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
346 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
347 sampler->create();
348
349 // Store both
350 samplers.push_back({sampler, tex});
351 }
352
354 r.state, vertexShader(), QString(rgb_filter).arg(filter));
355 }
356
357 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
358 {
359 // Nothing particular, we just upload the whole buffer
360 setPixels(res, frame.data[0], frame.linesize[0]);
361 }
362
363 void
364 setPixels(QRhiResourceUpdateBatch& res, uint8_t* pixels, int stride) const noexcept
365 {
366 const auto w = decoder.width, h = decoder.height;
367 auto y_tex = samplers[0].texture;
368
369 QRhiTextureUploadEntry entry{
370 0, 0, createTextureUpload(pixels, w, h, bytes_per_pixel, stride)};
371
372 QRhiTextureUploadDescription desc{entry};
373 res.uploadTexture(y_tex, desc);
374 }
375};
376}
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:394
Definition VideoInterface.hpp:16
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:195
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:273
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:250
Definition RGBA.hpp:92
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:171
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:130
Definition RGBA.hpp:294
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition RGBA.hpp:357
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition RGBA.hpp:333