gl: enable glsl if supported.

TODO: use QGLShaderProgram for better compatibility. user selectable gl
features
This commit is contained in:
wang-bin
2014-02-07 22:37:46 +08:00
parent b4c75f46e5
commit ace8ed3c7a
3 changed files with 145 additions and 107 deletions
+105 -75
View File
@@ -22,8 +22,11 @@
#include "QtAV/GLWidgetRenderer.h"
#include "private/GLWidgetRenderer_p.h"
#include <QResizeEvent>
#include <QtOpenGL/QGLShaderProgram>
#include <QtOpenGL/QGLShader>
//TODO: vsync http://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl
//TODO: check gl errors
/*
//GL_BGRA is available in OpenGL >= 1.2
#ifndef GL_BGRA
#ifndef GL_BGRA_EXT
@@ -41,7 +44,7 @@
#define GL_BGR GL_BGR_EXT
#endif //GL_BGRA
#endif //GL_BGRA
*/
#include <QtAV/FilterContext.h>
#include <QtAV/OSDFilter.h>
@@ -63,26 +66,31 @@ static inline void checkGlError(const char* op = 0) {
qWarning("GL error %s (%#x): %s", op, error, glGetString(error));
}
#ifdef QT_OPENGL_ES_2
static const char kVertexShader[] =
"attribute vec4 a_Position;\n"
"attribute vec2 a_TexCoords; \n"
"uniform highp mat4 u_MVP_matrix;\n"
"varying vec2 v_TexCoords; \n"
"attribute vec2 a_TexCoords;\n"
"uniform mat4 u_MVP_matrix;\n"
"varying vec2 v_TexCoords;\n"
"void main() {\n"
" gl_Position = u_MVP_matrix * a_Position;\n"
" v_TexCoords = a_TexCoords; \n"
"}\n";
static const char kFragmentShader[] =
#ifdef QT_OPENGL_ES_2
"precision mediump float;\n"
"uniform sampler2D u_Texture; \n"
"varying vec2 v_TexCoords; \n"
#endif
"uniform sampler2D u_Texture;\n"
"varying vec2 v_TexCoords;\n"
"void main() {\n"
" gl_FragColor = texture2D(u_Texture, v_TexCoords);\n"
"}\n";
GLuint loadShader(GLenum shaderType, const char* pSource) {
// TODO: use QGLShaderProgram for better compatiblity
GLuint GLWidgetRendererPrivate::loadShader(GLenum shaderType, const char* pSource) {
if (!hasGLSL)
return 0;
GLuint shader = glCreateShader(shaderType);
if (shader) {
glShaderSource(shader, 1, &pSource, NULL);
@@ -107,7 +115,9 @@ GLuint loadShader(GLenum shaderType, const char* pSource) {
return shader;
}
GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
GLuint GLWidgetRendererPrivate::createProgram(const char* pVertexSource, const char* pFragmentSource) {
if (!hasGLSL)
return 0;
GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
if (!vertexShader) {
return 0;
@@ -142,7 +152,6 @@ GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
}
return program;
}
#endif
GLWidgetRenderer::GLWidgetRenderer(QWidget *parent, const QGLWidget* shareWidget, Qt::WindowFlags f):
QGLWidget(parent, shareWidget, f),VideoRenderer(*new GLWidgetRendererPrivate())
@@ -199,13 +208,15 @@ void GLWidgetRenderer::drawFrame()
#ifdef QT_OPENGL_ES_2
#define FMT_INTERNAL GL_BGRA //why BGRA?
#define FMT GL_BGRA
glUseProgram(d.program); //qpainter need
glActiveTexture(GL_TEXTURE0); //TODO: can remove??
glUniform1i(d.tex_location, 0);
#else //QT_OPENGL_ES_2
#define FMT_INTERNAL GL_RGBA //why? why 3 works?
#define FMT GL_BGRA
#endif //QT_OPENGL_ES_2
if (d.hasGLSL) {
glUseProgram(d.program); //qpainter need
glActiveTexture(GL_TEXTURE0); //TODO: can remove??
glUniform1i(d.tex_location, 0);
}
glBindTexture(GL_TEXTURE_2D, d.texture);
d.setupQuality();
QRect roi = realROI();
@@ -262,74 +273,91 @@ void GLWidgetRenderer::drawFrame()
};
#endif //ROI_TEXCOORDS
#ifndef QT_OPENGL_ES_2
//qpainter will reset gl state, so need glMatrixMode and clear color(in drawBackground())
//TODO: study what state will be reset
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//GL_XXX may not defined in ES2. so macro is required
if (!d.hasGLSL) {
//qpainter will reset gl state, so need glMatrixMode and clear color(in drawBackground())
//TODO: study what state will be reset
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
d.setupAspectRatio(); //TODO: can we avoid calling this every time but only in resize event?
glVertexPointer(2, GL_FLOAT, 0, kVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, kTexCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
#else //QT_OPENGL_ES_2
d.setupAspectRatio(); //TODO: can we avoid calling this every time but only in resize event?
//qpainter need. TODO: VBO?
glVertexAttribPointer(d.position_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
glEnableVertexAttribArray(d.position_location);
glVertexAttribPointer(d.tex_coords_location, 2, GL_FLOAT, GL_FALSE, 0, kTexCoords);
glEnableVertexAttribArray(d.tex_coords_location);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableVertexAttribArray(d.tex_coords_location);
glDisableVertexAttribArray(d.position_location);
glPushMatrix();
d.setupAspectRatio(); //TODO: can we avoid calling this every time but only in resize event?
glVertexPointer(2, GL_FLOAT, 0, kVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, kTexCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
#endif //QT_OPENGL_ES_2
if (d.hasGLSL) {
d.setupAspectRatio(); //TODO: can we avoid calling this every time but only in resize event?
//qpainter need. TODO: VBO?
glVertexAttribPointer(d.position_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
glEnableVertexAttribArray(d.position_location);
glVertexAttribPointer(d.tex_coords_location, 2, GL_FLOAT, GL_FALSE, 0, kTexCoords);
glEnableVertexAttribArray(d.tex_coords_location);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableVertexAttribArray(d.tex_coords_location);
glDisableVertexAttribArray(d.position_location);
}
}
void GLWidgetRenderer::initializeGL()
{
DPTR_D(GLWidgetRenderer);
makeCurrent();
//qDebug("OpenGL version: %d.%d", d)
const QByteArray extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
d.hasGLSL = QGLShaderProgram::hasOpenGLShaderPrograms()
#ifndef QT_OPENGL_ES_2
&& extensions.contains("ARB_shader_objects")
#endif
;
initializeGLFunctions();
d.initializeGLFunctions();
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &d.texture);
qDebug("initializeGL~~~~~~~");
#ifdef QT_OPENGL_ES_2
if (d.program)
return;
d.program = createProgram(kVertexShader, kFragmentShader);
if (!d.program) {
qWarning("Could not create program.");
return;
}
d.position_location = glGetAttribLocation(d.program, "a_Position");
checkGlError("glGetAttribLocation");
qDebug("glGetAttribLocation(\"a_Position\") = %d\n", d.position_location);
d.tex_coords_location = glGetAttribLocation(d.program, "a_TexCoords");
checkGlError("glGetAttribLocation");
qDebug("glGetAttribLocation(\"a_TexCoords\") = %d\n", d.tex_coords_location);
d.tex_location = glGetUniformLocation(d.program, "u_Texture");
checkGlError("glGetUniformLocation");
qDebug("glGetUniformLocation(\"u_Texture\") = %d\n", d.tex_location);
d.u_matrix = glGetUniformLocation(d.program, "u_MVP_matrix");
checkGlError("glGetUniformLocation");
qDebug("glGetUniformLocation(\"u_MVP_matrix\") = %d\n", d.u_matrix);
qDebug("initializeGL~~~~~~~ has GLSL: %d", d.hasGLSL);
if (d.hasGLSL) {
if (d.program)
return;
d.program = d.createProgram(kVertexShader, kFragmentShader);
if (!d.program) {
qWarning("Could not create program.");
return;
}
d.position_location = glGetAttribLocation(d.program, "a_Position");
checkGlError("glGetAttribLocation");
qDebug("glGetAttribLocation(\"a_Position\") = %d\n", d.position_location);
d.tex_coords_location = glGetAttribLocation(d.program, "a_TexCoords");
checkGlError("glGetAttribLocation");
qDebug("glGetAttribLocation(\"a_TexCoords\") = %d\n", d.tex_coords_location);
d.tex_location = glGetUniformLocation(d.program, "u_Texture");
checkGlError("glGetUniformLocation");
qDebug("glGetUniformLocation(\"u_Texture\") = %d\n", d.tex_location);
d.u_matrix = glGetUniformLocation(d.program, "u_MVP_matrix");
checkGlError("glGetUniformLocation");
qDebug("glGetUniformLocation(\"u_MVP_matrix\") = %d\n", d.u_matrix);
glUseProgram(d.program);
checkGlError("glUseProgram");
glVertexAttribPointer(d.position_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
checkGlError("glVertexAttribPointer");
glEnableVertexAttribArray(d.position_location);
checkGlError("glEnableVertexAttribArray");
#else
glShadeModel(GL_SMOOTH); //setupQuality?
glClearDepth(1.0f);
glUseProgram(d.program);
checkGlError("glUseProgram");
glVertexAttribPointer(d.position_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
checkGlError("glVertexAttribPointer");
glEnableVertexAttribArray(d.position_location);
checkGlError("glEnableVertexAttribArray");
}
#ifndef QT_OPENGL_ES_2
if (!d.hasGLSL) {
glShadeModel(GL_SMOOTH); //setupQuality?
glClearDepth(1.0f);
}
#endif //QT_OPENGL_ES_2
glClearColor(0.0, 0.0, 0.0, 0.0);
d.setupQuality();
@@ -359,10 +387,12 @@ void GLWidgetRenderer::resizeGL(int w, int h)
d.setupAspectRatio();
#ifndef QT_OPENGL_ES_2
//??
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (!d.hasGLSL) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
#endif //QT_OPENGL_ES_2
}
+2 -1
View File
@@ -24,11 +24,12 @@
#include <QtAV/VideoRenderer.h>
#include <QtOpenGL/QGLWidget>
#include <QtOpenGL/QGLFunctions>
namespace QtAV {
class GLWidgetRendererPrivate;
class Q_AV_EXPORT GLWidgetRenderer : public QGLWidget, public VideoRenderer
class Q_AV_EXPORT GLWidgetRenderer : public QGLWidget, public VideoRenderer, public QGLFunctions
{
Q_OBJECT
DPTR_DECLARE_PRIVATE(GLWidgetRenderer)
+38 -31
View File
@@ -25,33 +25,31 @@
#include "private/VideoRenderer_p.h"
namespace QtAV {
class Q_AV_EXPORT GLWidgetRendererPrivate : public VideoRendererPrivate
class Q_AV_EXPORT GLWidgetRendererPrivate : public VideoRendererPrivate, public QGLFunctions
{
public:
GLWidgetRendererPrivate():
VideoRendererPrivate()
, hasGLSL(true)
, update_texcoords(true)
, texture(0)
#ifdef QT_OPENGL_ES_2
, program(0)
, position_location(0)
, tex_coords_location(0)
, tex_location(0)
, u_matrix(0)
#endif //QT_OPENGL_ES_2
, painter(0)
{
if (QGLFormat::openGLVersionFlags() == QGLFormat::OpenGL_Version_None) {
available = false;
return;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
}
}
~GLWidgetRendererPrivate() {
glDeleteTextures(1, &texture);
}
GLuint loadShader(GLenum shaderType, const char* pSource);
GLuint createProgram(const char* pVertexSource, const char* pFragmentSource);
//GL 4.x: GL_FRAGMENT_SHADER_DERIVATIVE_HINT,GL_TEXTURE_COMPRESSION_HINT
//GL_DONT_CARE(default), GL_FASTEST, GL_NICEST
/*
@@ -69,59 +67,68 @@ public:
//texture zoom in
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#ifndef QT_OPENGL_ES_2
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
if (!hasGLSL) {
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
#endif //QT_OPENGL_ES_2
break;
case VideoRenderer::QualityFastest:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#ifndef QT_OPENGL_ES_2
glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
if (!hasGLSL) {
glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
}
#endif //QT_OPENGL_ES_2
break;
default:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //GL_NEAREST
#ifndef QT_OPENGL_ES_2
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
if (!hasGLSL) {
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
//glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
}
#endif //QT_OPENGL_ES_2
break;
}
}
void setupAspectRatio() {
#ifdef QT_OPENGL_ES_2
const GLfloat matrix[] = {
(float)out_rect.width()/(float)renderer_width, 0, 0, 0,
0, (float)out_rect.height()/(float)renderer_height, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
glUniformMatrix4fv(u_matrix, 1, GL_FALSE/*transpose or not*/, matrix);
#else
glScalef((float)out_rect.width()/(float)renderer_width, (float)out_rect.height()/(float)renderer_height, 0);
#endif
if (hasGLSL) {
const GLfloat matrix[] = {
(float)out_rect.width()/(float)renderer_width, 0, 0, 0,
0, (float)out_rect.height()/(float)renderer_height, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
glUniformMatrix4fv(u_matrix, 1, GL_FALSE/*transpose or not*/, matrix);
}
#ifndef QT_OPENGL_ES_2
if (!hasGLSL) {
glScalef((float)out_rect.width()/(float)renderer_width, (float)out_rect.height()/(float)renderer_height, 0);
}
#endif //QT_OPENGL_ES_2
}
bool hasGLSL;
bool update_texcoords;
GLuint texture;
#ifdef QT_OPENGL_ES_2
//TODO: u_tex, a_position
GLuint program;
GLuint position_location;
GLuint tex_coords_location;
GLuint tex_location;
GLuint u_matrix;
#endif
QPainter *painter;
};