[libcamera-devel] [RFC] [PATCH 2/3] Added opengl widget class for qcam

Show Liu show.liu at linaro.org
Fri Mar 20 09:50:28 CET 2020


qcam: Added opengl widget class for qcam

Signed-off-by: Show Liu <show.liu at linaro.org>
---
 src/qcam/glwidget.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++
 src/qcam/glwidget.h   |  76 +++++++++++++++
 src/qcam/meson.build  |   4 +-
 3 files changed, 292 insertions(+), 1 deletion(-)
 create mode 100644 src/qcam/glwidget.cpp
 create mode 100644 src/qcam/glwidget.h

diff --git a/src/qcam/glwidget.cpp b/src/qcam/glwidget.cpp
new file mode 100644
index 0000000..bf6add4
--- /dev/null
+++ b/src/qcam/glwidget.cpp
@@ -0,0 +1,213 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * glwidget.cpp - Rendering YUV frame by OpenGL shader
+ */
+
+#include "glwidget.h"
+#include <QImage>
+
+#define ATTRIB_VERTEX 0
+#define ATTRIB_TEXTURE 1
+
+GLWidget::GLWidget(QWidget *parent)
+	: QOpenGLWidget(parent),
+	textureY(QOpenGLTexture::Target2D),
+	textureU(QOpenGLTexture::Target2D),
+	textureV(QOpenGLTexture::Target2D),
+	yuvDataPtr(NULL),
+	glBuffer(QOpenGLBuffer::VertexBuffer)
+{
+}
+
+GLWidget::~GLWidget()
+{
+	removeShader();
+
+	textureY.destroy();
+	textureU.destroy();
+	textureV.destroy();
+
+	glBuffer.destroy();
+}
+
+void GLWidget::updateFrame(unsigned char  *buffer)
+{
+	if(buffer) {
+		yuvDataPtr = buffer;
+		update();
+	}
+}
+
+void GLWidget::setFrameSize(int width, int height)
+{
+	if(width > 0 && height > 0) {
+		width_ = width;
+		height_ = height;
+	}
+}
+
+int GLWidget::configure(unsigned int format, unsigned int width,
+						unsigned int height)
+{
+	switch (format) {
+	case DRM_FORMAT_NV12:
+	break;
+	case DRM_FORMAT_NV21:
+	break;
+	default:
+		return -EINVAL;
+	};
+	format_ = format;
+	width_ = width;
+	height_ = height;
+
+	return 0;
+}
+
+void GLWidget::createShader()
+{
+	bool ret = false;
+
+	QString vsrc =  "attribute vec4 vertexIn; \n"
+					"attribute vec2 textureIn; \n"
+					"varying vec2 textureOut; \n"
+					"void main(void) \n"
+					"{ \n"
+						"gl_Position = vertexIn; \n"
+						"textureOut = textureIn; \n"
+					"} \n";
+
+	ret = shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
+	if(!ret) {
+		qDebug() << __func__ << ":" << shaderProgram.log();
+	}
+
+	QString fsrc =  "#ifdef GL_ES \n"
+					"precision highp float; \n"
+					"#endif \n"
+					"varying vec2 textureOut; \n"
+					"uniform sampler2D tex_y; \n"
+					"uniform sampler2D tex_uv; \n"
+					"void main(void) \n"
+					"{ \n"
+					"vec3 yuv; \n"
+					"vec3 rgb; \n"
+					"yuv.x = texture2D(tex_y, textureOut).r - 0.0625; \n"
+					"yuv.y = texture2D(tex_uv, textureOut).r - 0.5; \n"
+					"yuv.z = texture2D(tex_uv, textureOut).g - 0.5; \n"
+					"rgb = mat3( 1.0,       1.0,         1.0, \n"
+					 "           0.0,       -0.39465,  2.03211, \n"
+					 "           1.13983, -0.58060,  0.0) * yuv; \n"
+					"gl_FragColor = vec4(rgb, 1.0); \n"
+					"}\n";
+	ret = shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);
+	if(!ret) {
+		qDebug() << __func__ << ":" << shaderProgram.log();
+	}
+
+	// Link shader pipeline
+	if (!shaderProgram.link()) {
+		qDebug() << __func__ << ": shader program link failed.\n" << shaderProgram.log();
+		close();
+	}
+
+	// Bind shader pipeline for use
+	if (!shaderProgram.bind()) {
+		qDebug() << __func__ << ": shader program binding failed.\n" << shaderProgram.log();
+		close();
+	}
+
+}
+
+void GLWidget::configureTexture(unsigned int id)
+{
+	glBindTexture(GL_TEXTURE_2D, id);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void GLWidget::removeShader()
+{
+	if (shaderProgram.isLinked()) {
+		shaderProgram.release();
+		shaderProgram.removeAllShaders();
+	}
+}
+
+void GLWidget::initializeGL()
+{
+	initializeOpenGLFunctions();
+
+
+	glEnable(GL_TEXTURE_2D);
+	glDisable(GL_DEPTH_TEST);
+
+	static const GLfloat vertices[] {
+		-1.0f,-1.0f,
+		-1.0f,+1.0f,
+		+1.0f,+1.0f,
+		+1.0f,-1.0f,
+		0.0f,1.0f,
+		0.0f,0.0f,
+		1.0f,0.0f,
+		1.0f,1.0f,
+	};
+
+	glBuffer.create();
+	glBuffer.bind();
+	glBuffer.allocate(vertices,sizeof(vertices));
+
+	createShader();
+
+	shaderProgram.enableAttributeArray(ATTRIB_VERTEX);
+	shaderProgram.enableAttributeArray(ATTRIB_TEXTURE);
+
+	shaderProgram.setAttributeBuffer(ATTRIB_VERTEX,GL_FLOAT,0,2,2*sizeof(GLfloat));
+	shaderProgram.setAttributeBuffer(ATTRIB_TEXTURE,GL_FLOAT,8*sizeof(GLfloat),2,2*sizeof(GLfloat));
+
+	textureUniformY = shaderProgram.uniformLocation("tex_y");
+	textureUniformU = shaderProgram.uniformLocation("tex_uv");
+
+	textureY.create();
+	textureU.create();
+
+	id_y = textureY.textureId();
+	id_u = textureU.textureId();
+
+	configureTexture(id_y);
+	configureTexture(id_u);
+
+	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
+}
+
+void GLWidget::paintGL()
+{
+	if(yuvDataPtr)
+	{
+		glClearColor(0.0, 0.0, 0.0, 1.0);
+		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+		// activate texture Y
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, id_y);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width_, height_, 0, GL_RED, GL_UNSIGNED_BYTE, yuvDataPtr);
+		glUniform1i(textureUniformY, 0);
+
+		// activate texture UV
+		glActiveTexture(GL_TEXTURE1);
+		glBindTexture(GL_TEXTURE_2D, id_u);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, width_/2, height_/2, 0, GL_RG, GL_UNSIGNED_BYTE, (char*)yuvDataPtr+width_*height_);
+		glUniform1i(textureUniformU, 1);
+
+		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+	}
+}
+
+void GLWidget::resizeGL(int w, int h)
+{
+	glViewport(0,0,w,h);
+}
diff --git a/src/qcam/glwidget.h b/src/qcam/glwidget.h
new file mode 100644
index 0000000..17f71b9
--- /dev/null
+++ b/src/qcam/glwidget.h
@@ -0,0 +1,76 @@
+#ifndef GLWINDOW_H
+#define GLWINDOW_H
+
+#include <fcntl.h>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string.h>
+#include <unistd.h>
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * glwidget.h - Rendering YUV frame by OpenGL shader
+ */
+#include <QOpenGLTexture>
+#include <QOpenGLShader>
+#include <QOpenGLShaderProgram>
+
+#include <QOpenGLBuffer>
+#include <QImage>
+
+#include <linux/drm_fourcc.h>
+
+class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
+{
+	Q_OBJECT
+
+public:
+	GLWidget(QWidget *parent = 0);
+	~GLWidget();
+
+	void        setFrameSize(int width, int height);
+	void        updateFrame(unsigned char  *buffer);
+
+	int configure(unsigned int format, unsigned int width,
+					unsigned int height);
+
+	void createShader();
+
+protected:
+	void        initializeGL() Q_DECL_OVERRIDE;
+	void        paintGL() Q_DECL_OVERRIDE;
+	void        resizeGL(int w, int h) Q_DECL_OVERRIDE;
+
+private:
+
+	void configureTexture(unsigned int id);
+	void removeShader();
+
+	QOpenGLShader *pVShader;
+	QOpenGLShader *pFShader;
+	QOpenGLShaderProgram shaderProgram;
+
+	GLuint textureUniformY;
+	GLuint textureUniformU;
+	GLuint textureUniformV;
+	GLuint id_y;
+	GLuint id_u;
+	GLuint id_v;
+	QOpenGLTexture textureY;
+	QOpenGLTexture textureU;
+	QOpenGLTexture textureV;
+
+	unsigned int format_;
+	unsigned int width_;
+	unsigned int height_;
+
+	unsigned char* yuvDataPtr;
+
+	QOpenGLBuffer glBuffer;
+};
+#endif // GLWINDOW_H
diff --git a/src/qcam/meson.build b/src/qcam/meson.build
index 5150631..8bbcfba 100644
--- a/src/qcam/meson.build
+++ b/src/qcam/meson.build
@@ -5,10 +5,12 @@ qcam_sources = files([
     '../cam/options.cpp',
     'qt_event_dispatcher.cpp',
     'viewfinder.cpp',
+    'glwidget.cpp'
 ])
 
 qcam_moc_headers = files([
     'main_window.h',
+    'glwidget.h'
 ])
 
 qcam_resources = files([
@@ -18,7 +20,7 @@ qcam_resources = files([
 qt5 = import('qt5')
 qt5_dep = dependency('qt5',
                      method : 'pkg-config',
-                     modules : ['Core', 'Gui', 'Widgets'],
+                     modules : ['Core', 'Gui', 'Widgets','OpenGL', 'OpenGLExtensions'],
                      required : false)
 
 if qt5_dep.found()
-- 
2.20.1



More information about the libcamera-devel mailing list