From ace8ed3c7ac174154e16f2626bf2c7fb235154cb Mon Sep 17 00:00:00 2001 From: wang-bin Date: Fri, 7 Feb 2014 18:20:11 +0800 Subject: [PATCH] gl: enable glsl if supported. TODO: use QGLShaderProgram for better compatibility. user selectable gl features --- src/GLWidgetRenderer.cpp | 180 +++++++++++++++----------- src/QtAV/GLWidgetRenderer.h | 3 +- src/QtAV/private/GLWidgetRenderer_p.h | 69 +++++----- 3 files changed, 145 insertions(+), 107 deletions(-) diff --git a/src/GLWidgetRenderer.cpp b/src/GLWidgetRenderer.cpp index 951b2c73..9c33e8c2 100644 --- a/src/GLWidgetRenderer.cpp +++ b/src/GLWidgetRenderer.cpp @@ -22,8 +22,11 @@ #include "QtAV/GLWidgetRenderer.h" #include "private/GLWidgetRenderer_p.h" #include +#include +#include //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 #include @@ -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(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 } diff --git a/src/QtAV/GLWidgetRenderer.h b/src/QtAV/GLWidgetRenderer.h index 3ce02d9e..cff27c98 100644 --- a/src/QtAV/GLWidgetRenderer.h +++ b/src/QtAV/GLWidgetRenderer.h @@ -24,11 +24,12 @@ #include #include +#include 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) diff --git a/src/QtAV/private/GLWidgetRenderer_p.h b/src/QtAV/private/GLWidgetRenderer_p.h index b3973e0e..082d16c6 100644 --- a/src/QtAV/private/GLWidgetRenderer_p.h +++ b/src/QtAV/private/GLWidgetRenderer_p.h @@ -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; };