[libcamera-devel] [PATCH v4 2/3] qcam: add OpenGL renderer
Show Liu
show.liu at linaro.org
Tue Sep 8 03:52:53 CEST 2020
Hi Laurent,
On Sun, Sep 6, 2020 at 8:58 AM Laurent Pinchart <
laurent.pinchart at ideasonboard.com> wrote:
> Hi Show,
>
> On Fri, Sep 04, 2020 at 04:43:13PM +0800, Show Liu wrote:
> > qcam: add OpenGL renderer
> >
> > Signed-off-by: Show Liu <show.liu at linaro.org>
>
> Do I assume correctly that this was a stray file that shouldn't have
> been sent as part of this series ?
>
Yes. Please skip this.
Sorry for the confusion.
Best Regards,
Show Liu
>
> > ---
> > src/qcam/meson.build | 2 +
> > src/qcam/renderer.cpp | 346 ++++++++++++++++++++++++++++++++++++++++++
> > src/qcam/renderer.h | 81 ++++++++++
> > 3 files changed, 429 insertions(+)
> > create mode 100644 src/qcam/renderer.cpp
> > create mode 100644 src/qcam/renderer.h
> >
> > diff --git a/src/qcam/meson.build b/src/qcam/meson.build
> > index e0c6f26..8c9032f 100644
> > --- a/src/qcam/meson.build
> > +++ b/src/qcam/meson.build
> > @@ -7,11 +7,13 @@ qcam_sources = files([
> > 'main.cpp',
> > 'main_window.cpp',
> > 'viewfinder.cpp',
> > + 'renderer.cpp'
> > ])
> >
> > qcam_moc_headers = files([
> > 'main_window.h',
> > 'viewfinder.h',
> > + 'renderer.h'
> > ])
> >
> > qcam_resources = files([
> > diff --git a/src/qcam/renderer.cpp b/src/qcam/renderer.cpp
> > new file mode 100644
> > index 0000000..23e8fa8
> > --- /dev/null
> > +++ b/src/qcam/renderer.cpp
> > @@ -0,0 +1,346 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (C) 2020, Linaro
> > + *
> > + * renderer.cpp - Render YUV format frame by OpenGL shader
> > + */
> > +
> > +#include "renderer.h"
> > +
> > +Renderer::Renderer()
> > + : fbo_(nullptr),
> > + vbo_(QOpenGLBuffer::VertexBuffer),
> > + pFShader_(nullptr),
> > + pVShader_(nullptr),
> > + textureU_(QOpenGLTexture::Target2D),
> > + textureV_(QOpenGLTexture::Target2D),
> > + textureY_(QOpenGLTexture::Target2D)
> > +{
> > + /* offscreen format setup */
> > + setFormat(requestedFormat());
> > + create();
> > +
> > + /* create OpenGL context */
> > + if (ctx_.create()) {
> > + ctx_.makeCurrent(this);
> > + initializeOpenGLFunctions();
> > + } else {
> > + qWarning() << "[Renderer]: "
> > + << "OpenGL renderer is not available.";
> > + }
> > +}
> > +
> > +Renderer::~Renderer()
> > +{
> > + if (vbo_.isCreated()) {
> > + vbo_.release();
> > + vbo_.destroy();
> > + }
> > +
> > + if (fbo_) {
> > + fbo_->release();
> > + delete fbo_;
> > + }
> > +
> > + removeShader();
> > +
> > + if (textureY_.isCreated())
> > + textureY_.destroy();
> > +
> > + if (textureU_.isCreated())
> > + textureU_.destroy();
> > +
> > + if (textureV_.isCreated())
> > + textureV_.destroy();
> > +
> > + ctx_.doneCurrent();
> > +}
> > +
> > +void Renderer::initializeGL()
> > +{
> > + 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
> > + };
> > +
> > + vbo_.create();
> > + vbo_.bind();
> > + vbo_.allocate(vertices, sizeof(vertices));
> > +
> > + glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
> > +}
> > +
> > +bool Renderer::selectShader(const libcamera::PixelFormat &format)
> > +{
> > + bool ret = true;
> > + switch (format) {
> > + case libcamera::formats::NV12:
> > + horzSubSample_ = 2;
> > + vertSubSample_ = 2;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_2_planes_UV_f.glsl";
> > + break;
> > + case libcamera::formats::NV21:
> > + horzSubSample_ = 2;
> > + vertSubSample_ = 2;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_2_planes_VU_f.glsl";
> > + break;
> > + case libcamera::formats::NV16:
> > + horzSubSample_ = 2;
> > + vertSubSample_ = 1;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_2_planes_UV_f.glsl";
> > + break;
> > + case libcamera::formats::NV61:
> > + horzSubSample_ = 2;
> > + vertSubSample_ = 1;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_2_planes_VU_f.glsl";
> > + break;
> > + case libcamera::formats::NV24:
> > + horzSubSample_ = 1;
> > + vertSubSample_ = 1;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_2_planes_UV_f.glsl";
> > + break;
> > + case libcamera::formats::NV42:
> > + horzSubSample_ = 1;
> > + vertSubSample_ = 1;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_2_planes_VU_f.glsl";
> > + break;
> > + case libcamera::formats::YUV420:
> > + horzSubSample_ = 2;
> > + vertSubSample_ = 2;
> > + vsrc_ = ":NV_vertex_shader.glsl";
> > + fsrc_ = ":NV_3_planes_UV_f.glsl";
> > + break;
> > + default:
> > + ret = false;
> > + qWarning() << "[Renderer]: "
> > + << "format not support yet.";
> > + break;
> > + };
> > +
> > + return ret;
> > +}
> > +
> > +void Renderer::removeShader()
> > +{
> > + if (shaderProgram_.isLinked()) {
> > + shaderProgram_.release();
> > + shaderProgram_.removeAllShaders();
> > + }
> > +
> > + if (pFShader_)
> > + delete pFShader_;
> > +
> > + if (pVShader_)
> > + delete pVShader_;
> > +}
> > +
> > +bool Renderer::createShader()
> > +{
> > + bool bCompile;
> > +
> > + /* Create Vertex Shader */
> > + pVShader_ = new QOpenGLShader(QOpenGLShader::Vertex, this);
> > +
> > + bCompile = pVShader_->compileSourceFile(vsrc_);
> > + if (!bCompile) {
> > + qWarning() << "[Renderer]: " << pVShader_->log();
> > + return bCompile;
> > + }
> > +
> > + shaderProgram_.addShader(pVShader_);
> > +
> > + /* Create Fragment Shader */
> > + pFShader_ = new QOpenGLShader(QOpenGLShader::Fragment, this);
> > +
> > + bCompile = pFShader_->compileSourceFile(fsrc_);
> > + if (!bCompile) {
> > + qWarning() << "[Renderer]: " << pFShader_->log();
> > + return bCompile;
> > + }
> > +
> > + shaderProgram_.addShader(pFShader_);
> > +
> > + // Link shader pipeline
> > + if (!shaderProgram_.link()) {
> > + qWarning() << "[Renderer]: " << shaderProgram_.log();
> > + return false;
> > + }
> > +
> > + // Bind shader pipeline for use
> > + if (!shaderProgram_.bind()) {
> > + qWarning() << "[Renderer]: " << shaderProgram_.log();
> > + return false;
> > + }
> > + return true;
> > +}
> > +
> > +bool Renderer::configure(const libcamera::PixelFormat &format, const
> QSize &size)
> > +{
> > + bool ret = true;
> > +
> > + if (selectShader(format)) {
> > + ret = createShader();
> > + if (!ret)
> > + return ret;
> > +
> > + 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_u");
> > + textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
> > +
> > + if (!textureY_.isCreated())
> > + textureY_.create();
> > +
> > + if (!textureU_.isCreated())
> > + textureU_.create();
> > +
> > + if (!textureV_.isCreated())
> > + textureV_.create();
> > +
> > + id_y_ = textureY_.textureId();
> > + id_u_ = textureU_.textureId();
> > + id_v_ = textureV_.textureId();
> > +
> > + fbo_ = new QOpenGLFramebufferObject(size.width(),
> > + size.height(),
> > + GL_TEXTURE_2D);
> > + fbo_->bind();
> > + glViewport(0, 0, size.width(), size.height());
> > +
> > + format_ = format;
> > + size_ = size;
> > + } else {
> > + ret = false;
> > + }
> > + return ret;
> > +}
> > +
> > +void Renderer::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 Renderer::render(unsigned char *buffer)
> > +{
> > + QMutexLocker locker(&mutex_);
> > +
> > + glClearColor(0.0, 0.0, 0.0, 1.0);
> > + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
> > +
> > + switch (format_) {
> > + case libcamera::formats::NV12:
> > + case libcamera::formats::NV21:
> > + case libcamera::formats::NV16:
> > + case libcamera::formats::NV61:
> > + case libcamera::formats::NV24:
> > + case libcamera::formats::NV42:
> > + /* activate texture 0 */
> > + glActiveTexture(GL_TEXTURE0);
> > + configureTexture(id_y_);
> > + glTexImage2D(GL_TEXTURE_2D,
> > + 0,
> > + GL_RED,
> > + size_.width(),
> > + size_.height(),
> > + 0,
> > + GL_RED,
> > + GL_UNSIGNED_BYTE,
> > + buffer);
> > + glUniform1i(textureUniformY_, 0);
> > +
> > + /* activate texture 1 */
> > + glActiveTexture(GL_TEXTURE1);
> > + configureTexture(id_u_);
> > + glTexImage2D(GL_TEXTURE_2D,
> > + 0,
> > + GL_RG,
> > + size_.width() / horzSubSample_,
> > + size_.height() / vertSubSample_,
> > + 0,
> > + GL_RG,
> > + GL_UNSIGNED_BYTE,
> > + buffer + size_.width() * size_.height());
> > + glUniform1i(textureUniformU_, 1);
> > + break;
> > + case libcamera::formats::YUV420:
> > + /* activate texture 0 */
> > + glActiveTexture(GL_TEXTURE0);
> > + configureTexture(id_y_);
> > + glTexImage2D(GL_TEXTURE_2D,
> > + 0,
> > + GL_RED,
> > + size_.width(),
> > + size_.height(),
> > + 0,
> > + GL_RED,
> > + GL_UNSIGNED_BYTE,
> > + buffer);
> > + glUniform1i(textureUniformY_, 0);
> > +
> > + /* activate texture 1 */
> > + glActiveTexture(GL_TEXTURE1);
> > + configureTexture(id_u_);
> > + glTexImage2D(GL_TEXTURE_2D,
> > + 0,
> > + GL_RG,
> > + size_.width() / horzSubSample_,
> > + size_.height() / vertSubSample_,
> > + 0,
> > + GL_RG,
> > + GL_UNSIGNED_BYTE,
> > + buffer + size_.width() * size_.height());
> > + glUniform1i(textureUniformU_, 1);
> > +
> > + /* activate texture 2 */
> > + glActiveTexture(GL_TEXTURE2);
> > + configureTexture(id_v_);
> > + glTexImage2D(GL_TEXTURE_2D,
> > + 0,
> > + GL_RG,
> > + size_.width() / horzSubSample_,
> > + size_.height() / vertSubSample_,
> > + 0, GL_RG,
> > + GL_UNSIGNED_BYTE,
> > + buffer + size_.width() * size_.height() * 5 /
> 4);
> > + glUniform1i(textureUniformV_, 2);
> > + break;
> > + default:
> > + break;
> > + };
> > +
> > + glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
> > +}
> > +
> > +QImage Renderer::toImage()
> > +{
> > + QMutexLocker locker(&mutex_);
> > + return (fbo_->toImage(true));
> > +}
> > diff --git a/src/qcam/renderer.h b/src/qcam/renderer.h
> > new file mode 100644
> > index 0000000..1ea0c48
> > --- /dev/null
> > +++ b/src/qcam/renderer.h
> > @@ -0,0 +1,81 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (C) 2020, Linaro
> > + *
> > + * renderer.h - Render YUV format frame by OpenGL shader
> > + */
> > +#ifndef __QCAM_RENDERER_H__
> > +#define __QCAM_RENDERER_H__
> > +
> > +#include <QImage>
> > +#include <QMutex>
> > +#include <QOffscreenSurface>
> > +#include <QOpenGLBuffer>
> > +#include <QOpenGLContext>
> > +#include <QOpenGLFramebufferObject>
> > +#include <QOpenGLFunctions>
> > +#include <QOpenGLShader>
> > +#include <QOpenGLShaderProgram>
> > +#include <QOpenGLTexture>
> > +#include <QSize>
> > +#include <QSurfaceFormat>
> > +
> > +#include <libcamera/formats.h>
> > +
> > +#define ATTRIB_VERTEX 0
> > +#define ATTRIB_TEXTURE 1
> > +
> > +class Renderer : public QOffscreenSurface, protected QOpenGLFunctions
> > +{
> > + Q_OBJECT
> > +
> > +public:
> > + Renderer();
> > + ~Renderer();
> > +
> > + void initializeGL();
> > + bool configure(const libcamera::PixelFormat &format, const QSize
> &size);
> > + void render(unsigned char *buffer);
> > + QImage toImage();
> > +
> > +private:
> > + bool createShader();
> > + void configureTexture(unsigned int id);
> > + void removeShader();
> > + bool selectShader(const libcamera::PixelFormat &format);
> > +
> > + /* OpenGL renderer components */
> > + QOpenGLContext ctx_;
> > + QOpenGLFramebufferObject *fbo_;
> > + QOpenGLBuffer vbo_;
> > + QOpenGLShader *pFShader_;
> > + QOpenGLShader *pVShader_;
> > + QOpenGLShaderProgram shaderProgram_;
> > + QSurfaceFormat surfaceFormat_;
> > +
> > + /* Fragment and Vertex shader file */
> > + QString fsrc_;
> > + QString vsrc_;
> > +
> > + /* YUV frame size and format */
> > + libcamera::PixelFormat format_;
> > + QSize size_;
> > +
> > + /* YUV texture planars and parameters*/
> > + GLuint id_u_;
> > + GLuint id_v_;
> > + GLuint id_y_;
> > + GLuint textureUniformU_;
> > + GLuint textureUniformV_;
> > + GLuint textureUniformY_;
> > + QOpenGLTexture textureU_;
> > + QOpenGLTexture textureV_;
> > + QOpenGLTexture textureY_;
> > + unsigned int horzSubSample_;
> > + unsigned int vertSubSample_;
> > +
> > + QImage image_;
> > + QMutex mutex_; /* Prevent concurrent access to image_ */
> > +};
> > +
> > +#endif /* __QCAM_RENDERER_H__ */
>
> --
> Regards,
>
> Laurent Pinchart
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.libcamera.org/pipermail/libcamera-devel/attachments/20200908/b954eb68/attachment-0001.htm>
More information about the libcamera-devel
mailing list