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