支持直接绘制采集数据的fd句柄,不需要通过DMA将数据dump到内存中再绘制。
代码参考自Jetson Multimedia API,结合QOpenGLWidget的使用心得。
使用了自行编写的一些辅助类,诸如线程互斥锁TLock_t,需要自行替换。
JetsonViewWidget.h
/*
* Ryan chen 2021
* Contact: 70565912@qq.com
*/
#ifndef JETSON_VIEW_WIDGET_H
#define JETSON_VIEW_WIDGET_H
#include <QtCore>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include "Common.h"
#include <GLES2/gl2ext.h>
class JetsonViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
JetsonViewWidget(QWidget* parent = nullptr);
virtual ~JetsonViewWidget();
int Init(int width, int height);
int DrawDmaHandle(int dma_fd);
void Close();
int GetWidth() {return m_width;};
int GetHeight() {return m_height;};
protected:
void initializeGL();
void paintGL();
private:
int InitializeShaders(void);
void CreateShader(GLuint program, GLenum type, const char *source, int size);
int CreateTexture();
int m_width = 0;
int m_height = 0;
TLock_t m_lock;
std::vector<int> m_listDmaFd;
uint32_t m_textureId = 0; /**< Holds the GL Texture ID used for rendering. */
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = 0;
};
#endif // JETSON_VIEW_WIDGET_H
JetsonViewWidget.cpp
/*
* Ryan chen 2021
* Contact: 70565912@qq.com
*/
#include "JetsonViewWidget.h"
#include <QtGui>
#include <QLayout>
#include <QCloseEvent>
#include <nvbuf_utils.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
JetsonViewWidget::JetsonViewWidget(QWidget* parent)
: QOpenGLWidget(parent)
{
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
setFormat(format);
}
JetsonViewWidget::~JetsonViewWidget()
{
Close();
}
int JetsonViewWidget::Init(int width, int height)
{
m_width = width;
m_height = height;
Close();
if (context() && m_width && m_height)
{
makeCurrent();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, m_width, m_height);
glScissor(0, 0, m_width, m_height);
if (InitializeShaders() < 0)
{
printf("Error while initializing shaders\n");
return -1;
}
CreateTexture();
doneCurrent();
}
return 0;
}
void JetsonViewWidget::Close()
{
if (context())
{
if (m_textureId)
{
makeCurrent();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDeleteTextures(1, &m_textureId);
doneCurrent();
}
}
}
int JetsonViewWidget::DrawDmaHandle(int dma_fd)
{
if (!context())
return 0;
if (this->isHidden())
{
printf("window is hidden.\n");
return 0;
}
m_lock.Lock();
m_listDmaFd.push_back(dma_fd);
m_lock.Unlock();
QMetaObject::invokeMethod(this, "update");
return 0;
}
void JetsonViewWidget::initializeGL()
{
initializeOpenGLFunctions();
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
if (!glEGLImageTargetTexture2DOES)
printf("ERROR getting proc addr of glEGLImageTargetTexture2DOES\n");
Init(m_width, m_height);
}
void JetsonViewWidget::paintGL()
{
int dma_fd = 0;
m_lock.Lock();
if (m_listDmaFd.size())
dma_fd = m_listDmaFd.back();
m_listDmaFd.clear();
m_lock.Unlock();
if (!dma_fd)
return;
if (isHidden())
return;
EGLDisplay egl_display = eglGetCurrentDisplay();
if (!egl_display)
return;
EGLImageKHR hEglImage;
int iErr;
hEglImage = NvEGLImageFromFd(egl_display, dma_fd);
if (!hEglImage)
{
printf("Could not get EglImage from fd. Not rendering\n");
return;
}
makeCurrent();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, hEglImage);
glDrawArrays(GL_TRIANGLES, 0, 6);
iErr = glGetError();
if (iErr != GL_NO_ERROR)
{
printf("glDrawArrays arrays failed: %d\n", iErr);
}
doneCurrent();
NvDestroyEGLImage(egl_display, hEglImage);
}
void JetsonViewWidget::CreateShader(GLuint program, GLenum type, const char *source, int size)
{
char log[4096];
int result = GL_FALSE;
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, &size);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(shader, sizeof(log), NULL, log);
printf("Got Fatal Log as %s\n", log);
}
glAttachShader(program, shader);
if (glGetError() != GL_NO_ERROR)
{
printf("Got gl error as %d\n", glGetError());
}
}
int JetsonViewWidget::InitializeShaders(void)
{
GLuint program;
int result = GL_FALSE;
char log[4096];
uint32_t pos_location = 0;
// pos_x, pos_y, uv_u, uv_v
float vertexTexBuf[24] = {
-1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f,
};
static const char kVertexShader[] = "varying vec2 interp_tc;\n"
"attribute vec4 in_pos;\n"
"void main() { \n"
"interp_tc = in_pos.zw; \n" "gl_Position = vec4(in_pos.xy, 0, 1); \n" "}\n";
static const char kFragmentShader[] =
"#extension GL_OES_EGL_image_external : require\n"
"precision mediump float;\n" "varying vec2 interp_tc; \n"
"uniform samplerExternalOES tex; \n" "void main() {\n"
"gl_FragColor = texture2D(tex, interp_tc);\n" "}\n";
glEnable(GL_SCISSOR_TEST);
program = glCreateProgram();
CreateShader(program, GL_VERTEX_SHADER, kVertexShader,
sizeof(kVertexShader));
CreateShader(program, GL_FRAGMENT_SHADER, kFragmentShader,
sizeof(kFragmentShader));
glLinkProgram(program);
if (glGetError() != GL_NO_ERROR)
{
printf("Got gl error as %d\n", glGetError());
return -1;
}
glGetProgramiv(program, GL_LINK_STATUS, &result);
if (!result)
{
glGetShaderInfoLog(program, sizeof(log), NULL, log);
printf("Error while Linking %s\n", log);
return -1;
}
glUseProgram(program);
if (glGetError() != GL_NO_ERROR)
{
printf("Got gl error as %d\n", glGetError());
return -1;
}
GLuint vbo; // Store vetex and tex coords
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexTexBuf), vertexTexBuf, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
pos_location = glGetAttribLocation(program, "in_pos");
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(pos_location, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(pos_location);
glActiveTexture(GL_TEXTURE0);
glUniform1i(glGetUniformLocation(program, "texSampler"), 0);
if (glGetError() != GL_NO_ERROR)
{
printf("Got gl error as %d\n", glGetError());
return -1;
}
printf("Shaders intialized\n");
return 0;
}
int JetsonViewWidget::CreateTexture()
{
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glScissor(viewport[0], viewport[1], viewport[2], viewport[3]);
glGenTextures(1, &m_textureId);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId);
return 0;
}