• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * The YUY2 shader code is based on face-responder. The code is under public domain:
3  * https://bitbucket.org/nateharward/face-responder/src/0c3b4b957039d9f4bf1da09b9471371942de2601/yuv42201_laplace.frag?at=master
4  *
5  * All other OpenGL code:
6  *
7  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
8  *
9  * This program is free software; you may redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; version 2 of the License.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
17  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
23 #include "capture-win-gl.h"
24 
25 #include <stdio.h>
26 
CaptureWinGL(ApplicationWindow * aw)27 CaptureWinGL::CaptureWinGL(ApplicationWindow *aw) :
28 	CaptureWin(aw)
29 {
30 #ifdef HAVE_QTGL
31 	CaptureWin::buildWindow(&m_videoSurface);
32 #endif
33 	CaptureWin::setWindowTitle("V4L2 Capture (OpenGL)");
34 }
35 
~CaptureWinGL()36 CaptureWinGL::~CaptureWinGL()
37 {
38 }
39 
stop()40 void CaptureWinGL::stop()
41 {
42 #ifdef HAVE_QTGL
43 	m_videoSurface.stop();
44 #endif
45 }
46 
closeEvent(QCloseEvent * event)47 void CaptureWinGL::closeEvent(QCloseEvent *event)
48 {
49 	this->hide();
50 	event->ignore();
51 	emit close();
52 }
53 
resizeEvent(QResizeEvent * event)54 void CaptureWinGL::resizeEvent(QResizeEvent *event)
55 {
56 #ifdef HAVE_QTGL
57 	// Get size of frame viewport. Can't use size of m_videoSurface
58 	// since it is a subwidget of this widget.
59 	QSize margins = getMargins();
60 	m_windowSize = size() - margins;
61 	// Re-calculate sizes
62 	m_frame.updated = true;
63 	CaptureWin::updateSize();
64 	// Lock viewport size to follow calculated size
65 	m_videoSurface.lockSize(m_scaledSize);
66 #endif
67 	event->accept();
68 }
69 
setRenderFrame()70 void CaptureWinGL::setRenderFrame()
71 {
72 #ifdef HAVE_QTGL
73 	m_videoSurface.setFrame(m_frame.size.width(), m_frame.size.height(),
74 				m_crop.delta.width(), m_crop.delta.height(),
75 				m_frame.format,
76 				m_frame.planeData[0],
77 				m_frame.planeData[1],
78 				m_frame.planeData[2]);
79 #endif
80 	m_frame.updated = false;
81 	m_crop.updated = false;
82 }
83 
hasNativeFormat(__u32 format)84 bool CaptureWinGL::hasNativeFormat(__u32 format)
85 {
86 #ifdef HAVE_QTGL
87 	return m_videoSurface.hasNativeFormat(format);
88 #else
89 	return false;
90 #endif
91 }
92 
isSupported()93 bool CaptureWinGL::isSupported()
94 {
95 #ifdef HAVE_QTGL
96 	return true;
97 #else
98 	return false;
99 #endif
100 }
101 
setColorspace(unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization,bool is_sdtv)102 void CaptureWinGL::setColorspace(unsigned colorspace, unsigned xfer_func,
103 		unsigned ycbcr_enc, unsigned quantization, bool is_sdtv)
104 {
105 #ifdef HAVE_QTGL
106 	m_videoSurface.setColorspace(colorspace, xfer_func,
107 			ycbcr_enc, quantization, is_sdtv);
108 #endif
109 }
110 
setField(unsigned field)111 void CaptureWinGL::setField(unsigned field)
112 {
113 #ifdef HAVE_QTGL
114 	m_videoSurface.setField(field);
115 #endif
116 }
117 
setBlending(bool enable)118 void CaptureWinGL::setBlending(bool enable)
119 {
120 #ifdef HAVE_QTGL
121 	m_videoSurface.setBlending(enable);
122 #endif
123 }
124 
setLinearFilter(bool enable)125 void CaptureWinGL::setLinearFilter(bool enable)
126 {
127 #ifdef HAVE_QTGL
128 	m_videoSurface.setLinearFilter(enable);
129 #endif
130 }
131 
132 #ifdef HAVE_QTGL
CaptureWinGLEngine()133 CaptureWinGLEngine::CaptureWinGLEngine() :
134 	m_frameWidth(0),
135 	m_frameHeight(0),
136 	m_WCrop(0),
137 	m_HCrop(0),
138 	m_colorspace(V4L2_COLORSPACE_REC709),
139 	m_xfer_func(V4L2_XFER_FUNC_DEFAULT),
140 	m_ycbcr_enc(V4L2_YCBCR_ENC_DEFAULT),
141 	m_quantization(V4L2_QUANTIZATION_DEFAULT),
142 	m_is_sdtv(false),
143 	m_is_rgb(false),
144 	m_field(V4L2_FIELD_NONE),
145 	m_screenTextureCount(0),
146 	m_formatChange(false),
147 	m_frameFormat(0),
148 	m_frameData(NULL),
149 	m_blending(false),
150 	m_mag_filter(GL_NEAREST),
151 	m_min_filter(GL_NEAREST)
152 {
153 	makeCurrent();
154 #if QT_VERSION < 0x060000
155 	m_glfunction.initializeGLFunctions(context());
156 #endif
157 }
158 
~CaptureWinGLEngine()159 CaptureWinGLEngine::~CaptureWinGLEngine()
160 {
161 	clearShader();
162 }
163 
setColorspace(unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization,bool is_sdtv)164 void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
165 		unsigned ycbcr_enc, unsigned quantization, bool is_sdtv)
166 {
167 	bool is_rgb = true;
168 
169 	switch (m_frameFormat) {
170 	case V4L2_PIX_FMT_YUYV:
171 	case V4L2_PIX_FMT_YVYU:
172 	case V4L2_PIX_FMT_UYVY:
173 	case V4L2_PIX_FMT_VYUY:
174 	case V4L2_PIX_FMT_YUV422M:
175 	case V4L2_PIX_FMT_YVU422M:
176 	case V4L2_PIX_FMT_YUV422P:
177 	case V4L2_PIX_FMT_YVU420:
178 	case V4L2_PIX_FMT_YUV420:
179 	case V4L2_PIX_FMT_YVU420M:
180 	case V4L2_PIX_FMT_YUV420M:
181 	case V4L2_PIX_FMT_NV12:
182 	case V4L2_PIX_FMT_NV21:
183 	case V4L2_PIX_FMT_NV12M:
184 	case V4L2_PIX_FMT_NV21M:
185 	case V4L2_PIX_FMT_NV16:
186 	case V4L2_PIX_FMT_NV61:
187 	case V4L2_PIX_FMT_NV16M:
188 	case V4L2_PIX_FMT_NV61M:
189 	case V4L2_PIX_FMT_NV24:
190 	case V4L2_PIX_FMT_NV42:
191 	case V4L2_PIX_FMT_YUV444M:
192 	case V4L2_PIX_FMT_YVU444M:
193 	case V4L2_PIX_FMT_YUV444:
194 	case V4L2_PIX_FMT_YUV555:
195 	case V4L2_PIX_FMT_YUV565:
196 	case V4L2_PIX_FMT_YUV32:
197 	case V4L2_PIX_FMT_AYUV32:
198 	case V4L2_PIX_FMT_XYUV32:
199 	case V4L2_PIX_FMT_VUYA32:
200 	case V4L2_PIX_FMT_VUYX32:
201 	case V4L2_PIX_FMT_YUVA32:
202 	case V4L2_PIX_FMT_YUVX32:
203 	case V4L2_PIX_FMT_HSV24:
204 	case V4L2_PIX_FMT_HSV32:
205 		is_rgb = false;
206 		break;
207 	}
208 
209 	switch (colorspace) {
210 	case V4L2_COLORSPACE_SMPTE170M:
211 	case V4L2_COLORSPACE_SMPTE240M:
212 	case V4L2_COLORSPACE_REC709:
213 	case V4L2_COLORSPACE_470_SYSTEM_M:
214 	case V4L2_COLORSPACE_470_SYSTEM_BG:
215 	case V4L2_COLORSPACE_SRGB:
216 	case V4L2_COLORSPACE_OPRGB:
217 	case V4L2_COLORSPACE_BT2020:
218 	case V4L2_COLORSPACE_DCI_P3:
219 		break;
220 	default:
221 		// If the colorspace was not specified, then guess
222 		// based on the pixel format.
223 		if (is_rgb)
224 			colorspace = V4L2_COLORSPACE_SRGB;
225 		else if (is_sdtv)
226 			colorspace = V4L2_COLORSPACE_SMPTE170M;
227 		else
228 			colorspace = V4L2_COLORSPACE_REC709;
229 		break;
230 	}
231 	if (m_colorspace == colorspace && m_xfer_func == xfer_func &&
232 	    m_ycbcr_enc == ycbcr_enc && m_quantization == quantization &&
233 	    m_is_sdtv == is_sdtv && m_is_rgb == is_rgb)
234 		return;
235 	m_colorspace = colorspace;
236 	if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
237 		xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
238 	if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
239 		ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
240 	if (quantization == V4L2_QUANTIZATION_DEFAULT)
241 		quantization = V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, colorspace, ycbcr_enc);
242 	m_xfer_func = xfer_func;
243 	m_ycbcr_enc = ycbcr_enc;
244 	m_quantization = quantization;
245 	m_is_sdtv = is_sdtv;
246 	m_is_rgb = is_rgb;
247 	m_formatChange = true;
248 }
249 
setField(unsigned field)250 void CaptureWinGLEngine::setField(unsigned field)
251 {
252 	if (m_field == field)
253 		return;
254 	m_field = field;
255 	m_formatChange = true;
256 }
257 
setLinearFilter(bool enable)258 void CaptureWinGLEngine::setLinearFilter(bool enable)
259 {
260 	if (enable) {
261 		m_mag_filter = GL_LINEAR;
262 		m_min_filter = GL_LINEAR;
263 	}
264 	else {
265 		m_mag_filter = GL_NEAREST;
266 		m_min_filter = GL_NEAREST;
267 	}
268 	m_formatChange = true;
269 }
270 
clearShader()271 void CaptureWinGLEngine::clearShader()
272 {
273 	if (m_screenTextureCount)
274 		glDeleteTextures(m_screenTextureCount, m_screenTexture);
275 	if (m_shaderProgram.isLinked()) {
276 		m_shaderProgram.release();
277 		m_shaderProgram.removeAllShaders();
278 	}
279 }
280 
stop()281 void CaptureWinGLEngine::stop()
282 {
283 	// Setting the m_frameData to NULL stops OpenGL
284 	// from updating frames on repaint
285 	m_frameData = NULL;
286 	m_frameData2 = NULL;
287 }
288 
initializeGL()289 void CaptureWinGLEngine::initializeGL()
290 {
291 #if QT_VERSION >= 0x060000
292 	initializeOpenGLFunctions();
293 #endif
294 	glShadeModel(GL_FLAT);
295 	glEnable(GL_TEXTURE_2D);
296 	glEnable(GL_BLEND);
297 	glDisable(GL_DEPTH_TEST);
298 
299 	// Check if the the GL_FRAMEBUFFER_SRGB feature is available.
300 	// If it is, then the GPU can perform the SRGB transfer function
301 	// for us.
302 	GLint res = 0;
303 	glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &res);
304 	// With Qt6 enabling sRGB results in dark colors for some reason.
305 	// It is fine with Qt5.
306 	// Since qvidcap also ignores this (i.e. it never enables sRGB)
307 	// I decided to do the same for qv4l2, so just set this to false.
308 	m_haveFramebufferSRGB = false;
309 	if (m_haveFramebufferSRGB)
310 		glEnable(GL_FRAMEBUFFER_SRGB);
311 	m_hasGLRed = glGetString(GL_VERSION)[0] >= '3';
312 	m_glRed = m_hasGLRed ? GL_RED : GL_LUMINANCE;
313 	m_glRed16 = m_hasGLRed ? GL_R16 : GL_LUMINANCE;
314 	m_glRedGreen = m_hasGLRed ? GL_RG : GL_LUMINANCE_ALPHA;
315 
316 	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
317 	glBlendFunc(GL_ONE, GL_ZERO);
318 	checkError("InitializeGL");
319 }
320 
lockSize(QSize size)321 void CaptureWinGLEngine::lockSize(QSize size)
322 {
323 	if ((size.width() > 0) && (size.height() > 0)) {
324 		setFixedSize(size);
325 	}
326 }
327 
resizeGL(int width,int height)328 void CaptureWinGLEngine::resizeGL(int width, int height)
329 {
330 	glViewport(0, 0, width, height);
331 }
332 
setFrame(int width,int height,int WCrop,int HCrop,__u32 format,unsigned char * data,unsigned char * data2,unsigned char * data3)333 void CaptureWinGLEngine::setFrame(int width, int height, int WCrop, int HCrop,
334 				  __u32 format, unsigned char *data, unsigned char *data2,
335 				  unsigned char *data3)
336 {
337 	if (format != m_frameFormat || width != m_frameWidth || height != m_frameHeight
338 	    || WCrop != m_WCrop || HCrop != m_HCrop) {
339 		m_formatChange = true;
340 		m_frameWidth = width;
341 		m_frameHeight = height;
342 		m_WCrop = WCrop;
343 		m_HCrop = HCrop;
344 		m_frameFormat = format;
345 	}
346 
347 	m_frameData = data;
348 	m_frameData2 = data2 ? data2 : data;
349 	m_frameData3 = data3 ? data3 : data;
350 #if QT_VERSION < 0x060000
351 	updateGL();
352 #else
353 	update();
354 #endif
355 }
356 
checkError(const char * msg)357 void CaptureWinGLEngine::checkError(const char *msg)
358 {
359 	int err = glGetError();
360 	if (err) fprintf(stderr, "OpenGL Error 0x%x: %s.\n", err, msg);
361 }
362 
hasNativeFormat(__u32 format)363 bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
364 {
365 	static const __u32 supported_fmts[] = {
366 		V4L2_PIX_FMT_RGB32,
367 		V4L2_PIX_FMT_XRGB32,
368 		V4L2_PIX_FMT_ARGB32,
369 		V4L2_PIX_FMT_BGR32,
370 		V4L2_PIX_FMT_XBGR32,
371 		V4L2_PIX_FMT_ABGR32,
372 		V4L2_PIX_FMT_RGB24,
373 		V4L2_PIX_FMT_BGR24,
374 		V4L2_PIX_FMT_RGB565,
375 		V4L2_PIX_FMT_RGB565X,
376 		V4L2_PIX_FMT_RGB444,
377 		V4L2_PIX_FMT_XRGB444,
378 		V4L2_PIX_FMT_ARGB444,
379 		V4L2_PIX_FMT_RGB555,
380 		V4L2_PIX_FMT_XRGB555,
381 		V4L2_PIX_FMT_ARGB555,
382 		V4L2_PIX_FMT_RGB555X,
383 		V4L2_PIX_FMT_XRGB555X,
384 		V4L2_PIX_FMT_ARGB555X,
385 		V4L2_PIX_FMT_RGB332,
386 		V4L2_PIX_FMT_BGR666,
387 		V4L2_PIX_FMT_SBGGR8,
388 		V4L2_PIX_FMT_SGBRG8,
389 		V4L2_PIX_FMT_SGRBG8,
390 		V4L2_PIX_FMT_SRGGB8,
391 		V4L2_PIX_FMT_SBGGR10,
392 		V4L2_PIX_FMT_SGBRG10,
393 		V4L2_PIX_FMT_SGRBG10,
394 		V4L2_PIX_FMT_SRGGB10,
395 		V4L2_PIX_FMT_SBGGR12,
396 		V4L2_PIX_FMT_SGBRG12,
397 		V4L2_PIX_FMT_SGRBG12,
398 		V4L2_PIX_FMT_SRGGB12,
399 		V4L2_PIX_FMT_SBGGR16,
400 		V4L2_PIX_FMT_SGBRG16,
401 		V4L2_PIX_FMT_SGRBG16,
402 		V4L2_PIX_FMT_SRGGB16,
403 		V4L2_PIX_FMT_YUYV,
404 		V4L2_PIX_FMT_YVYU,
405 		V4L2_PIX_FMT_UYVY,
406 		V4L2_PIX_FMT_VYUY,
407 		V4L2_PIX_FMT_YUV422M,
408 		V4L2_PIX_FMT_YVU422M,
409 		V4L2_PIX_FMT_YUV422P,
410 		V4L2_PIX_FMT_YVU420,
411 		V4L2_PIX_FMT_YUV420,
412 		V4L2_PIX_FMT_NV12,
413 		V4L2_PIX_FMT_NV21,
414 		V4L2_PIX_FMT_NV16,
415 		V4L2_PIX_FMT_NV61,
416 		V4L2_PIX_FMT_NV24,
417 		V4L2_PIX_FMT_NV42,
418 		V4L2_PIX_FMT_YUV444M,
419 		V4L2_PIX_FMT_YVU444M,
420 		V4L2_PIX_FMT_NV16M,
421 		V4L2_PIX_FMT_NV61M,
422 		V4L2_PIX_FMT_YVU420M,
423 		V4L2_PIX_FMT_YUV420M,
424 		V4L2_PIX_FMT_NV12M,
425 		V4L2_PIX_FMT_NV21M,
426 		V4L2_PIX_FMT_YUV444,
427 		V4L2_PIX_FMT_YUV555,
428 		V4L2_PIX_FMT_YUV565,
429 		V4L2_PIX_FMT_YUV32,
430 		V4L2_PIX_FMT_AYUV32,
431 		V4L2_PIX_FMT_XYUV32,
432 		V4L2_PIX_FMT_VUYA32,
433 		V4L2_PIX_FMT_VUYX32,
434 		V4L2_PIX_FMT_YUVA32,
435 		V4L2_PIX_FMT_YUVX32,
436 		V4L2_PIX_FMT_GREY,
437 		V4L2_PIX_FMT_Z16,
438 		V4L2_PIX_FMT_INZI,
439 		V4L2_PIX_FMT_Y10,
440 		V4L2_PIX_FMT_Y12,
441 		V4L2_PIX_FMT_Y16,
442 		V4L2_PIX_FMT_Y16_BE,
443 		V4L2_PIX_FMT_HSV24,
444 		V4L2_PIX_FMT_HSV32,
445 		0
446 	};
447 
448 #if QT_VERSION < 0x060000
449 	if (!m_glfunction.hasOpenGLFeature(QGLFunctions::Shaders))
450 		return false;
451 #else
452 	if (!hasOpenGLFeature(QOpenGLFunctions::Shaders))
453 		return false;
454 #endif
455 
456 	for (int i = 0; supported_fmts[i]; i++)
457 		if (supported_fmts[i] == format)
458 			return true;
459 
460 	return false;
461 }
462 
changeShader()463 void CaptureWinGLEngine::changeShader()
464 {
465 	m_formatChange = false;
466 	clearShader();
467 
468 	glMatrixMode(GL_PROJECTION);
469 	glLoadIdentity();
470 	glOrtho(0, m_frameWidth, m_frameHeight, 0, 0, 1);
471 #if QT_VERSION < 0x060000
472 	resizeGL(QGLWidget::width(), QGLWidget::height());
473 #else
474 	resizeGL(QOpenGLWidget::width(), QOpenGLWidget::height());
475 #endif
476 	checkError("Render settings.\n");
477 
478 	switch (m_frameFormat) {
479 	case V4L2_PIX_FMT_YUYV:
480 	case V4L2_PIX_FMT_YVYU:
481 	case V4L2_PIX_FMT_UYVY:
482 	case V4L2_PIX_FMT_VYUY:
483 		shader_YUY2(m_frameFormat);
484 		break;
485 
486 	case V4L2_PIX_FMT_NV16:
487 	case V4L2_PIX_FMT_NV61:
488 	case V4L2_PIX_FMT_NV16M:
489 	case V4L2_PIX_FMT_NV61M:
490 		shader_NV16(m_frameFormat);
491 		break;
492 
493 	case V4L2_PIX_FMT_NV12:
494 	case V4L2_PIX_FMT_NV21:
495 	case V4L2_PIX_FMT_NV12M:
496 	case V4L2_PIX_FMT_NV21M:
497 		shader_NV12(m_frameFormat);
498 		break;
499 
500 	case V4L2_PIX_FMT_NV24:
501 	case V4L2_PIX_FMT_NV42:
502 		shader_NV24(m_frameFormat);
503 		break;
504 
505 	case V4L2_PIX_FMT_YUV444:
506 	case V4L2_PIX_FMT_YUV555:
507 	case V4L2_PIX_FMT_YUV565:
508 	case V4L2_PIX_FMT_YUV32:
509 	case V4L2_PIX_FMT_AYUV32:
510 	case V4L2_PIX_FMT_XYUV32:
511 	case V4L2_PIX_FMT_VUYA32:
512 	case V4L2_PIX_FMT_VUYX32:
513 	case V4L2_PIX_FMT_YUVA32:
514 	case V4L2_PIX_FMT_YUVX32:
515 		shader_YUV_packed(m_frameFormat);
516 		break;
517 
518 	case V4L2_PIX_FMT_YUV422P:
519 	case V4L2_PIX_FMT_YUV420:
520 	case V4L2_PIX_FMT_YVU420:
521 	case V4L2_PIX_FMT_YUV420M:
522 	case V4L2_PIX_FMT_YVU420M:
523 	case V4L2_PIX_FMT_YUV422M:
524 	case V4L2_PIX_FMT_YVU422M:
525 	case V4L2_PIX_FMT_YUV444M:
526 	case V4L2_PIX_FMT_YVU444M:
527 		shader_YUV(m_frameFormat);
528 		break;
529 
530 	case V4L2_PIX_FMT_SBGGR8:
531 	case V4L2_PIX_FMT_SGBRG8:
532 	case V4L2_PIX_FMT_SGRBG8:
533 	case V4L2_PIX_FMT_SRGGB8:
534 	case V4L2_PIX_FMT_SBGGR10:
535 	case V4L2_PIX_FMT_SGBRG10:
536 	case V4L2_PIX_FMT_SGRBG10:
537 	case V4L2_PIX_FMT_SRGGB10:
538 	case V4L2_PIX_FMT_SBGGR12:
539 	case V4L2_PIX_FMT_SGBRG12:
540 	case V4L2_PIX_FMT_SGRBG12:
541 	case V4L2_PIX_FMT_SRGGB12:
542 	case V4L2_PIX_FMT_SBGGR16:
543 	case V4L2_PIX_FMT_SGBRG16:
544 	case V4L2_PIX_FMT_SGRBG16:
545 	case V4L2_PIX_FMT_SRGGB16:
546 		shader_Bayer(m_frameFormat);
547 		break;
548 
549 	case V4L2_PIX_FMT_RGB332:
550 	case V4L2_PIX_FMT_BGR666:
551 	case V4L2_PIX_FMT_RGB555:
552 	case V4L2_PIX_FMT_XRGB555:
553 	case V4L2_PIX_FMT_ARGB555:
554 	case V4L2_PIX_FMT_RGB444:
555 	case V4L2_PIX_FMT_XRGB444:
556 	case V4L2_PIX_FMT_ARGB444:
557 	case V4L2_PIX_FMT_RGB555X:
558 	case V4L2_PIX_FMT_XRGB555X:
559 	case V4L2_PIX_FMT_ARGB555X:
560 	case V4L2_PIX_FMT_RGB565:
561 	case V4L2_PIX_FMT_RGB565X:
562 	case V4L2_PIX_FMT_RGB24:
563 	case V4L2_PIX_FMT_BGR24:
564 	case V4L2_PIX_FMT_RGB32:
565 	case V4L2_PIX_FMT_BGR32:
566 	case V4L2_PIX_FMT_XRGB32:
567 	case V4L2_PIX_FMT_XBGR32:
568 	case V4L2_PIX_FMT_ARGB32:
569 	case V4L2_PIX_FMT_ABGR32:
570 	case V4L2_PIX_FMT_GREY:
571 	case V4L2_PIX_FMT_Z16:
572 	case V4L2_PIX_FMT_INZI:
573 	case V4L2_PIX_FMT_Y10:
574 	case V4L2_PIX_FMT_Y12:
575 	case V4L2_PIX_FMT_Y16:
576 	case V4L2_PIX_FMT_Y16_BE:
577 	case V4L2_PIX_FMT_HSV24:
578 	case V4L2_PIX_FMT_HSV32:
579 	default:
580 		shader_RGB(m_frameFormat);
581 		break;
582 	}
583 }
584 
paintFrame()585 void CaptureWinGLEngine::paintFrame()
586 {
587 	float HCrop_f = (float)m_HCrop / m_frameHeight;
588 	float WCrop_f = (float)m_WCrop / m_frameWidth;
589 
590 	glBegin(GL_QUADS);
591 	glTexCoord2f(WCrop_f, HCrop_f);               glVertex2f(0, 0);
592 	glTexCoord2f(1.0f - WCrop_f, HCrop_f);        glVertex2f(m_frameWidth, 0);
593 	glTexCoord2f(1.0f - WCrop_f, 1.0f - HCrop_f); glVertex2f(m_frameWidth, m_frameHeight);
594 	glTexCoord2f(WCrop_f, 1.0f - HCrop_f);        glVertex2f(0, m_frameHeight);
595 	glEnd();
596 }
597 
paintSquare()598 void CaptureWinGLEngine::paintSquare()
599 {
600 	// Draw a black square on the white background to
601 	// test the alpha channel.
602 	unsigned w4 = m_frameWidth / 4;
603 	unsigned h4 = m_frameHeight / 4;
604 
605 	glClear(GL_COLOR_BUFFER_BIT);
606 	glBindTexture(GL_TEXTURE_2D, 0);
607 
608 	glBegin(GL_QUADS);
609 	glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
610 	glVertex2f(w4, h4);
611 	glVertex2f(w4, 3 * h4);
612 	glVertex2f(3 * w4, 3 * h4);
613 	glVertex2f(3 * w4, h4);
614 	glEnd();
615 }
616 
paintGL()617 void CaptureWinGLEngine::paintGL()
618 {
619 	if (m_frameWidth < 1 || m_frameHeight < 1) {
620 		return;
621 	}
622 
623 	if (m_formatChange)
624 		changeShader();
625 
626 	if (m_frameData == NULL) {
627 		paintFrame();
628 		return;
629 	}
630 
631 	if (m_blending) {
632 		paintSquare();
633 		glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
634 	}
635 
636 	switch (m_frameFormat) {
637 	case V4L2_PIX_FMT_YUYV:
638 	case V4L2_PIX_FMT_YVYU:
639 	case V4L2_PIX_FMT_UYVY:
640 	case V4L2_PIX_FMT_VYUY:
641 		render_YUY2(m_frameFormat);
642 		break;
643 
644 	case V4L2_PIX_FMT_NV16:
645 	case V4L2_PIX_FMT_NV61:
646 	case V4L2_PIX_FMT_NV16M:
647 	case V4L2_PIX_FMT_NV61M:
648 		render_NV16(m_frameFormat);
649 		break;
650 
651 	case V4L2_PIX_FMT_NV12:
652 	case V4L2_PIX_FMT_NV21:
653 	case V4L2_PIX_FMT_NV12M:
654 	case V4L2_PIX_FMT_NV21M:
655 		render_NV12(m_frameFormat);
656 		break;
657 
658 	case V4L2_PIX_FMT_NV24:
659 	case V4L2_PIX_FMT_NV42:
660 		render_NV24(m_frameFormat);
661 		break;
662 
663 	case V4L2_PIX_FMT_YUV422P:
664 	case V4L2_PIX_FMT_YUV420:
665 	case V4L2_PIX_FMT_YVU420:
666 	case V4L2_PIX_FMT_YUV420M:
667 	case V4L2_PIX_FMT_YVU420M:
668 	case V4L2_PIX_FMT_YUV422M:
669 	case V4L2_PIX_FMT_YVU422M:
670 	case V4L2_PIX_FMT_YUV444M:
671 	case V4L2_PIX_FMT_YVU444M:
672 		render_YUV(m_frameFormat);
673 		break;
674 
675 	case V4L2_PIX_FMT_YUV444:
676 	case V4L2_PIX_FMT_YUV555:
677 	case V4L2_PIX_FMT_YUV565:
678 	case V4L2_PIX_FMT_YUV32:
679 	case V4L2_PIX_FMT_AYUV32:
680 	case V4L2_PIX_FMT_XYUV32:
681 	case V4L2_PIX_FMT_VUYA32:
682 	case V4L2_PIX_FMT_VUYX32:
683 	case V4L2_PIX_FMT_YUVA32:
684 	case V4L2_PIX_FMT_YUVX32:
685 		render_YUV_packed(m_frameFormat);
686 		break;
687 
688 	case V4L2_PIX_FMT_SBGGR8:
689 	case V4L2_PIX_FMT_SGBRG8:
690 	case V4L2_PIX_FMT_SGRBG8:
691 	case V4L2_PIX_FMT_SRGGB8:
692 	case V4L2_PIX_FMT_SBGGR10:
693 	case V4L2_PIX_FMT_SGBRG10:
694 	case V4L2_PIX_FMT_SGRBG10:
695 	case V4L2_PIX_FMT_SRGGB10:
696 	case V4L2_PIX_FMT_SBGGR12:
697 	case V4L2_PIX_FMT_SGBRG12:
698 	case V4L2_PIX_FMT_SGRBG12:
699 	case V4L2_PIX_FMT_SRGGB12:
700 	case V4L2_PIX_FMT_SBGGR16:
701 	case V4L2_PIX_FMT_SGBRG16:
702 	case V4L2_PIX_FMT_SGRBG16:
703 	case V4L2_PIX_FMT_SRGGB16:
704 		render_Bayer(m_frameFormat);
705 		break;
706 
707 	case V4L2_PIX_FMT_GREY:
708 	case V4L2_PIX_FMT_Z16:
709 	case V4L2_PIX_FMT_INZI:
710 	case V4L2_PIX_FMT_Y10:
711 	case V4L2_PIX_FMT_Y12:
712 	case V4L2_PIX_FMT_Y16:
713 	case V4L2_PIX_FMT_Y16_BE:
714 	case V4L2_PIX_FMT_RGB332:
715 	case V4L2_PIX_FMT_BGR666:
716 	case V4L2_PIX_FMT_RGB555:
717 	case V4L2_PIX_FMT_XRGB555:
718 	case V4L2_PIX_FMT_ARGB555:
719 	case V4L2_PIX_FMT_RGB555X:
720 	case V4L2_PIX_FMT_XRGB555X:
721 	case V4L2_PIX_FMT_ARGB555X:
722 	case V4L2_PIX_FMT_RGB444:
723 	case V4L2_PIX_FMT_XRGB444:
724 	case V4L2_PIX_FMT_ARGB444:
725 	case V4L2_PIX_FMT_RGB565:
726 	case V4L2_PIX_FMT_RGB565X:
727 	case V4L2_PIX_FMT_RGB24:
728 	case V4L2_PIX_FMT_BGR24:
729 	case V4L2_PIX_FMT_RGB32:
730 	case V4L2_PIX_FMT_BGR32:
731 	case V4L2_PIX_FMT_XRGB32:
732 	case V4L2_PIX_FMT_XBGR32:
733 	case V4L2_PIX_FMT_ARGB32:
734 	case V4L2_PIX_FMT_ABGR32:
735 	case V4L2_PIX_FMT_HSV24:
736 	case V4L2_PIX_FMT_HSV32:
737 	default:
738 		render_RGB(m_frameFormat);
739 		break;
740 	}
741 	paintFrame();
742 
743 	if (m_blending)
744 		glBlendFunc(GL_ONE, GL_ZERO);
745 }
746 
configureTexture(size_t idx)747 void CaptureWinGLEngine::configureTexture(size_t idx)
748 {
749 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[idx]);
750 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
751 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
752 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
753 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
754 }
755 
756 // Normalize y to [0...1] and uv to [-0.5...0.5], taking into account the
757 // colorspace.
codeYUVNormalize()758 QString CaptureWinGLEngine::codeYUVNormalize()
759 {
760 	switch (m_quantization) {
761 	case V4L2_QUANTIZATION_FULL_RANGE:
762 		if (m_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&
763 		    m_ycbcr_enc != V4L2_YCBCR_ENC_XV709)
764 			return "";
765 		/*
766 		 * xv709 and xv601 always have limited range quantization. But the
767 		 * result are values outside the normal 0-1 range, which is the
768 		 * point of these extended gamut encodings.
769 		 */
770 
771 		/* fall-through */
772 	default:
773 		return QString("   y = (255.0 / 219.0) * (y - (16.0 / 255.0));"
774 			       "   u = (255.0 / 224.0) * u;"
775 			       "   v = (255.0 / 224.0) * v;"
776 			       );
777 	}
778 }
779 
780 // Normalize r, g and b to [0...1]
codeRGBNormalize()781 QString CaptureWinGLEngine::codeRGBNormalize()
782 {
783 	switch (m_quantization) {
784 	case V4L2_QUANTIZATION_FULL_RANGE:
785 		return "";
786 	default:
787 		return QString("   r = (255.0 / 219.0) * (r - (16.0 / 255.0));"
788 			       "   g = (255.0 / 219.0) * (g - (16.0 / 255.0));"
789 			       "   b = (255.0 / 219.0) * (b - (16.0 / 255.0));"
790 			       );
791 	}
792 }
793 
794 // Convert Y'CbCr (aka YUV) to R'G'B', taking into account the
795 // colorspace.
codeYUV2RGB()796 QString CaptureWinGLEngine::codeYUV2RGB()
797 {
798 	switch (m_ycbcr_enc) {
799 	case V4L2_YCBCR_ENC_SMPTE240M:
800 		// Old obsolete HDTV standard. Replaced by REC 709.
801 		// SMPTE 240M has its own luma coefficients
802 		return QString("   float r = y + 1.5756 * v;"
803 			       "   float g = y - 0.2253 * u - 0.4768 * v;"
804 			       "   float b = y + 1.8270 * u;"
805 			       );
806 	case V4L2_YCBCR_ENC_BT2020:
807 		// BT.2020 luma coefficients
808 		return QString("   float r = y + 1.4719 * v;"
809 			       "   float g = y - 0.1646 * u - 0.5703 * v;"
810 			       "   float b = y + 1.8814 * u;"
811 			       );
812 	case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
813 		// BT.2020_CONST_LUM luma coefficients
814 		return QString("   float b = u <= 0.0 ? y + 1.9404 * u : y + 1.5816 * u;"
815 			       "   float r = v <= 0.0 ? y + 1.7184 * v : y + 0.9936 * v;"
816 			       "   float lin_r = (r < 0.081) ? r / 4.5 : pow((r + 0.099) / 1.099, 1.0 / 0.45);"
817 			       "   float lin_b = (b < 0.081) ? b / 4.5 : pow((b + 0.099) / 1.099, 1.0 / 0.45);"
818 			       "   float lin_y = (y < 0.081) ? y / 4.5 : pow((y + 0.099) / 1.099, 1.0 / 0.45);"
819 			       "   float lin_g = lin_y / 0.6780 - lin_r * 0.2627 / 0.6780 - lin_b * 0.0593 / 0.6780;"
820 			       "   float g = (lin_g < 0.018) ? lin_g * 4.5 : 1.099 * pow(lin_g, 0.45) - 0.099;"
821 			       );
822 	case V4L2_YCBCR_ENC_601:
823 	case V4L2_YCBCR_ENC_XV601:
824 		// These colorspaces all use the BT.601 luma coefficients
825 		return QString("   float r = y + 1.403 * v;"
826 		       "   float g = y - 0.344 * u - 0.714 * v;"
827 		       "   float b = y + 1.773 * u;"
828 		       );
829 	default:
830 		// The HDTV colorspaces all use REC 709 luma coefficients
831 		return QString("   float r = y + 1.5701 * v;"
832 			       "   float g = y - 0.1870 * u - 0.4664 * v;"
833 			       "   float b = y + 1.8556 * u;"
834 			       );
835 	}
836 }
837 
838 // Convert non-linear R'G'B' to linear RGB, taking into account the
839 // colorspace.
codeTransformToLinear()840 QString CaptureWinGLEngine::codeTransformToLinear()
841 {
842 	switch (m_xfer_func) {
843 	case V4L2_XFER_FUNC_SMPTE240M:
844 		// Old obsolete HDTV standard. Replaced by REC 709.
845 		// This is the transfer function for SMPTE 240M
846 		return QString("   r = (r < 0.0913) ? r / 4.0 : pow((r + 0.1115) / 1.1115, 1.0 / 0.45);"
847 			       "   g = (g < 0.0913) ? g / 4.0 : pow((g + 0.1115) / 1.1115, 1.0 / 0.45);"
848 			       "   b = (b < 0.0913) ? b / 4.0 : pow((b + 0.1115) / 1.1115, 1.0 / 0.45);"
849 			       );
850 	case V4L2_XFER_FUNC_SRGB:
851 		// This is used for sRGB as specified by the IEC FDIS 61966-2-1 standard
852 		return QString("   r = (r < -0.04045) ? -pow((-r + 0.055) / 1.055, 2.4) : "
853 			       "        ((r <= 0.04045) ? r / 12.92 : pow((r + 0.055) / 1.055, 2.4));"
854 			       "   g = (g < -0.04045) ? -pow((-g + 0.055) / 1.055, 2.4) : "
855 			       "        ((g <= 0.04045) ? g / 12.92 : pow((g + 0.055) / 1.055, 2.4));"
856 			       "   b = (b < -0.04045) ? -pow((-b + 0.055) / 1.055, 2.4) : "
857 			       "        ((b <= 0.04045) ? b / 12.92 : pow((b + 0.055) / 1.055, 2.4));"
858 			       );
859 	case V4L2_XFER_FUNC_OPRGB:
860 		return QString("   r = pow(max(r, 0.0), 2.19921875);"
861 			       "   g = pow(max(g, 0.0), 2.19921875);"
862 			       "   b = pow(max(b, 0.0), 2.19921875);");
863 	case V4L2_XFER_FUNC_DCI_P3:
864 		return QString("   r = pow(max(r, 0.0), 2.6);"
865 			       "   g = pow(max(g, 0.0), 2.6);"
866 			       "   b = pow(max(b, 0.0), 2.6);");
867 	case V4L2_XFER_FUNC_SMPTE2084:
868 		return QString("   float m1 = 1.0 / ((2610.0 / 4096.0) / 4.0);"
869 			       "   float m2 = 1.0 / (128.0 * 2523.0 / 4096.0);"
870 			       "   float c1 = 3424.0 / 4096.0;"
871 			       "   float c2 = 32.0 * 2413.0 / 4096.0;"
872 			       "   float c3 = 32.0 * 2392.0 / 4096.0;"
873 			       "   r = pow(max(r, 0.0), m2);"
874 			       "   g = pow(max(g, 0.0), m2);"
875 			       "   b = pow(max(b, 0.0), m2);"
876 			       // The factor 100 is because SMPTE-2084 maps to 0-10000 cd/m^2
877 			       // whereas other transfer functions map to 0-100 cd/m^2.
878 			       "   r = pow(max(r - c1, 0.0) / (c2 - c3 * r), m1) * 100.0;"
879 			       "   g = pow(max(g - c1, 0.0) / (c2 - c3 * g), m1) * 100.0;"
880 			       "   b = pow(max(b - c1, 0.0) / (c2 - c3 * b), m1) * 100.0;");
881 	case V4L2_XFER_FUNC_NONE:
882 		return "";
883 	case V4L2_XFER_FUNC_709:
884 	default:
885 		// All others use the transfer function specified by REC 709
886 		return QString("   r = (r <= -0.081) ? -pow((r - 0.099) / -1.099, 1.0 / 0.45) : "
887 			       "        ((r < 0.081) ? r / 4.5 : pow((r + 0.099) / 1.099, 1.0 / 0.45));"
888 			       "   g = (g <= -0.081) ? -pow((g - 0.099) / -1.099, 1.0 / 0.45) : "
889 			       "        ((g < 0.081) ? g / 4.5 : pow((g + 0.099) / 1.099, 1.0 / 0.45));"
890 			       "   b = (b <= -0.081) ? -pow((b - 0.099) / -1.099, 1.0 / 0.45) : "
891 			       "        ((b < 0.081) ? b / 4.5 : pow((b + 0.099) / 1.099, 1.0 / 0.45));"
892 			       );
893 	}
894 }
895 
896 // Convert the given colorspace to the REC 709/sRGB colorspace. All colors are
897 // specified as linear RGB.
codeColorspaceConversion()898 QString CaptureWinGLEngine::codeColorspaceConversion()
899 {
900 	switch (m_colorspace) {
901 	case V4L2_COLORSPACE_SMPTE170M:
902 	case V4L2_COLORSPACE_SMPTE240M:
903 		// Current SDTV standard, although slowly being replaced by REC 709.
904 		// Uses the SMPTE 170M aka SMPTE-C aka SMPTE RP 145 conversion matrix.
905 		return QString("   float rr =  0.939536 * r + 0.050215 * g + 0.001789 * b;"
906 			       "   float gg =  0.017743 * r + 0.965758 * g + 0.016243 * b;"
907 			       "   float bb = -0.001591 * r - 0.004356 * g + 1.005951 * b;"
908 			       "   r = rr; g = gg; b = bb;"
909 			       );
910 	case V4L2_COLORSPACE_470_SYSTEM_M:
911 		// Old obsolete NTSC standard. Replaced by REC 709.
912 		// Uses the NTSC 1953 conversion matrix and the Bradford method to
913 		// compensate for the different whitepoints.
914 		return QString("   float rr =  1.4858417 * r - 0.4033361 * g - 0.0825056 * b;"
915 			       "   float gg = -0.0251179 * r + 0.9541568 * g + 0.0709611 * b;"
916 			       "   float bb = -0.0272254 * r - 0.0440815 * g + 1.0713068 * b;"
917 			       "   r = rr; g = gg; b = bb;"
918 			       );
919 	case V4L2_COLORSPACE_470_SYSTEM_BG:
920 		// Old obsolete PAL/SECAM standard. Replaced by REC 709.
921 		// Uses the EBU Tech. 3213 conversion matrix.
922 		return QString("   float rr = 1.0440 * r - 0.0440 * g;"
923 			       "   float bb = -0.0119 * g + 1.0119 * b;"
924 			       "   r = rr; b = bb;"
925 			       );
926 	case V4L2_COLORSPACE_OPRGB:
927 		return QString("   float rr =  1.3982832 * r - 0.3982831 * g;"
928 			       "   float bb = -0.0429383 * g + 1.0429383 * b;"
929 			       "   r = rr; b = bb;"
930 			       );
931 	case V4L2_COLORSPACE_DCI_P3:
932 		// Uses the Bradford method to compensate for the different whitepoints.
933 		return QString("   float rr =  1.1574000 * r - 0.1548597 * g - 0.0025403 * b;"
934 			       "   float gg = -0.0415052 * r + 1.0455684 * g - 0.0040633 * b;"
935 			       "   float bb = -0.0180562 * r - 0.0785993 * g + 1.0966555 * b;"
936 			       );
937 	case V4L2_COLORSPACE_BT2020:
938 		return QString("   float rr =  1.6603627 * r - 0.5875400 * g - 0.0728227 * b;"
939 			       "   float gg = -0.1245635 * r + 1.1329114 * g - 0.0083478 * b;"
940 			       "   float bb = -0.0181566 * r - 0.1006017 * g + 1.1187583 * b;"
941 			       "   r = rr; g = gg; b = bb;"
942 			       );
943 	case V4L2_COLORSPACE_REC709:
944 	case V4L2_COLORSPACE_SRGB:
945 	default:
946 		return "";
947 	}
948 }
949 
950 // Convert linear RGB to non-linear R'G'B', taking into account the
951 // given display colorspace.
codeTransformToNonLinear()952 QString CaptureWinGLEngine::codeTransformToNonLinear()
953 {
954 	// Use the sRGB transfer function. Do nothing if the GL_FRAMEBUFFER_SRGB
955 	// is available.
956 	if (m_haveFramebufferSRGB)
957 		return "";
958 	return QString("   r = (r < -0.0031308) ? -1.055 * pow(-r, 1.0 / 2.4) + 0.055 : "
959 		       "        ((r <= 0.0031308) ? r * 12.92 : 1.055 * pow(r, 1.0 / 2.4) - 0.055);"
960 		       "   g = (g < -0.0031308) ? -1.055 * pow(-g, 1.0 / 2.4) + 0.055 : "
961 		       "        ((g <= 0.0031308) ? g * 12.92 : 1.055 * pow(g, 1.0 / 2.4) - 0.055);"
962 		       "   b = (b < -0.0031308) ? -1.055 * pow(-b, 1.0 / 2.4) + 0.055 : "
963 		       "        ((b <= 0.0031308) ? b * 12.92 : 1.055 * pow(b, 1.0 / 2.4) - 0.055);"
964 		       );
965 }
966 
967 static const QString codeSuffix("   gl_FragColor = vec4(r, g, b, 0.0);"
968 			  "}");
969 
970 static const QString codeSuffixWithAlpha("   gl_FragColor = vec4(r, g, b, a);"
971 			  "}");
972 
shader_YUV(__u32 format)973 void CaptureWinGLEngine::shader_YUV(__u32 format)
974 {
975 	unsigned vdiv = 2, hdiv = 2;
976 
977 	switch (format) {
978 	case V4L2_PIX_FMT_YUV422P:
979 	case V4L2_PIX_FMT_YUV422M:
980 	case V4L2_PIX_FMT_YVU422M:
981 		vdiv = 1;
982 		break;
983 	case V4L2_PIX_FMT_YUV444M:
984 	case V4L2_PIX_FMT_YVU444M:
985 		vdiv = hdiv = 1;
986 		break;
987 	}
988 
989 	m_screenTextureCount = 3;
990 	glGenTextures(m_screenTextureCount, m_screenTexture);
991 
992 	glActiveTexture(GL_TEXTURE0);
993 	configureTexture(0);
994 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
995 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
996 	checkError("YUV shader texture 0");
997 
998 	glActiveTexture(GL_TEXTURE1);
999 	configureTexture(1);
1000 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth / hdiv, m_frameHeight / vdiv, 0,
1001 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1002 	checkError("YUV shader texture 1");
1003 
1004 	glActiveTexture(GL_TEXTURE2);
1005 	configureTexture(2);
1006 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth / hdiv, m_frameHeight / vdiv, 0,
1007 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1008 	checkError("YUV shader texture 2");
1009 
1010 	QString codeHead = QString("uniform sampler2D ytex;"
1011 				   "uniform sampler2D utex;"
1012 				   "uniform sampler2D vtex;"
1013 				   "uniform float tex_h;"
1014 				   "void main()"
1015 				   "{"
1016 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
1017 				   "   float ycoord = floor(xy.y * tex_h);");
1018 
1019 	if (m_field == V4L2_FIELD_SEQ_TB)
1020 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1021 	else if (m_field == V4L2_FIELD_SEQ_BT)
1022 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1023 
1024 	codeHead += "   float y = texture2D(ytex, xy).r;"
1025 		    "   float u = texture2D(utex, xy).r - 0.5;"
1026 		    "   float v = texture2D(vtex, xy).r - 0.5;";
1027 
1028 	QString codeTail = codeYUVNormalize() +
1029 			   codeYUV2RGB() +
1030 			   codeTransformToLinear() +
1031 			   codeColorspaceConversion() +
1032 			   codeTransformToNonLinear() +
1033 			   codeSuffix;
1034 
1035 	bool src_c = m_shaderProgram.addShaderFromSourceCode(
1036 #if QT_VERSION < 0x060000
1037 				QGLShader::Fragment,
1038 #else
1039 				QOpenGLShader::Fragment,
1040 #endif
1041 				codeHead + codeTail);
1042 
1043 	if (!src_c)
1044 		fprintf(stderr, "OpenGL Error: YUV shader compilation failed.\n");
1045 
1046 	m_shaderProgram.bind();
1047 }
1048 
render_YUV(__u32 format)1049 void CaptureWinGLEngine::render_YUV(__u32 format)
1050 {
1051 	unsigned vdiv = 2, hdiv = 2;
1052 	int idxU = 0;
1053 	int idxV = 0;
1054 
1055 	switch (format) {
1056 	case V4L2_PIX_FMT_YUV444M:
1057 	case V4L2_PIX_FMT_YVU444M:
1058 		vdiv = hdiv = 1;
1059 		break;
1060 	case V4L2_PIX_FMT_YUV422P:
1061 		idxU = m_frameWidth * m_frameHeight;
1062 		idxV = idxU + (idxU / 2);
1063 		vdiv = 1;
1064 		break;
1065 	case V4L2_PIX_FMT_YUV422M:
1066 	case V4L2_PIX_FMT_YVU422M:
1067 		vdiv = 1;
1068 		break;
1069 	case V4L2_PIX_FMT_YUV420:
1070 		idxU = m_frameWidth * m_frameHeight;
1071 		idxV = idxU + (idxU / 4);
1072 		break;
1073 	case V4L2_PIX_FMT_YVU420:
1074 		idxV = m_frameWidth * m_frameHeight;
1075 		idxU = idxV + (idxV / 4);
1076 		break;
1077 	}
1078 
1079 	int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1080 	glUniform1f(idx, m_frameHeight);
1081 
1082 	glActiveTexture(GL_TEXTURE0);
1083 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1084 #if QT_VERSION < 0x060000
1085 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1086 #else
1087 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1088 #endif
1089 	glUniform1i(Y, 0);
1090 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1091 			m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1092 	checkError("YUV paint ytex");
1093 
1094 	glActiveTexture(GL_TEXTURE1);
1095 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1096 #if QT_VERSION < 0x060000
1097 	GLint U = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "utex");
1098 #else
1099 	GLint U = glGetUniformLocation(m_shaderProgram.programId(), "utex");
1100 #endif
1101 	glUniform1i(U, 1);
1102 	switch (format) {
1103 	case V4L2_PIX_FMT_YUV422P:
1104 	case V4L2_PIX_FMT_YUV420:
1105 	case V4L2_PIX_FMT_YVU420:
1106 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1107 			m_glRed, GL_UNSIGNED_BYTE, m_frameData == NULL ? NULL : &m_frameData[idxU]);
1108 		break;
1109 	case V4L2_PIX_FMT_YUV420M:
1110 	case V4L2_PIX_FMT_YUV422M:
1111 	case V4L2_PIX_FMT_YUV444M:
1112 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1113 			m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1114 		break;
1115 	case V4L2_PIX_FMT_YVU420M:
1116 	case V4L2_PIX_FMT_YVU422M:
1117 	case V4L2_PIX_FMT_YVU444M:
1118 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1119 			m_glRed, GL_UNSIGNED_BYTE, m_frameData3);
1120 		break;
1121 	}
1122 	checkError("YUV paint utex");
1123 
1124 	glActiveTexture(GL_TEXTURE2);
1125 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[2]);
1126 #if QT_VERSION < 0x060000
1127 	GLint V = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "vtex");
1128 #else
1129 	GLint V = glGetUniformLocation(m_shaderProgram.programId(), "vtex");
1130 #endif
1131 	glUniform1i(V, 2);
1132 	switch (format) {
1133 	case V4L2_PIX_FMT_YUV422P:
1134 	case V4L2_PIX_FMT_YUV420:
1135 	case V4L2_PIX_FMT_YVU420:
1136 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1137 			m_glRed, GL_UNSIGNED_BYTE, m_frameData == NULL ? NULL : &m_frameData[idxV]);
1138 		break;
1139 	case V4L2_PIX_FMT_YUV420M:
1140 	case V4L2_PIX_FMT_YUV422M:
1141 	case V4L2_PIX_FMT_YUV444M:
1142 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1143 			m_glRed, GL_UNSIGNED_BYTE, m_frameData3);
1144 		break;
1145 	case V4L2_PIX_FMT_YVU420M:
1146 	case V4L2_PIX_FMT_YVU422M:
1147 	case V4L2_PIX_FMT_YVU444M:
1148 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1149 			m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1150 		break;
1151 	}
1152 	checkError("YUV paint vtex");
1153 }
1154 
shader_NV12_invariant(__u32 format)1155 QString CaptureWinGLEngine::shader_NV12_invariant(__u32 format)
1156 {
1157 	switch (format) {
1158 	case V4L2_PIX_FMT_NV12:
1159 	case V4L2_PIX_FMT_NV12M:
1160 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1161 			       "   u = texture2D(uvtex, xy).r - 0.5;"
1162 			       "   v = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1163 			       "} else {"
1164 			       "   u = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1165 			       "   v = texture2D(uvtex, xy).r - 0.5;"
1166 			       "}"
1167 			       );
1168 
1169 	case V4L2_PIX_FMT_NV21:
1170 	case V4L2_PIX_FMT_NV21M:
1171 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1172 			       "   u = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1173 			       "   v = texture2D(uvtex, xy).r - 0.5;"
1174 			       "} else {"
1175 			       "   u = texture2D(uvtex, xy).r - 0.5;"
1176 			       "   v = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1177 			       "}"
1178 			       );
1179 
1180 	default:
1181 		return QString();
1182 	}
1183 }
1184 
1185 
shader_NV12(__u32 format)1186 void CaptureWinGLEngine::shader_NV12(__u32 format)
1187 {
1188 	m_screenTextureCount = 2;
1189 	glGenTextures(m_screenTextureCount, m_screenTexture);
1190 
1191 	glActiveTexture(GL_TEXTURE0);
1192 	configureTexture(0);
1193 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1194 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1195 	checkError("NV12 shader texture 0");
1196 
1197 	glActiveTexture(GL_TEXTURE1);
1198 	configureTexture(1);
1199 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight / 2, 0,
1200 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1201 	checkError("NV12 shader texture 1");
1202 
1203 	QString codeHead = QString("uniform sampler2D ytex;"
1204 				   "uniform sampler2D uvtex;"
1205 				   "uniform float texl_w;"
1206 				   "uniform float tex_w;"
1207 				   "uniform float tex_h;"
1208 				   "void main()"
1209 				   "{"
1210 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
1211 				   "   float ycoord = floor(xy.y * tex_h);");
1212 
1213 	if (m_field == V4L2_FIELD_SEQ_TB)
1214 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1215 	else if (m_field == V4L2_FIELD_SEQ_BT)
1216 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1217 
1218 	codeHead += "   float u, v;"
1219 		    "   float xcoord = floor(xy.x * tex_w);"
1220 		    "   float y = texture2D(ytex, xy).r;";
1221 
1222 	QString codeBody = shader_NV12_invariant(format);
1223 
1224 	QString codeTail = codeYUVNormalize() +
1225 			   codeYUV2RGB() +
1226 			   codeTransformToLinear() +
1227 			   codeColorspaceConversion() +
1228 			   codeTransformToNonLinear() +
1229 			   codeSuffix;
1230 
1231 	bool src_c = m_shaderProgram.addShaderFromSourceCode(
1232 #if QT_VERSION < 0x060000
1233 				QGLShader::Fragment,
1234 #else
1235 				QOpenGLShader::Fragment,
1236 #endif
1237 				QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1238 
1239 	if (!src_c)
1240 		fprintf(stderr, "OpenGL Error: YUV shader compilation failed.\n");
1241 
1242 	m_shaderProgram.bind();
1243 }
1244 
render_NV12(__u32 format)1245 void CaptureWinGLEngine::render_NV12(__u32 format)
1246 {
1247 	int idx;
1248 
1249 	idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texel width
1250 	glUniform1f(idx, 1.0 / m_frameWidth);
1251 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1252 	glUniform1f(idx, m_frameWidth);
1253 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1254 	glUniform1f(idx, m_frameHeight);
1255 
1256 	glActiveTexture(GL_TEXTURE0);
1257 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1258 #if QT_VERSION < 0x060000
1259 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1260 #else
1261 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1262 #endif
1263 	glUniform1i(Y, 0);
1264 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1265 			m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1266 	checkError("NV12 paint ytex");
1267 
1268 	glActiveTexture(GL_TEXTURE1);
1269 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1270 #if QT_VERSION < 0x060000
1271 	GLint U = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1272 #else
1273 	GLint U = glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1274 #endif
1275 	glUniform1i(U, 1);
1276 	switch (format) {
1277 	case V4L2_PIX_FMT_NV12:
1278 	case V4L2_PIX_FMT_NV21:
1279 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight / 2,
1280 				m_glRed, GL_UNSIGNED_BYTE,
1281 				m_frameData ? m_frameData + m_frameWidth * m_frameHeight : NULL);
1282 		break;
1283 	case V4L2_PIX_FMT_NV12M:
1284 	case V4L2_PIX_FMT_NV21M:
1285 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight / 2,
1286 				m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1287 		break;
1288 	}
1289 	checkError("NV12 paint uvtex");
1290 }
1291 
shader_NV24_invariant(__u32 format)1292 QString CaptureWinGLEngine::shader_NV24_invariant(__u32 format)
1293 {
1294 	switch (format) {
1295 	case V4L2_PIX_FMT_NV24:
1296 		if (m_hasGLRed)
1297 			return QString("   u = texture2D(uvtex, xy).r - 0.5;"
1298 				       "   v = texture2D(uvtex, xy).g - 0.5;"
1299 				       );
1300 		return QString("   u = texture2D(uvtex, xy).r - 0.5;"
1301 			       "   v = texture2D(uvtex, xy).a - 0.5;"
1302 			       );
1303 
1304 	case V4L2_PIX_FMT_NV42:
1305 		if (m_hasGLRed)
1306 			return QString("   v = texture2D(uvtex, xy).r - 0.5;"
1307 				       "   u = texture2D(uvtex, xy).g - 0.5;"
1308 				       );
1309 		return QString("   v = texture2D(uvtex, xy).r - 0.5;"
1310 			       "   u = texture2D(uvtex, xy).a - 0.5;"
1311 			       );
1312 
1313 	default:
1314 		return QString();
1315 	}
1316 }
1317 
shader_NV24(__u32 format)1318 void CaptureWinGLEngine::shader_NV24(__u32 format)
1319 {
1320 	m_screenTextureCount = 2;
1321 	glGenTextures(m_screenTextureCount, m_screenTexture);
1322 
1323 	glActiveTexture(GL_TEXTURE0);
1324 	configureTexture(0);
1325 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1326 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1327 	checkError("NV24 shader texture 0");
1328 
1329 	glActiveTexture(GL_TEXTURE1);
1330 	configureTexture(1);
1331 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRedGreen, m_frameWidth, m_frameHeight, 0,
1332 		     m_glRedGreen, GL_UNSIGNED_BYTE, NULL);
1333 	checkError("NV24 shader texture 1");
1334 
1335 	QString codeHead = QString("uniform sampler2D ytex;"
1336 				   "uniform sampler2D uvtex;"
1337 				   "uniform float tex_w;"
1338 				   "uniform float tex_h;"
1339 				   "void main()"
1340 				   "{"
1341 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
1342 				   "   float ycoord = floor(xy.y * tex_h);");
1343 
1344 	if (m_field == V4L2_FIELD_SEQ_TB)
1345 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1346 	else if (m_field == V4L2_FIELD_SEQ_BT)
1347 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1348 
1349 	codeHead += "   float u, v;"
1350 		    "   float y = texture2D(ytex, xy).r;";
1351 
1352 	QString codeBody = shader_NV24_invariant(format);
1353 
1354 	QString codeTail = codeYUVNormalize() +
1355 			   codeYUV2RGB() +
1356 			   codeTransformToLinear() +
1357 			   codeColorspaceConversion() +
1358 			   codeTransformToNonLinear() +
1359 			   codeSuffix;
1360 
1361 	bool src_c = m_shaderProgram.addShaderFromSourceCode(
1362 #if QT_VERSION < 0x060000
1363 				QGLShader::Fragment,
1364 #else
1365 				QOpenGLShader::Fragment,
1366 #endif
1367 				QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1368 
1369 	if (!src_c)
1370 		fprintf(stderr, "OpenGL Error: YUV shader compilation failed.\n");
1371 
1372 	m_shaderProgram.bind();
1373 }
1374 
render_NV24(__u32 format)1375 void CaptureWinGLEngine::render_NV24(__u32 format)
1376 {
1377 	int idx;
1378 
1379 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1380 	glUniform1f(idx, m_frameWidth);
1381 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1382 	glUniform1f(idx, m_frameHeight);
1383 
1384 	glActiveTexture(GL_TEXTURE0);
1385 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1386 #if QT_VERSION < 0x060000
1387 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1388 #else
1389 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1390 #endif
1391 	glUniform1i(Y, 0);
1392 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1393 			m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1394 	checkError("NV24 paint ytex");
1395 
1396 	glActiveTexture(GL_TEXTURE1);
1397 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1398 #if QT_VERSION < 0x060000
1399 	GLint U = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1400 #else
1401 	GLint U = glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1402 #endif
1403 	glUniform1i(U, 1);
1404 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1405 			m_glRedGreen, GL_UNSIGNED_BYTE,
1406 			m_frameData ? m_frameData + m_frameWidth * m_frameHeight : NULL);
1407 	checkError("NV24 paint uvtex");
1408 }
1409 
shader_NV16_invariant(__u32 format)1410 QString CaptureWinGLEngine::shader_NV16_invariant(__u32 format)
1411 {
1412 	switch (format) {
1413 	case V4L2_PIX_FMT_NV16:
1414 	case V4L2_PIX_FMT_NV16M:
1415 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1416 			       "   u = texture2D(uvtex, xy).r - 0.5;"
1417 			       "   v = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1418 			       "} else {"
1419 			       "   u = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1420 			       "   v = texture2D(uvtex, xy).r - 0.5;"
1421 			       "}"
1422 			       );
1423 
1424 	case V4L2_PIX_FMT_NV61:
1425 	case V4L2_PIX_FMT_NV61M:
1426 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1427 			       "   u = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1428 			       "   v = texture2D(uvtex, xy).r - 0.5;"
1429 			       "} else {"
1430 			       "   u = texture2D(uvtex, xy).r - 0.5;"
1431 			       "   v = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1432 			       "}"
1433 			       );
1434 
1435 	default:
1436 		return QString();
1437 	}
1438 }
1439 
shader_NV16(__u32 format)1440 void CaptureWinGLEngine::shader_NV16(__u32 format)
1441 {
1442 	m_screenTextureCount = 2;
1443 	glGenTextures(m_screenTextureCount, m_screenTexture);
1444 
1445 	glActiveTexture(GL_TEXTURE0);
1446 	configureTexture(0);
1447 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1448 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1449 	checkError("NV16 shader texture 0");
1450 
1451 	glActiveTexture(GL_TEXTURE1);
1452 	configureTexture(1);
1453 	glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1454 		     m_glRed, GL_UNSIGNED_BYTE, NULL);
1455 	checkError("NV16 shader texture 1");
1456 
1457 	QString codeHead = QString("uniform sampler2D ytex;"
1458 				   "uniform sampler2D uvtex;"
1459 				   "uniform float texl_w;"
1460 				   "uniform float tex_w;"
1461 				   "uniform float tex_h;"
1462 				   "void main()"
1463 				   "{"
1464 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
1465 				   "   float ycoord = floor(xy.y * tex_h);");
1466 
1467 	if (m_field == V4L2_FIELD_SEQ_TB)
1468 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1469 	else if (m_field == V4L2_FIELD_SEQ_BT)
1470 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1471 
1472 	codeHead += "   float u, v;"
1473 		    "   float xcoord = floor(xy.x * tex_w);"
1474 		    "   float y = texture2D(ytex, xy).r;";
1475 
1476 	QString codeBody = shader_NV16_invariant(format);
1477 
1478 	QString codeTail = codeYUVNormalize() +
1479 			   codeYUV2RGB() +
1480 			   codeTransformToLinear() +
1481 			   codeColorspaceConversion() +
1482 			   codeTransformToNonLinear() +
1483 			   codeSuffix;
1484 
1485 	bool src_ok = m_shaderProgram.addShaderFromSourceCode(
1486 #if QT_VERSION < 0x060000
1487 				QGLShader::Fragment,
1488 #else
1489 				QOpenGLShader::Fragment,
1490 #endif
1491 				QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1492 
1493 	if (!src_ok)
1494 		fprintf(stderr, "OpenGL Error: NV16 shader compilation failed.\n");
1495 
1496 	m_shaderProgram.bind();
1497 }
1498 
render_NV16(__u32 format)1499 void CaptureWinGLEngine::render_NV16(__u32 format)
1500 {
1501 	int idx;
1502 	idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texel width
1503 	glUniform1f(idx, 1.0 / m_frameWidth);
1504 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1505 	glUniform1f(idx, m_frameWidth);
1506 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1507 	glUniform1f(idx, m_frameHeight);
1508 
1509 	glActiveTexture(GL_TEXTURE0);
1510 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1511 #if QT_VERSION < 0x060000
1512 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1513 #else
1514 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1515 #endif
1516 	glUniform1i(Y, 0);
1517 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1518 			m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1519 	checkError("NV16 paint ytex");
1520 
1521 	glActiveTexture(GL_TEXTURE1);
1522 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1523 #if QT_VERSION < 0x060000
1524 	GLint UV = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1525 #else
1526 	GLint UV = glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1527 #endif
1528 	glUniform1i(UV, 1);
1529 	switch (format) {
1530 	case V4L2_PIX_FMT_NV16:
1531 	case V4L2_PIX_FMT_NV61:
1532 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1533 				m_glRed, GL_UNSIGNED_BYTE,
1534 				m_frameData ? m_frameData + m_frameWidth * m_frameHeight : NULL);
1535 		break;
1536 	case V4L2_PIX_FMT_NV16M:
1537 	case V4L2_PIX_FMT_NV61M:
1538 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1539 				m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1540 		break;
1541 	}
1542 	checkError("NV16 paint");
1543 }
1544 
shader_YUY2_invariant(__u32 format)1545 QString CaptureWinGLEngine::shader_YUY2_invariant(__u32 format)
1546 {
1547 	switch (format) {
1548 	case V4L2_PIX_FMT_YUYV:
1549 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1550 			       "   luma_chroma = texture2D(tex, xy);"
1551 			       "   y = luma_chroma.r;"
1552 			       "} else {"
1553 			       "   luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1554 			       "   y = luma_chroma.b;"
1555 			       "}"
1556 			       "u = luma_chroma.g - 0.5;"
1557 			       "v = luma_chroma.a - 0.5;"
1558 			       );
1559 
1560 	case V4L2_PIX_FMT_YVYU:
1561 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1562 			       "   luma_chroma = texture2D(tex, xy);"
1563 			       "   y = luma_chroma.r;"
1564 			       "} else {"
1565 			       "   luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1566 			       "   y = luma_chroma.b;"
1567 			       "}"
1568 			       "u = luma_chroma.a - 0.5;"
1569 			       "v = luma_chroma.g - 0.5;"
1570 			       );
1571 
1572 	case V4L2_PIX_FMT_UYVY:
1573 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1574 			       "   luma_chroma = texture2D(tex, xy);"
1575 			       "   y = luma_chroma.g;"
1576 			       "} else {"
1577 			       "   luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1578 			       "   y = luma_chroma.a;"
1579 			       "}"
1580 			       "u = luma_chroma.r - 0.5;"
1581 			       "v = luma_chroma.b - 0.5;"
1582 			       );
1583 
1584 	case V4L2_PIX_FMT_VYUY:
1585 		return QString("if (mod(xcoord, 2.0) == 0.0) {"
1586 			       "   luma_chroma = texture2D(tex, xy);"
1587 			       "   y = luma_chroma.g;"
1588 			       "} else {"
1589 			       "   luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1590 			       "   y = luma_chroma.a;"
1591 			       "}"
1592 			       "u = luma_chroma.b - 0.5;"
1593 			       "v = luma_chroma.r - 0.5;"
1594 			       );
1595 
1596 	default:
1597 		return QString();
1598 	}
1599 }
1600 
shader_YUY2(__u32 format)1601 void CaptureWinGLEngine::shader_YUY2(__u32 format)
1602 {
1603 	m_screenTextureCount = 1;
1604 	glGenTextures(m_screenTextureCount, m_screenTexture);
1605 	configureTexture(0);
1606 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_frameWidth / 2, m_frameHeight, 0,
1607 		     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1608 
1609 	checkError("YUY2 shader");
1610 
1611 	QString codeHead = QString("uniform sampler2D tex;"
1612 				   "uniform float texl_w;"
1613 				   "uniform float tex_w;"
1614 				   "uniform float tex_h;"
1615 				   "void main()"
1616 				   "{"
1617 				   "   float y, u, v;"
1618 				   "   vec4 luma_chroma;"
1619 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
1620 				   "   float xcoord = floor(xy.x * tex_w);"
1621 				   "   float ycoord = floor(xy.y * tex_h);");
1622 
1623 	if (m_field == V4L2_FIELD_SEQ_TB)
1624 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1625 	else if (m_field == V4L2_FIELD_SEQ_BT)
1626 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1627 
1628 	QString codeBody = shader_YUY2_invariant(format);
1629 
1630 	QString codeTail = codeYUVNormalize() +
1631 			   codeYUV2RGB() +
1632 			   codeTransformToLinear() +
1633 			   codeColorspaceConversion() +
1634 			   codeTransformToNonLinear() +
1635 			   codeSuffix;
1636 
1637 	bool src_ok = m_shaderProgram.addShaderFromSourceCode(
1638 #if QT_VERSION < 0x060000
1639 				QGLShader::Fragment,
1640 #else
1641 				QOpenGLShader::Fragment,
1642 #endif
1643 				QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1644 
1645 	if (!src_ok)
1646 		fprintf(stderr, "OpenGL Error: YUY2 shader compilation failed.\n");
1647 
1648 	m_shaderProgram.bind();
1649 }
1650 
render_YUY2(__u32 format)1651 void CaptureWinGLEngine::render_YUY2(__u32 format)
1652 {
1653 	int idx;
1654 	idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texel width
1655 	glUniform1f(idx, 1.0 / m_frameWidth);
1656 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1657 	glUniform1f(idx, m_frameWidth);
1658 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1659 	glUniform1f(idx, m_frameHeight);
1660 
1661 	glActiveTexture(GL_TEXTURE0);
1662 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1663 #if QT_VERSION < 0x060000
1664 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
1665 #else
1666 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
1667 #endif
1668 	glUniform1i(Y, 0);
1669 	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / 2, m_frameHeight,
1670 			GL_RGBA, GL_UNSIGNED_BYTE, m_frameData);
1671 	checkError("YUY2 paint");
1672 }
1673 
shader_RGB(__u32 format)1674 void CaptureWinGLEngine::shader_RGB(__u32 format)
1675 {
1676 	bool manualTransform;
1677 	bool hasAlpha = false;
1678 
1679 	m_screenTextureCount = 1;
1680 	glGenTextures(m_screenTextureCount, m_screenTexture);
1681 	glActiveTexture(GL_TEXTURE0);
1682 	configureTexture(0);
1683 
1684 	manualTransform = m_quantization == V4L2_QUANTIZATION_LIM_RANGE ||
1685                           m_xfer_func != V4L2_XFER_FUNC_SRGB ||
1686 			  format == V4L2_PIX_FMT_BGR666 ||
1687 			  format == V4L2_PIX_FMT_GREY ||
1688 			  format == V4L2_PIX_FMT_Z16 ||
1689 			  format == V4L2_PIX_FMT_INZI ||
1690 			  format == V4L2_PIX_FMT_Y10 ||
1691 			  format == V4L2_PIX_FMT_Y12 ||
1692 			  format == V4L2_PIX_FMT_Y16 ||
1693 			  format == V4L2_PIX_FMT_Y16_BE ||
1694 			  format == V4L2_PIX_FMT_HSV24 ||
1695 			  format == V4L2_PIX_FMT_HSV32;
1696 	GLint internalFmt = manualTransform ? GL_RGBA8 : GL_SRGB8_ALPHA8;
1697 
1698 	switch (format) {
1699 	case V4L2_PIX_FMT_ARGB555:
1700 		hasAlpha = true;
1701 		/* fall-through */
1702 	case V4L2_PIX_FMT_RGB555:
1703 	case V4L2_PIX_FMT_XRGB555:
1704 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1705 			     GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
1706 		break;
1707 
1708 	case V4L2_PIX_FMT_ARGB444:
1709 		hasAlpha = true;
1710 		/* fall-through */
1711 	case V4L2_PIX_FMT_RGB444:
1712 	case V4L2_PIX_FMT_XRGB444:
1713 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1714 			     GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, NULL);
1715 		break;
1716 
1717 	case V4L2_PIX_FMT_ARGB555X:
1718 		hasAlpha = true;
1719 		/* fall-through */
1720 	case V4L2_PIX_FMT_RGB555X:
1721 	case V4L2_PIX_FMT_XRGB555X:
1722 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1723 			     GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
1724 		break;
1725 
1726 	case V4L2_PIX_FMT_BGR666:
1727 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1728 				GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
1729 		break;
1730 
1731 	case V4L2_PIX_FMT_RGB332:
1732 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1733 			     GL_RGB, GL_UNSIGNED_BYTE_3_3_2, NULL);
1734 		break;
1735 
1736 	case V4L2_PIX_FMT_RGB565:
1737 	case V4L2_PIX_FMT_RGB565X:
1738 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1739 			     GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
1740 		break;
1741 	case V4L2_PIX_FMT_ARGB32:
1742 		hasAlpha = true;
1743 		/* fall-through */
1744 	case V4L2_PIX_FMT_RGB32:
1745 	case V4L2_PIX_FMT_XRGB32:
1746 	case V4L2_PIX_FMT_HSV32:
1747 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1748 				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
1749 		break;
1750 	case V4L2_PIX_FMT_ABGR32:
1751 		hasAlpha = true;
1752 		/* fall-through */
1753 	case V4L2_PIX_FMT_BGR32:
1754 	case V4L2_PIX_FMT_XBGR32:
1755 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1756 				GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
1757 		break;
1758 	case V4L2_PIX_FMT_GREY:
1759 		glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1760 			     m_glRed, GL_UNSIGNED_BYTE, NULL);
1761 		break;
1762 	case V4L2_PIX_FMT_Z16:
1763 	case V4L2_PIX_FMT_INZI:
1764 	case V4L2_PIX_FMT_Y10:
1765 	case V4L2_PIX_FMT_Y12:
1766 	case V4L2_PIX_FMT_Y16:
1767 	case V4L2_PIX_FMT_Y16_BE:
1768 		glTexImage2D(GL_TEXTURE_2D, 0, m_glRed16, m_frameWidth, m_frameHeight, 0,
1769 			     m_glRed, GL_UNSIGNED_SHORT, NULL);
1770 		break;
1771 	case V4L2_PIX_FMT_RGB24:
1772 	case V4L2_PIX_FMT_BGR24:
1773 	case V4L2_PIX_FMT_HSV24:
1774 	default:
1775 		glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1776 				GL_RGB, GL_UNSIGNED_BYTE, NULL);
1777 		break;
1778 	}
1779 
1780 	checkError("RGB shader");
1781 
1782 	QString codeHead = QString("uniform sampler2D tex;"
1783 				   "uniform float tex_h;"
1784 				   "void main()"
1785 				   "{"
1786 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
1787 				   "   float ycoord = floor(xy.y * tex_h);");
1788 
1789 	if (m_field == V4L2_FIELD_SEQ_TB)
1790 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1791 	else if (m_field == V4L2_FIELD_SEQ_BT)
1792 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1793 
1794 	codeHead +=		   "   vec4 color = texture2D(tex, xy);"
1795 				   "   float a = color.a;";
1796 
1797 	switch (format) {
1798 	case V4L2_PIX_FMT_BGR666:
1799 		codeHead += "   float ub = floor(color.b * 255.0);"
1800 			    "   float ug = floor(color.g * 255.0);"
1801 			    "   float ur = floor(color.r * 255.0);"
1802 			    "   ur = floor(ur / 64.0) + mod(ug, 16.0) * 4.0;"
1803 			    "   ug = floor(ug / 16.0) + mod(ub, 4.0) * 16.0;"
1804 			    "   ub = floor(ub / 4.0);"
1805 			    "   float b = ub / 63.0;"
1806 			    "   float g = ug / 63.0;"
1807 			    "   float r = ur / 63.0;";
1808 		break;
1809 	case V4L2_PIX_FMT_BGR24:
1810 		codeHead += "   float r = color.b;"
1811 			    "   float g = color.g;"
1812 			    "   float b = color.r;";
1813 		break;
1814 	case V4L2_PIX_FMT_Y10:
1815 		codeHead += "   float r = color.r * (65535.0 / 1023.0);"
1816 			    "   float g = r;"
1817 			    "   float b = r;";
1818 		break;
1819 	case V4L2_PIX_FMT_Y12:
1820 		codeHead += "   float r = color.r * (65535.0 / 4095.0);"
1821 			    "   float g = r;"
1822 			    "   float b = r;";
1823 		break;
1824 	case V4L2_PIX_FMT_INZI:
1825 		codeHead += "   float r = color.r * (ycoord < floor(tex_h / 2.0) ? 65535.0 / 1023.0 : 1.0);"
1826 			    "   float g = r;"
1827 			    "   float b = r;";
1828 		break;
1829 	case V4L2_PIX_FMT_GREY:
1830 	case V4L2_PIX_FMT_Z16:
1831 	case V4L2_PIX_FMT_Y16:
1832 	case V4L2_PIX_FMT_Y16_BE:
1833 		codeHead += "   float r = color.r;"
1834 			    "   float g = r;"
1835 			    "   float b = r;";
1836 		break;
1837 	case V4L2_PIX_FMT_HSV24:
1838 	case V4L2_PIX_FMT_HSV32:
1839 		/* From http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl */
1840 		if (m_ycbcr_enc == V4L2_HSV_ENC_256)
1841 			codeHead += "   float hue = color.r;";
1842 		else
1843 			codeHead += "   float hue = (color.r * 256.0) / 180.0;";
1844 
1845 		codeHead += "   vec3 c = vec3(hue, color.g, color.b);"
1846 			    "   vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
1847 			    "   vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
1848 			    "   vec3 ret = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
1849 			    "   float r = ret.x;"
1850 			    "   float g = ret.y;"
1851 			    "   float b = ret.z;";
1852 		break;
1853 	default:
1854 		codeHead += "   float r = color.r;"
1855 			    "   float g = color.g;"
1856 			    "   float b = color.b;";
1857 		break;
1858 	}
1859 
1860 	QString codeTail;
1861 
1862 	if (m_quantization == V4L2_QUANTIZATION_LIM_RANGE)
1863 		codeTail += codeRGBNormalize();
1864 	if (manualTransform)
1865 		codeTail += codeTransformToLinear();
1866 
1867 	codeTail += codeColorspaceConversion() +
1868 		    codeTransformToNonLinear() +
1869 		    (hasAlpha ? codeSuffixWithAlpha : codeSuffix);
1870 
1871 	bool src_ok = m_shaderProgram.addShaderFromSourceCode(
1872 #if QT_VERSION < 0x060000
1873 				QGLShader::Fragment,
1874 #else
1875 				QOpenGLShader::Fragment,
1876 #endif
1877 				QString("%1%2").arg(codeHead, codeTail));
1878 
1879 	if (!src_ok)
1880 		fprintf(stderr, "OpenGL Error: RGB shader compilation failed.\n");
1881 
1882 	m_shaderProgram.bind();
1883 }
1884 
render_RGB(__u32 format)1885 void CaptureWinGLEngine::render_RGB(__u32 format)
1886 {
1887 	glActiveTexture(GL_TEXTURE0);
1888 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1889 #if QT_VERSION < 0x060000
1890 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
1891 #else
1892 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
1893 #endif
1894 	glUniform1i(Y, 0);
1895 	int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1896 	glUniform1f(idx, m_frameHeight);
1897 
1898 	switch (format) {
1899 	case V4L2_PIX_FMT_RGB332:
1900 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1901 				GL_RGB, GL_UNSIGNED_BYTE_3_3_2, m_frameData);
1902 		break;
1903 	case V4L2_PIX_FMT_RGB555:
1904 	case V4L2_PIX_FMT_XRGB555:
1905 	case V4L2_PIX_FMT_ARGB555:
1906 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1907 				GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_frameData);
1908 		break;
1909 
1910 	case V4L2_PIX_FMT_RGB444:
1911 	case V4L2_PIX_FMT_XRGB444:
1912 	case V4L2_PIX_FMT_ARGB444:
1913 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1914 				GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, m_frameData);
1915 		break;
1916 
1917 	case V4L2_PIX_FMT_GREY:
1918 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1919 				m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1920 		break;
1921 
1922 	case V4L2_PIX_FMT_Y10:
1923 	case V4L2_PIX_FMT_Y12:
1924 	case V4L2_PIX_FMT_Y16:
1925 	case V4L2_PIX_FMT_Z16:
1926 	case V4L2_PIX_FMT_INZI:
1927 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1928 				m_glRed, GL_UNSIGNED_SHORT, m_frameData);
1929 		break;
1930 	case V4L2_PIX_FMT_Y16_BE:
1931 		glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
1932 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1933 				m_glRed, GL_UNSIGNED_SHORT, m_frameData);
1934 		glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1935 		break;
1936 
1937 	case V4L2_PIX_FMT_RGB555X:
1938 	case V4L2_PIX_FMT_XRGB555X:
1939 	case V4L2_PIX_FMT_ARGB555X:
1940 		// Note: most likely for big-endian systems SWAP_BYTES should be true
1941 		// for the RGB555 format, and false for this format. This would have
1942 		// to be tested first, though.
1943 		glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
1944 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1945 				GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_frameData);
1946 		glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1947 		break;
1948 
1949 	case V4L2_PIX_FMT_RGB565:
1950 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1951 				GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_frameData);
1952 		break;
1953 
1954 	case V4L2_PIX_FMT_RGB565X:
1955 		// Note: most likely for big-endian systems SWAP_BYTES should be true
1956 		// for the RGB565 format, and false for this format. This would have
1957 		// to be tested first, though.
1958 		glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
1959 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1960 				GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_frameData);
1961 		glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1962 		break;
1963 
1964 	case V4L2_PIX_FMT_RGB32:
1965 	case V4L2_PIX_FMT_XRGB32:
1966 	case V4L2_PIX_FMT_ARGB32:
1967 	case V4L2_PIX_FMT_HSV32:
1968 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1969 				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
1970 		break;
1971 	case V4L2_PIX_FMT_BGR666:
1972 	case V4L2_PIX_FMT_BGR32:
1973 	case V4L2_PIX_FMT_XBGR32:
1974 	case V4L2_PIX_FMT_ABGR32:
1975 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1976 				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
1977 		break;
1978 	case V4L2_PIX_FMT_RGB24:
1979 	case V4L2_PIX_FMT_BGR24:
1980 	case V4L2_PIX_FMT_HSV24:
1981 	default:
1982 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1983 				GL_RGB, GL_UNSIGNED_BYTE, m_frameData);
1984 		break;
1985 	}
1986 	checkError("RGB paint");
1987 }
1988 
shader_Bayer(__u32 format)1989 void CaptureWinGLEngine::shader_Bayer(__u32 format)
1990 {
1991 	m_screenTextureCount = 1;
1992 	glGenTextures(m_screenTextureCount, m_screenTexture);
1993 	glActiveTexture(GL_TEXTURE0);
1994 	configureTexture(0);
1995 
1996 	switch (format) {
1997 	case V4L2_PIX_FMT_SBGGR8:
1998 	case V4L2_PIX_FMT_SGBRG8:
1999 	case V4L2_PIX_FMT_SGRBG8:
2000 	case V4L2_PIX_FMT_SRGGB8:
2001 		glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
2002 			     m_glRed, GL_UNSIGNED_BYTE, NULL);
2003 		break;
2004 	case V4L2_PIX_FMT_SBGGR10:
2005 	case V4L2_PIX_FMT_SGBRG10:
2006 	case V4L2_PIX_FMT_SGRBG10:
2007 	case V4L2_PIX_FMT_SRGGB10:
2008 	case V4L2_PIX_FMT_SBGGR12:
2009 	case V4L2_PIX_FMT_SGBRG12:
2010 	case V4L2_PIX_FMT_SGRBG12:
2011 	case V4L2_PIX_FMT_SRGGB12:
2012 	case V4L2_PIX_FMT_SBGGR16:
2013 	case V4L2_PIX_FMT_SGBRG16:
2014 	case V4L2_PIX_FMT_SGRBG16:
2015 	case V4L2_PIX_FMT_SRGGB16:
2016 		glTexImage2D(GL_TEXTURE_2D, 0, m_glRed16, m_frameWidth, m_frameHeight, 0,
2017 			     m_glRed, GL_UNSIGNED_SHORT, NULL);
2018 		break;
2019 	}
2020 
2021 	checkError("Bayer shader");
2022 
2023 	QString codeHead = QString("uniform sampler2D tex;"
2024 				   "uniform float tex_h;"
2025 				   "uniform float tex_w;"
2026 				   "uniform float texl_h;"
2027 				   "uniform float texl_w;"
2028 				   "void main()"
2029 				   "{"
2030 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
2031 				   "   float xcoord = floor(xy.x * tex_w);"
2032 				   "   float ycoord = floor(xy.y * tex_h);");
2033 
2034 	if (m_field == V4L2_FIELD_SEQ_TB)
2035 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
2036 	else if (m_field == V4L2_FIELD_SEQ_BT)
2037 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
2038 
2039 	codeHead +=		   "   ycoord = floor(xy.y * tex_h);"
2040 				   "   float r, g, b;"
2041 				   "   vec2 cell;"
2042 				   "   cell.x = (mod(xcoord, 2.0) == 0.0) ? xy.x : xy.x - texl_w;"
2043 				   "   cell.y = (mod(ycoord, 2.0) == 0.0) ? xy.y : xy.y - texl_h;";
2044 
2045 	/* Poor quality Bayer to RGB conversion, but good enough for now */
2046 	switch (format) {
2047 	case V4L2_PIX_FMT_SBGGR8:
2048 	case V4L2_PIX_FMT_SBGGR10:
2049 	case V4L2_PIX_FMT_SBGGR12:
2050 	case V4L2_PIX_FMT_SBGGR16:
2051 		codeHead +=	   "   r = texture2D(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r;"
2052 				   "   g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r;"
2053 				   "   b = texture2D(tex, cell).r;";
2054 		break;
2055 	case V4L2_PIX_FMT_SGBRG8:
2056 	case V4L2_PIX_FMT_SGBRG10:
2057 	case V4L2_PIX_FMT_SGBRG12:
2058 	case V4L2_PIX_FMT_SGBRG16:
2059 		codeHead +=	   "   r = texture2D(tex, vec2(cell.x, cell.y + texl_h)).r;"
2060 				   "   g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r;"
2061 				   "   b = texture2D(tex, vec2(cell.x + texl_w, cell.y)).r;";
2062 		break;
2063 	case V4L2_PIX_FMT_SGRBG8:
2064 	case V4L2_PIX_FMT_SGRBG10:
2065 	case V4L2_PIX_FMT_SGRBG12:
2066 	case V4L2_PIX_FMT_SGRBG16:
2067 		codeHead +=	   "   r = texture2D(tex, vec2(cell.x + texl_w, cell.y)).r;"
2068 				   "   g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r;"
2069 				   "   b = texture2D(tex, vec2(cell.x, cell.y + texl_h)).r;";
2070 		break;
2071 	case V4L2_PIX_FMT_SRGGB8:
2072 	case V4L2_PIX_FMT_SRGGB10:
2073 	case V4L2_PIX_FMT_SRGGB12:
2074 	case V4L2_PIX_FMT_SRGGB16:
2075 		codeHead +=	   "   b = texture2D(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r;"
2076 				   "   g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r;"
2077 				   "   r = texture2D(tex, cell).r;";
2078 		break;
2079 	}
2080 
2081 	switch (format) {
2082 	case V4L2_PIX_FMT_SBGGR10:
2083 	case V4L2_PIX_FMT_SGBRG10:
2084 	case V4L2_PIX_FMT_SGRBG10:
2085 	case V4L2_PIX_FMT_SRGGB10:
2086 		codeHead +=	   "   b = b * (65535.0 / 1023.0);"
2087 				   "   g = g * (65535.0 / 1023.0);"
2088 				   "   r = r * (65535.0 / 1023.0);";
2089 		break;
2090 	case V4L2_PIX_FMT_SBGGR12:
2091 	case V4L2_PIX_FMT_SGBRG12:
2092 	case V4L2_PIX_FMT_SGRBG12:
2093 	case V4L2_PIX_FMT_SRGGB12:
2094 		codeHead +=	   "   b = b * (65535.0 / 4095.0);"
2095 				   "   g = g * (65535.0 / 4095.0);"
2096 				   "   r = r * (65535.0 / 4095.0);";
2097 		break;
2098 	}
2099 
2100 	QString codeTail;
2101 
2102 	if (m_quantization == V4L2_QUANTIZATION_LIM_RANGE)
2103 		codeTail += codeRGBNormalize();
2104 
2105 	codeTail += codeTransformToLinear() +
2106 		    codeColorspaceConversion() +
2107 		    codeTransformToNonLinear() +
2108 		    codeSuffix;
2109 
2110 	bool src_ok = m_shaderProgram.addShaderFromSourceCode(
2111 #if QT_VERSION < 0x060000
2112 				QGLShader::Fragment,
2113 #else
2114 				QOpenGLShader::Fragment,
2115 #endif
2116 				QString("%1%2").arg(codeHead, codeTail));
2117 
2118 	if (!src_ok)
2119 		fprintf(stderr, "OpenGL Error: Bayer shader compilation failed.\n");
2120 
2121 	m_shaderProgram.bind();
2122 }
2123 
render_Bayer(__u32 format)2124 void CaptureWinGLEngine::render_Bayer(__u32 format)
2125 {
2126 	glActiveTexture(GL_TEXTURE0);
2127 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
2128 #if QT_VERSION < 0x060000
2129 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
2130 #else
2131 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
2132 #endif
2133 	glUniform1i(Y, 0);
2134 	int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
2135 	glUniform1f(idx, m_frameHeight);
2136 	idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
2137 	glUniform1f(idx, m_frameWidth);
2138 	idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_h"); // Texture width
2139 	glUniform1f(idx, 1.0 / m_frameHeight);
2140 	idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texture width
2141 	glUniform1f(idx, 1.0 / m_frameWidth);
2142 
2143 	switch (format) {
2144 	case V4L2_PIX_FMT_SBGGR8:
2145 	case V4L2_PIX_FMT_SGBRG8:
2146 	case V4L2_PIX_FMT_SGRBG8:
2147 	case V4L2_PIX_FMT_SRGGB8:
2148 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2149 				m_glRed, GL_UNSIGNED_BYTE, m_frameData);
2150 		break;
2151 	case V4L2_PIX_FMT_SBGGR10:
2152 	case V4L2_PIX_FMT_SGBRG10:
2153 	case V4L2_PIX_FMT_SGRBG10:
2154 	case V4L2_PIX_FMT_SRGGB10:
2155 	case V4L2_PIX_FMT_SBGGR12:
2156 	case V4L2_PIX_FMT_SGBRG12:
2157 	case V4L2_PIX_FMT_SGRBG12:
2158 	case V4L2_PIX_FMT_SRGGB12:
2159 	case V4L2_PIX_FMT_SBGGR16:
2160 	case V4L2_PIX_FMT_SGBRG16:
2161 	case V4L2_PIX_FMT_SGRBG16:
2162 	case V4L2_PIX_FMT_SRGGB16:
2163 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2164 				m_glRed, GL_UNSIGNED_SHORT, m_frameData);
2165 		break;
2166 	}
2167 	checkError("Bayer paint");
2168 }
2169 
shader_YUV_packed(__u32 format)2170 void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
2171 {
2172 	bool hasAlpha = false;
2173 
2174 	m_screenTextureCount = 1;
2175 	glGenTextures(m_screenTextureCount, m_screenTexture);
2176 	glActiveTexture(GL_TEXTURE0);
2177 	configureTexture(0);
2178 
2179 	switch (format) {
2180 	case V4L2_PIX_FMT_YUV555:
2181 		hasAlpha = true;
2182 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2183 			     GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
2184 		break;
2185 
2186 	case V4L2_PIX_FMT_YUV444:
2187 		hasAlpha = true;
2188 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2189 			     GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, NULL);
2190 		break;
2191 
2192 	case V4L2_PIX_FMT_YUV565:
2193 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2194 			     GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
2195 		break;
2196 	case V4L2_PIX_FMT_AYUV32:
2197 		hasAlpha = true;
2198 		// fall-through
2199 	case V4L2_PIX_FMT_YUV32:
2200 	case V4L2_PIX_FMT_XYUV32:
2201 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2202 			     GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
2203 		break;
2204 	case V4L2_PIX_FMT_VUYA32:
2205 		hasAlpha = true;
2206 		// fall-through
2207 	case V4L2_PIX_FMT_VUYX32:
2208 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2209 			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
2210 		break;
2211 	case V4L2_PIX_FMT_YUVA32:
2212 		hasAlpha = true;
2213 		// fall-through
2214 	case V4L2_PIX_FMT_YUVX32:
2215 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2216 			     GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
2217 		break;
2218 	}
2219 
2220 	checkError("Packed YUV shader");
2221 
2222 	QString codeHead = QString("uniform sampler2D tex;"
2223 				   "uniform float tex_h;"
2224 				   "void main()"
2225 				   "{"
2226 				   "   vec2 xy = vec2(gl_TexCoord[0].xy);"
2227 				   "   float ycoord = floor(xy.y * tex_h);");
2228 
2229 	if (m_field == V4L2_FIELD_SEQ_TB)
2230 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
2231 	else if (m_field == V4L2_FIELD_SEQ_BT)
2232 		codeHead += "   xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
2233 
2234 	codeHead +=		   "   vec4 color = texture2D(tex, xy);"
2235 				   "   float a = color.a;";
2236 
2237 	codeHead += "   float y = color.r;"
2238 		    "   float u = color.g - 0.5;"
2239 		    "   float v = color.b - 0.5;";
2240 
2241 	QString codeTail = codeYUVNormalize() +
2242 			   codeYUV2RGB() +
2243 			   codeTransformToLinear() +
2244 			   codeColorspaceConversion() +
2245 			   codeTransformToNonLinear() +
2246 			   (hasAlpha ? codeSuffixWithAlpha : codeSuffix);
2247 
2248 	bool src_ok = m_shaderProgram.addShaderFromSourceCode(
2249 #if QT_VERSION < 0x060000
2250 				QGLShader::Fragment,
2251 #else
2252 				QOpenGLShader::Fragment,
2253 #endif
2254 				QString("%1%2").arg(codeHead, codeTail));
2255 
2256 	if (!src_ok)
2257 		fprintf(stderr, "OpenGL Error: Packed YUV shader compilation failed.\n");
2258 
2259 	m_shaderProgram.bind();
2260 }
2261 
render_YUV_packed(__u32 format)2262 void CaptureWinGLEngine::render_YUV_packed(__u32 format)
2263 {
2264 	glActiveTexture(GL_TEXTURE0);
2265 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
2266 #if QT_VERSION < 0x060000
2267 	GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
2268 #else
2269 	GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
2270 #endif
2271 	glUniform1i(Y, 0);
2272 	int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
2273 	glUniform1f(idx, m_frameHeight);
2274 
2275 	switch (format) {
2276 	case V4L2_PIX_FMT_YUV555:
2277 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2278 				GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_frameData);
2279 		break;
2280 
2281 	case V4L2_PIX_FMT_YUV444:
2282 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2283 				GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, m_frameData);
2284 		break;
2285 
2286 	case V4L2_PIX_FMT_YUV565:
2287 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2288 				GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_frameData);
2289 		break;
2290 
2291 	case V4L2_PIX_FMT_YUV32:
2292 	case V4L2_PIX_FMT_AYUV32:
2293 	case V4L2_PIX_FMT_XYUV32:
2294 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2295 				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
2296 		break;
2297 	case V4L2_PIX_FMT_VUYA32:
2298 	case V4L2_PIX_FMT_VUYX32:
2299 	case V4L2_PIX_FMT_YUVA32:
2300 	case V4L2_PIX_FMT_YUVX32:
2301 		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2302 				GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
2303 		break;
2304 	}
2305 	checkError("Packed YUV paint");
2306 }
2307 
2308 #endif
2309