diff --git a/sdrgui/gui/glshadertvarray.cpp b/sdrgui/gui/glshadertvarray.cpp index 0ed685258..a01f05221 100644 --- a/sdrgui/gui/glshadertvarray.cpp +++ b/sdrgui/gui/glshadertvarray.cpp @@ -20,25 +20,48 @@ #include "gui/glshadertvarray.h" -const QString GLShaderTVArray::m_strVertexShaderSourceArray = QString( +const QString GLShaderTVArray::m_strVertexShaderSourceArray2 = QString( "uniform highp mat4 uMatrix;\n" - "attribute highp vec4 vertex;\n" - "attribute highp vec2 texCoord;\n" - "varying mediump vec2 texCoordVar;\n" - "void main() {\n" - " gl_Position = uMatrix * vertex;\n" - " texCoordVar = texCoord;\n" - "}\n"); + "attribute highp vec4 vertex;\n" + "attribute highp vec2 texCoord;\n" + "varying mediump vec2 texCoordVar;\n" + "void main() {\n" + " gl_Position = uMatrix * vertex;\n" + " texCoordVar = texCoord;\n" + "}\n"); + +const QString GLShaderTVArray::m_strVertexShaderSourceArray = QString( + "#version 330\n" + "uniform highp mat4 uMatrix;\n" + "in highp vec4 vertex;\n" + "in highp vec2 texCoord;\n" + "out mediump vec2 texCoordVar;\n" + "void main() {\n" + " gl_Position = uMatrix * vertex;\n" + " texCoordVar = texCoord;\n" + "}\n"); + +const QString GLShaderTVArray::m_strFragmentShaderSourceColored2 = QString( + "uniform lowp sampler2D uTexture;\n" + "varying mediump vec2 texCoordVar;\n" + "void main() {\n" + " gl_FragColor = texture2D(uTexture, texCoordVar);\n" + "}\n"); const QString GLShaderTVArray::m_strFragmentShaderSourceColored = QString( + "#version 330\n" "uniform lowp sampler2D uTexture;\n" - "varying mediump vec2 texCoordVar;\n" - "void main() {\n" - " gl_FragColor = texture2D(uTexture, texCoordVar);\n" - "}\n"); + "in mediump vec2 texCoordVar;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " fragColor = texture(uTexture, texCoordVar);\n" + "}\n"); GLShaderTVArray::GLShaderTVArray(bool blnColor) : m_objProgram(nullptr), + m_vao(nullptr), + m_verticesBuf(nullptr), + m_textureCoordsBuf(nullptr), m_matrixLoc(0), m_textureLoc(0), m_objImage(nullptr), @@ -59,7 +82,7 @@ GLShaderTVArray::~GLShaderTVArray() cleanup(); } -void GLShaderTVArray::initializeGL(int intCols, int intRows) +void GLShaderTVArray::initializeGL(int majorVersion, int minorVersion, int intCols, int intRows) { QMatrix4x4 objQMatrix; @@ -73,20 +96,43 @@ void GLShaderTVArray::initializeGL(int intCols, int intRows) if (!m_objProgram) { m_objProgram = new QOpenGLShaderProgram(); - - if (!m_objProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, - m_strVertexShaderSourceArray)) + if ((majorVersion > 3) || ((majorVersion == 3) && (minorVersion >= 3))) { - qDebug() << "GLShaderArray::initializeGL: error in vertex shader: " - << m_objProgram->log(); + if (!m_objProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, + m_strVertexShaderSourceArray)) + { + qDebug() << "GLShaderArray::initializeGL: error in vertex shader: " + << m_objProgram->log(); + } + + if (!m_objProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, + m_strFragmentShaderSourceColored)) + { + qDebug() + << "GLShaderArray::initializeGL: error in fragment shader: " + << m_objProgram->log(); + } + + m_vao = new QOpenGLVertexArrayObject(); + m_vao->create(); + m_vao->bind(); } - - if (!m_objProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, - m_strFragmentShaderSourceColored)) + else { - qDebug() - << "GLShaderArray::initializeGL: error in fragment shader: " - << m_objProgram->log(); + if (!m_objProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, + m_strVertexShaderSourceArray2)) + { + qDebug() << "GLShaderArray::initializeGL: error in vertex shader: " + << m_objProgram->log(); + } + + if (!m_objProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, + m_strFragmentShaderSourceColored2)) + { + qDebug() + << "GLShaderArray::initializeGL: error in fragment shader: " + << m_objProgram->log(); + } } m_objProgram->bindAttributeLocation("vertex", 0); @@ -100,6 +146,16 @@ void GLShaderTVArray::initializeGL(int intCols, int intRows) m_objProgram->bind(); m_objProgram->setUniformValue(m_matrixLoc, objQMatrix); m_objProgram->setUniformValue(m_textureLoc, 0); + if (m_vao) + { + m_verticesBuf = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + m_verticesBuf->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_verticesBuf->create(); + m_textureCoordsBuf = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + m_textureCoordsBuf->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_textureCoordsBuf->create(); + m_vao->release(); + } m_objProgram->release(); } @@ -232,17 +288,41 @@ void GLShaderTVArray::RenderPixels(unsigned char *chrData) ptrF->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_intCols, m_intRows, GL_RGBA, GL_UNSIGNED_BYTE, m_objImage->bits()); - ptrF->glEnableVertexAttribArray(0); // vertex - ptrF->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, arrVertices); + if (m_vao) + { + m_vao->bind(); - ptrF->glEnableVertexAttribArray(1); // texture coordinates - ptrF->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, arrTextureCoords); + m_verticesBuf->bind(); + m_verticesBuf->allocate(arrVertices, intNbVertices * 2 * sizeof(GL_FLOAT)); + m_objProgram->enableAttributeArray(0); + m_objProgram->setAttributeBuffer(0, GL_FLOAT, 0, 2); + + m_textureCoordsBuf->bind(); + m_textureCoordsBuf->allocate(arrTextureCoords, intNbVertices * 2 * sizeof(GL_FLOAT)); + m_objProgram->enableAttributeArray(1); + m_objProgram->setAttributeBuffer(1, GL_FLOAT, 0, 2); + } + else + { + ptrF->glEnableVertexAttribArray(0); // vertex + ptrF->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, arrVertices); + + ptrF->glEnableVertexAttribArray(1); // texture coordinates + ptrF->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, arrTextureCoords); + } ptrF->glDrawArrays(GL_TRIANGLES, 0, intNbVertices); //cleanup - ptrF->glDisableVertexAttribArray(0); - ptrF->glDisableVertexAttribArray(1); + if (m_vao) + { + m_vao->release(); + } + else + { + ptrF->glDisableVertexAttribArray(0); + ptrF->glDisableVertexAttribArray(1); + } //*********************// @@ -294,6 +374,13 @@ void GLShaderTVArray::cleanup() delete m_objImage; m_objImage = nullptr; } + + delete m_verticesBuf; + m_verticesBuf = nullptr; + delete m_textureCoordsBuf; + m_textureCoordsBuf = nullptr; + delete m_vao; + m_vao = nullptr; } bool GLShaderTVArray::SelectRow(int intLine) diff --git a/sdrgui/gui/glshadertvarray.h b/sdrgui/gui/glshadertvarray.h index 4a2ce35f5..200105ad8 100644 --- a/sdrgui/gui/glshadertvarray.h +++ b/sdrgui/gui/glshadertvarray.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -45,7 +47,7 @@ public: void setColor(bool blnColor) { m_blnColor = blnColor; } void setAlphaBlend(bool blnAlphaBlend) { m_blnAlphaBlend = blnAlphaBlend; } void setAlphaReset() { m_blnAlphaReset = true; } - void initializeGL(int intCols, int intRows); + void initializeGL(int majorVersion, int minorVersion, int intCols, int intRows); void cleanup(); QRgb *GetRowBuffer(int intRow); void RenderPixels(unsigned char *chrData); @@ -57,10 +59,15 @@ public: protected: QOpenGLShaderProgram *m_objProgram; + QOpenGLVertexArrayObject *m_vao; + QOpenGLBuffer *m_verticesBuf; + QOpenGLBuffer *m_textureCoordsBuf; int m_matrixLoc; int m_textureLoc; //int m_objColorLoc; + static const QString m_strVertexShaderSourceArray2; static const QString m_strVertexShaderSourceArray; + static const QString m_strFragmentShaderSourceColored2; static const QString m_strFragmentShaderSourceColored; QImage *m_objImage; diff --git a/sdrgui/gui/tvscreen.cpp b/sdrgui/gui/tvscreen.cpp index ad49c773d..5227478e9 100644 --- a/sdrgui/gui/tvscreen.cpp +++ b/sdrgui/gui/tvscreen.cpp @@ -178,7 +178,13 @@ void TVScreen::paintGL() if ((m_askedCols != 0) && (m_askedRows != 0)) { - m_glShaderArray.initializeGL(m_askedCols, m_askedRows); + int major = 0, minor = 0; + if (QOpenGLContext::currentContext()) + { + major = QOpenGLContext::currentContext()->format().majorVersion(); + minor = QOpenGLContext::currentContext()->format().minorVersion(); + } + m_glShaderArray.initializeGL(major, minor, m_askedCols, m_askedRows); m_askedCols = 0; m_askedRows = 0; } diff --git a/sdrgui/gui/tvscreenanalog.cpp b/sdrgui/gui/tvscreenanalog.cpp index 28c2d9506..130fe9c1c 100644 --- a/sdrgui/gui/tvscreenanalog.cpp +++ b/sdrgui/gui/tvscreenanalog.cpp @@ -21,52 +21,101 @@ #include "tvscreenanalog.h" +static const char* vertexShaderSource2 = + "attribute highp vec4 vertex;\n" + "attribute highp vec2 texCoord;\n" + "varying highp vec2 texCoordVar;\n" + "void main() {\n" + " gl_Position = vertex;\n" + " texCoordVar = texCoord;\n" + "}\n"; + static const char* vertexShaderSource = -"attribute highp vec4 vertex;\n" -"attribute highp vec2 texCoord;\n" -"varying highp vec2 texCoordVar;\n" -"void main() {\n" -" gl_Position = vertex;\n" -" texCoordVar = texCoord;\n" -"}\n"; + "#version 330\n" + "in highp vec4 vertex;\n" + "in highp vec2 texCoord;\n" + "out highp vec2 texCoordVar;\n" + "void main() {\n" + " gl_Position = vertex;\n" + " texCoordVar = texCoord;\n" + "}\n"; + +static const char* fragmentShaderSource2 = + "uniform highp sampler2D tex1;\n" + "uniform highp sampler2D tex2;\n" + "uniform highp float imw;\n" + "uniform highp float imh;\n" + "uniform highp float tlw;\n" + "uniform highp float tlh;\n" + "varying highp vec2 texCoordVar;\n" + "void main() {\n" + " float tlhw = 0.5 * tlw;" + " float tlhh = 0.5 * tlh;" + " float tys = (texCoordVar.y + tlhh) * imh;\n" + " float p1y = floor(tys) * tlh - tlhh;\n" + " float p3y = p1y + tlh;\n" + " float tshift1 = texture2D(tex2, vec2(0.0, p1y)).r;\n" + " float tshift3 = texture2D(tex2, vec2(0.0, p3y)).r;\n" + " float shift1 = (1.0 - tshift1 * 2.0) * tlw;\n" + " float shift3 = (1.0 - tshift3 * 2.0) * tlw;\n" + " float txs1 = (texCoordVar.x + shift1 + tlhw) * imw;\n" + " float txs3 = (texCoordVar.x + shift3 + tlhw) * imw;\n" + " float p1x = floor(txs1) * tlw - tlhw;\n" + " float p3x = floor(txs3) * tlw - tlhw;\n" + " float p2x = p1x + tlw;\n" + " float p4x = p3x + tlw;\n" + " float p1 = texture2D(tex1, vec2(p1x, p1y)).r;\n" + " float p2 = texture2D(tex1, vec2(p2x, p1y)).r;\n" + " float p3 = texture2D(tex1, vec2(p3x, p3y)).r;\n" + " float p4 = texture2D(tex1, vec2(p4x, p3y)).r;\n" + " float p12 = mix(p1, p2, fract(txs1));\n" + " float p34 = mix(p3, p4, fract(txs3));\n" + " float p = mix(p12, p34, fract(tys));\n" + " gl_FragColor = vec4(p);\n" + "}\n"; static const char* fragmentShaderSource = -"uniform highp sampler2D tex1;\n" -"uniform highp sampler2D tex2;\n" -"uniform highp float imw;\n" -"uniform highp float imh;\n" -"uniform highp float tlw;\n" -"uniform highp float tlh;\n" -"varying highp vec2 texCoordVar;\n" -"void main() {\n" -" float tlhw = 0.5 * tlw;" -" float tlhh = 0.5 * tlh;" -" float tys = (texCoordVar.y + tlhh) * imh;\n" -" float p1y = floor(tys) * tlh - tlhh;\n" -" float p3y = p1y + tlh;\n" -" float tshift1 = texture2D(tex2, vec2(0.0, p1y)).r;\n" -" float tshift3 = texture2D(tex2, vec2(0.0, p3y)).r;\n" -" float shift1 = (1.0 - tshift1 * 2.0) * tlw;\n" -" float shift3 = (1.0 - tshift3 * 2.0) * tlw;\n" -" float txs1 = (texCoordVar.x + shift1 + tlhw) * imw;\n" -" float txs3 = (texCoordVar.x + shift3 + tlhw) * imw;\n" -" float p1x = floor(txs1) * tlw - tlhw;\n" -" float p3x = floor(txs3) * tlw - tlhw;\n" -" float p2x = p1x + tlw;\n" -" float p4x = p3x + tlw;\n" -" float p1 = texture2D(tex1, vec2(p1x, p1y)).r;\n" -" float p2 = texture2D(tex1, vec2(p2x, p1y)).r;\n" -" float p3 = texture2D(tex1, vec2(p3x, p3y)).r;\n" -" float p4 = texture2D(tex1, vec2(p4x, p3y)).r;\n" -" float p12 = mix(p1, p2, fract(txs1));\n" -" float p34 = mix(p3, p4, fract(txs3));\n" -" float p = mix(p12, p34, fract(tys));\n" -" gl_FragColor = vec4(p);\n" -"}\n"; + "#version 330\n" + "uniform highp sampler2D tex1;\n" + "uniform highp sampler2D tex2;\n" + "uniform highp float imw;\n" + "uniform highp float imh;\n" + "uniform highp float tlw;\n" + "uniform highp float tlh;\n" + "in highp vec2 texCoordVar;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " float tlhw = 0.5 * tlw;" + " float tlhh = 0.5 * tlh;" + " float tys = (texCoordVar.y + tlhh) * imh;\n" + " float p1y = floor(tys) * tlh - tlhh;\n" + " float p3y = p1y + tlh;\n" + " float tshift1 = texture2D(tex2, vec2(0.0, p1y)).r;\n" + " float tshift3 = texture2D(tex2, vec2(0.0, p3y)).r;\n" + " float shift1 = (1.0 - tshift1 * 2.0) * tlw;\n" + " float shift3 = (1.0 - tshift3 * 2.0) * tlw;\n" + " float txs1 = (texCoordVar.x + shift1 + tlhw) * imw;\n" + " float txs3 = (texCoordVar.x + shift3 + tlhw) * imw;\n" + " float p1x = floor(txs1) * tlw - tlhw;\n" + " float p3x = floor(txs3) * tlw - tlhw;\n" + " float p2x = p1x + tlw;\n" + " float p4x = p3x + tlw;\n" + " float p1 = texture(tex1, vec2(p1x, p1y)).r;\n" + " float p2 = texture(tex1, vec2(p2x, p1y)).r;\n" + " float p3 = texture(tex1, vec2(p3x, p3y)).r;\n" + " float p4 = texture(tex1, vec2(p4x, p3y)).r;\n" + " float p12 = mix(p1, p2, fract(txs1));\n" + " float p34 = mix(p3, p4, fract(txs3));\n" + " float p = mix(p12, p34, fract(tys));\n" + " fragColor = vec4(p);\n" + "}\n"; TVScreenAnalog::TVScreenAnalog(QWidget *parent) : QOpenGLWidget(parent), m_shader(nullptr), + m_vao(nullptr), + m_verticesBuf(nullptr), + m_textureCoordsBuf(nullptr), m_imageTexture(nullptr), m_lineShiftsTexture(nullptr) { @@ -107,7 +156,14 @@ void TVScreenAnalog::cleanup() delete m_lineShiftsTexture; m_lineShiftsTexture = nullptr; } -} + + delete m_verticesBuf; + m_verticesBuf = nullptr; + delete m_textureCoordsBuf; + m_textureCoordsBuf = nullptr; + delete m_vao; + m_vao = nullptr; + } TVScreenAnalogBuffer *TVScreenAnalog::getBackBuffer() { @@ -147,21 +203,52 @@ void TVScreenAnalog::initializeGL() m_shader = new QOpenGLShaderProgram(this); - if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) - { - qWarning() - << "TVScreenAnalog::initializeGL: error in vertex shader:" - << m_shader->log(); - return; - } + int majorVersion = 0, minorVersion = 0; + if (QOpenGLContext::currentContext()) + { + majorVersion = QOpenGLContext::currentContext()->format().majorVersion(); + minorVersion = QOpenGLContext::currentContext()->format().minorVersion(); + } + if ((majorVersion > 3) || ((majorVersion == 3) && (minorVersion >= 3))) + { + if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) + { + qWarning() + << "TVScreenAnalog::initializeGL: error in vertex shader:" + << m_shader->log(); + return; + } - if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource)) - { - qWarning() - << "TVScreenAnalog::initializeGL: error in fragment shader:" - << m_shader->log(); - return; - } + if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource)) + { + qWarning() + << "TVScreenAnalog::initializeGL: error in fragment shader:" + << m_shader->log(); + return; + } + + m_vao = new QOpenGLVertexArrayObject(); + m_vao->create(); + m_vao->bind(); + } + else + { + if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource2)) + { + qWarning() + << "TVScreenAnalog::initializeGL: error in vertex shader:" + << m_shader->log(); + return; + } + + if (!m_shader->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource2)) + { + qWarning() + << "TVScreenAnalog::initializeGL: error in fragment shader:" + << m_shader->log(); + return; + } + } if (!m_shader->link()) { @@ -179,6 +266,16 @@ void TVScreenAnalog::initializeGL() m_imageHeightLoc = m_shader->uniformLocation("imh"); m_texelWidthLoc = m_shader->uniformLocation("tlw"); m_texelHeightLoc = m_shader->uniformLocation("tlh"); + if (m_vao) + { + m_verticesBuf = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + m_verticesBuf->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_verticesBuf->create(); + m_textureCoordsBuf = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); + m_textureCoordsBuf->setUsagePattern(QOpenGLBuffer::DynamicDraw); + m_textureCoordsBuf->create(); + m_vao->release(); + } } void TVScreenAnalog::initializeTextures(TVScreenAnalogBuffer *buffer) @@ -280,13 +377,40 @@ void TVScreenAnalog::paintGL() 1.0f, 1.0f }; - glVertexAttribPointer(m_vertexAttribIndex, 2, GL_FLOAT, GL_FALSE, 0, vertices); - glEnableVertexAttribArray(m_vertexAttribIndex); - glVertexAttribPointer(m_texCoordAttribIndex, 2, GL_FLOAT, GL_FALSE, 0, arrTextureCoords); - glEnableVertexAttribArray(m_texCoordAttribIndex); + if (m_vao) + { + m_vao->bind(); + + m_verticesBuf->bind(); + m_verticesBuf->allocate(vertices, 4 * 2 * sizeof(GL_FLOAT)); + m_shader->enableAttributeArray(m_vertexAttribIndex); + m_shader->setAttributeBuffer(m_vertexAttribIndex, GL_FLOAT, 0, 2); + + // As these coords are constant, this could be moved into the init method + m_textureCoordsBuf->bind(); + m_textureCoordsBuf->allocate(arrTextureCoords, 4 * 2 * sizeof(GL_FLOAT)); + m_shader->enableAttributeArray(m_texCoordAttribIndex); + m_shader->setAttributeBuffer(m_texCoordAttribIndex, GL_FLOAT, 0, 2); + } + else + { + glVertexAttribPointer(m_vertexAttribIndex, 2, GL_FLOAT, GL_FALSE, 0, vertices); + glEnableVertexAttribArray(m_vertexAttribIndex); + glVertexAttribPointer(m_texCoordAttribIndex, 2, GL_FLOAT, GL_FALSE, 0, arrTextureCoords); + glEnableVertexAttribArray(m_texCoordAttribIndex); + } + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(m_vertexAttribIndex); - glDisableVertexAttribArray(m_texCoordAttribIndex); + + if (m_vao) + { + m_vao->release(); + } + else + { + glDisableVertexAttribArray(m_vertexAttribIndex); + glDisableVertexAttribArray(m_texCoordAttribIndex); + } m_shader->release(); } diff --git a/sdrgui/gui/tvscreenanalog.h b/sdrgui/gui/tvscreenanalog.h index 3d1f6a2c3..fd78688d5 100644 --- a/sdrgui/gui/tvscreenanalog.h +++ b/sdrgui/gui/tvscreenanalog.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include class TVScreenAnalogBuffer { @@ -130,6 +132,9 @@ class SDRGUI_API TVScreenAnalog : public QOpenGLWidget, protected QOpenGLFunctio TVScreenAnalogBuffer *m_backBuffer; QOpenGLShaderProgram *m_shader; + QOpenGLVertexArrayObject *m_vao; + QOpenGLBuffer *m_verticesBuf; + QOpenGLBuffer *m_textureCoordsBuf; QOpenGLTexture *m_imageTexture; QOpenGLTexture *m_lineShiftsTexture;