Loading...
Searching...
No Matches
Bayer.hpp
1#pragma once
3#include <Gfx/Graph/decoders/GPUVideoDecoder.hpp>
4
5#include <QString>
6
7extern "C" {
8#include <libavformat/avformat.h>
9}
10
11namespace score::gfx
12{
40{
43 enum class Phase
44 {
45 RGGB,
46 GRBG,
47 GBRG,
48 BGGR,
49 };
50
51 // %1 = user filter, %2/%3 = red-site offset, %4 = sample scale
52#define SCORE_GFX_BAYER_DEMOSAIC R"_(
53layout(binding=3) uniform sampler2D u_tex;
54
55layout(location = 0) in vec2 v_texcoord;
56layout(location = 0) out vec4 fragColor;
57
58vec4 processTexture(vec4 tex) {
59 vec4 processed = tex;
60 { %1 }
61 return processed;
62}
63
64float smp(ivec2 q, ivec2 lim) {
65 return texelFetch(u_tex, clamp(q, ivec2(0), lim), 0).r;
66}
67
68void main() {
69 ivec2 sz = textureSize(u_tex, 0);
70 ivec2 lim = sz - ivec2(1);
71 ivec2 ip = clamp(ivec2(floor(v_texcoord * vec2(sz))), ivec2(0), lim);
72
73 // (0,0) marks the red site; the other three cells follow from its parity.
74 ivec2 c = (ip + ivec2(%2, %3)) & 1;
75
76 float ctr = smp(ip, lim);
77 float n = smp(ip + ivec2( 0,-1), lim);
78 float s = smp(ip + ivec2( 0, 1), lim);
79 float w = smp(ip + ivec2(-1, 0), lim);
80 float e = smp(ip + ivec2( 1, 0), lim);
81 float nw = smp(ip + ivec2(-1,-1), lim);
82 float ne = smp(ip + ivec2( 1,-1), lim);
83 float sw = smp(ip + ivec2(-1, 1), lim);
84 float se = smp(ip + ivec2( 1, 1), lim);
85
86 float cross4 = (n + s + w + e) * 0.25;
87 float diag4 = (nw + ne + sw + se) * 0.25;
88 float horz2 = (w + e) * 0.5;
89 float vert2 = (n + s) * 0.5;
90
91 vec3 rgb;
92 if(c.x == 0 && c.y == 0)
93 rgb = vec3(ctr, cross4, diag4); // red site
94 else if(c.x == 1 && c.y == 1)
95 rgb = vec3(diag4, cross4, ctr); // blue site
96 else if(c.x == 1 && c.y == 0)
97 rgb = vec3(horz2, ctr, vert2); // green, red neighbours across
98 else
99 rgb = vec3(vert2, ctr, horz2); // green, blue neighbours across
100
101 fragColor = processTexture(vec4(adjustCapture(rgb * %4), 1.0));
102}
103)_"
104
106 static const constexpr auto frag = R"_(#version 450
107
109
112 static const constexpr auto fileFrag = R"_(#version 450
113
114)_" SCORE_GFX_VIDEO_UNIFORMS R"_(
115vec3 adjustCapture(vec3 c) { return c; }
116)_" SCORE_GFX_BAYER_DEMOSAIC;
117#undef SCORE_GFX_BAYER_DEMOSAIC
118
121 enum class Source
122 {
123 Capture,
124 File
125 };
126
128 QRhiTexture::Format fmt, int bytesPerSample, Video::ImageFormat& d,
129 Phase phase, double sampleScale = 1.0, Source source = Source::Capture,
130 QString f = "")
131 : format{fmt}
132 , bytesPerSample{bytesPerSample}
133 , decoder{d}
134 , phase{phase}
135 , sampleScale{sampleScale}
136 , source{source}
137 , filter{std::move(f)}
138 {
139 }
140
141 QRhiTexture::Format format;
142 int bytesPerSample{};
143 Video::ImageFormat& decoder;
144 Phase phase{};
145 double sampleScale{1.0};
146 Source source{Source::Capture};
147 QString filter;
148
149 std::pair<QShader, QShader> init(RenderList& r) override
150 {
151 auto& rhi = *r.state.rhi;
152 const auto w = decoder.width, h = decoder.height;
153
154 {
155 const bool supported = rhi.isTextureFormatSupported(format);
156 auto tex = rhi.newTexture(format, QSize{w, h}, 1, QRhiTexture::Flag{});
157 const bool created = tex->create();
158 if(!supported || !created)
159 qWarning() << "BayerDecoder: the backend will not give us a" << int(format)
160 << "texture at" << w << "x" << h
161 << "(supported:" << supported << "created:" << created
162 << ") -- the mosaic has nowhere to land";
163 else
164 qDebug() << "BayerDecoder:" << w << "x" << h << "format" << int(format)
165 << "ok";
166
167 // The mosaic is reconstructed per texel: linear filtering would blend
168 // neighbouring colour sites together before the demosaic can separate
169 // them, which is the same hazard the byte-reassembling decoders have.
170 auto sampler = rhi.newSampler(
171 QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
172 QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
173 sampler->create();
174
175 samplers.push_back({sampler, tex});
176 }
177
178 int px = 0, py = 0;
179 switch(phase)
180 {
181 case Phase::RGGB: px = 0; py = 0; break;
182 case Phase::GRBG: px = 1; py = 0; break;
183 case Phase::GBRG: px = 0; py = 1; break;
184 case Phase::BGGR: px = 1; py = 1; break;
185 }
186
187 const bool file = source == Source::File;
189 r.state, file ? vertexShader() : QString(score::gfx::captureVertexShader),
190 QString(file ? fileFrag : frag)
191 .arg(filter)
192 .arg(px)
193 .arg(py)
194 .arg(QString::number(sampleScale, 'f', 6)));
195 }
196
197 void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
198 {
199 auto tex = samplers[0].texture;
200 QRhiTextureUploadEntry entry{
201 0, 0,
203 frame.data[0], decoder.width, decoder.height, bytesPerSample,
204 frame.linesize[0])};
205 QRhiTextureUploadDescription desc{entry};
206 res.uploadTexture(tex, desc);
207 }
208};
209
210} // namespace score::gfx
The sensor corrections, as shader source shared by every demosaicer.
#define SCORE_GFX_CAPTURE_ADJUST_FN
Definition CaptureAdjustGLSL.hpp:48
#define SCORE_GFX_CAPTURE_UNIFORMS
Definition CaptureAdjustGLSL.hpp:30
Processes and renders a video frame on the GPU.
Definition GPUVideoDecoder.hpp:161
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:33
RenderState & state
RenderState corresponding to this RenderList.
Definition RenderList.hpp:274
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:1523
STL namespace.
Definition VideoInterface.hpp:29
Demosaics a single-channel colour-filter-array frame into RGB.
Definition Bayer.hpp:40
Phase
Definition Bayer.hpp:44
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition Bayer.hpp:149
static const constexpr auto frag
Capture inputs: the long material block, with the sensor corrections.
Definition Bayer.hpp:106
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition Bayer.hpp:197
Source
Definition Bayer.hpp:122
static const constexpr auto fileFrag
Definition Bayer.hpp:112