From 9e4409b0bbb5323bf4a825de5be3d7e8a3f5f2ff Mon Sep 17 00:00:00 2001 From: Ruslan Kabatsayev Date: Thu, 17 Oct 2024 02:22:25 +0400 Subject: [PATCH] Rewrite spheric mirror to make it more efficient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old version rewrote VBO about 150×3 times per frame, which is very inefficient, especially given that the data written never change. This version writes these constant data once in the constructor of the distorter and uses them on rendering. Fixes #3535 --- src/core/StelViewportEffect.cpp | 173 +++++++++++++++++++++++++++++--- src/core/StelViewportEffect.hpp | 24 +++++ 2 files changed, 181 insertions(+), 16 deletions(-) diff --git a/src/core/StelViewportEffect.cpp b/src/core/StelViewportEffect.cpp index 65335a3719a89..fca9cf876e981 100644 --- a/src/core/StelViewportEffect.cpp +++ b/src/core/StelViewportEffect.cpp @@ -31,6 +31,19 @@ #include #include +namespace +{ +constexpr int SPHERIC_MIRROR_COORDS_PER_VERTEX = 2; +constexpr int SPHERIC_MIRROR_COORDS_PER_COLOR = 4; +constexpr int SPHERIC_MIRROR_COORDS_PER_TEXCOORD = 2; +enum +{ + VERTEX_ATTRIB_INDEX, + COLOR_ATTRIB_INDEX, + TEXCOORD_ATTRIB_INDEX, +}; +} + void StelViewportEffect::paintViewportBuffer(const QOpenGLFramebufferObject* buf) const { StelPainter sPainter(StelApp::getInstance().getCore()->getProjection2d()); @@ -51,6 +64,8 @@ StelViewportDistorterFisheyeToSphericMirror::StelViewportDistorterFisheyeToSpher , screen_h(screen_h) , originalProjectorParams(StelApp::getInstance().getCore()->getCurrentStelProjectorParams()) , texture_point_array(Q_NULLPTR) + , vao(new QOpenGLVertexArrayObject) + , verticesVBO(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)) { QSettings& conf = *StelApp::getInstance().getSettings(); StelCore* core = StelApp::getInstance().getCore(); @@ -236,12 +251,132 @@ StelViewportDistorterFisheyeToSphericMirror::StelViewportDistorterFisheyeToSpher } } delete[] vertex_point_array; + + StelApp::getInstance().ensureGLContextCurrent(); + setupBuffers(); + setupShaders(); +} + +void StelViewportDistorterFisheyeToSphericMirror::setupShaders() +{ + QOpenGLShader vsh(QOpenGLShader::Vertex); + const auto vsrc = + StelOpenGL::globalShaderPrefix(StelOpenGL::VERTEX_SHADER) + + "ATTRIBUTE highp vec3 vertex;\n" + "ATTRIBUTE mediump vec2 texCoord;\n" + "ATTRIBUTE mediump vec4 color;\n" + "uniform mediump mat4 projectionMatrix;\n" + "VARYING mediump vec2 texc;\n" + "VARYING mediump vec4 outColor;\n" + "void main()\n" + "{\n" + " gl_Position = projectionMatrix * vec4(vertex, 1.);\n" + " texc = texCoord;\n" + " outColor = color;\n" + "}\n"; + vsh.compileSourceCode(vsrc); + if (!vsh.log().isEmpty()) + qWarning().noquote() << "StelViewportDistorterFisheyeToSphericMirror: Warnings while compiling vertex shader: " << vsh.log(); + + QOpenGLShader fsh(QOpenGLShader::Fragment); + const auto fsrc = + StelOpenGL::globalShaderPrefix(StelOpenGL::FRAGMENT_SHADER) + + "VARYING mediump vec2 texc;\n" + "VARYING mediump vec4 outColor;\n" + "uniform sampler2D tex;\n" + "void main()\n" + "{\n" + " FRAG_COLOR = texture2D(tex, texc)*outColor;\n" + "}\n"; + fsh.compileSourceCode(fsrc); + if (!fsh.log().isEmpty()) + qWarning().noquote() << "StelViewportDistorterFisheyeToSphericMirror: Warnings while compiling fragment shader: " << fsh.log(); + + shaderProgram.reset(new QOpenGLShaderProgram(QOpenGLContext::currentContext())); + shaderProgram->addShader(&vsh); + shaderProgram->addShader(&fsh); + shaderProgram->bindAttributeLocation("vertex", VERTEX_ATTRIB_INDEX); + shaderProgram->bindAttributeLocation("color", COLOR_ATTRIB_INDEX); + shaderProgram->bindAttributeLocation("texCoord", TEXCOORD_ATTRIB_INDEX); + StelPainter::linkProg(shaderProgram.get(), "spheric mirror distortion shader program"); + shaderVars.projectionMatrix = shaderProgram->uniformLocation("projectionMatrix"); + shaderVars.texture = shaderProgram->uniformLocation("tex"); +} + +void StelViewportDistorterFisheyeToSphericMirror::setupBuffers() +{ + verticesVBO->create(); + verticesVBO->setUsagePattern(QOpenGLBuffer::StaticDraw); + verticesVBO->bind(); + const int colorElemSize = SPHERIC_MIRROR_COORDS_PER_COLOR * sizeof(GLfloat); + const int vertElemSize = SPHERIC_MIRROR_COORDS_PER_VERTEX * sizeof(GLfloat); + const int texCoordElemSize = SPHERIC_MIRROR_COORDS_PER_TEXCOORD * sizeof(GLfloat); + const int numberOfVerticesToCopy = displayVertexList.size(); + const auto bufferSize = vertElemSize*numberOfVerticesToCopy + + texCoordElemSize*numberOfVerticesToCopy + + colorElemSize*numberOfVerticesToCopy; + verticesVBO->allocate(bufferSize); + vboVertexDataOffset = 0; + const auto vertexDataSize = vertElemSize*numberOfVerticesToCopy; + verticesVBO->write(vboVertexDataOffset, displayVertexList.constData(), vertexDataSize); + vboTexCoordDataOffset = vertexDataSize; + const auto texCoordDataSize = texCoordElemSize*numberOfVerticesToCopy; + verticesVBO->write(vboTexCoordDataOffset, displayTexCoordList.constData(), texCoordDataSize); + vboColorDataOffset = vertexDataSize + texCoordDataSize; + const auto colorDataSize = colorElemSize*numberOfVerticesToCopy; + verticesVBO->write(vboColorDataOffset, displayColorList.constData(), colorDataSize); + verticesVBO->release(); + + vao->create(); + bindVAO(); + setupCurrentVAO(); + releaseVAO(); +} + +void StelViewportDistorterFisheyeToSphericMirror::setupCurrentVAO() const +{ + auto& gl = *QOpenGLContext::currentContext()->functions(); + verticesVBO->bind(); + gl.glVertexAttribPointer(VERTEX_ATTRIB_INDEX, SPHERIC_MIRROR_COORDS_PER_VERTEX, GL_FLOAT, + false, 0, reinterpret_cast(vboVertexDataOffset)); + gl.glVertexAttribPointer(COLOR_ATTRIB_INDEX, SPHERIC_MIRROR_COORDS_PER_COLOR, GL_FLOAT, + false, 0, reinterpret_cast(vboColorDataOffset)); + gl.glVertexAttribPointer(TEXCOORD_ATTRIB_INDEX, SPHERIC_MIRROR_COORDS_PER_TEXCOORD, GL_FLOAT, + false, 0, reinterpret_cast(vboTexCoordDataOffset)); + verticesVBO->release(); + gl.glEnableVertexAttribArray(VERTEX_ATTRIB_INDEX); + gl.glEnableVertexAttribArray(COLOR_ATTRIB_INDEX); + gl.glEnableVertexAttribArray(TEXCOORD_ATTRIB_INDEX); } +void StelViewportDistorterFisheyeToSphericMirror::bindVAO() const +{ + if(vao->isCreated()) + vao->bind(); + else + setupCurrentVAO(); +} + +void StelViewportDistorterFisheyeToSphericMirror::releaseVAO() const +{ + if(vao->isCreated()) + { + vao->release(); + } + else + { + auto& gl = *QOpenGLContext::currentContext()->functions(); + gl.glDisableVertexAttribArray(VERTEX_ATTRIB_INDEX); + gl.glDisableVertexAttribArray(COLOR_ATTRIB_INDEX); + gl.glDisableVertexAttribArray(TEXCOORD_ATTRIB_INDEX); + } +} StelViewportDistorterFisheyeToSphericMirror::~StelViewportDistorterFisheyeToSphericMirror(void) { + StelApp::getInstance().ensureGLContextCurrent(); // Make sure that VBO & VAO will be properly deleted + if (texture_point_array) delete[] texture_point_array; StelApp::getInstance().getCore()->setCurrentStelProjectorParams(originalProjectorParams); @@ -323,24 +458,30 @@ void StelViewportDistorterFisheyeToSphericMirror::distortXY(qreal &x, qreal &y) void StelViewportDistorterFisheyeToSphericMirror::paintViewportBuffer(const QOpenGLFramebufferObject* buf) const { - StelPainter sPainter(StelApp::getInstance().getCore()->getProjection2d()); - QOpenGLFunctions* gl = sPainter.glFuncs(); - GL(gl->glActiveTexture(GL_TEXTURE0)); - GL(gl->glBindTexture(GL_TEXTURE_2D, buf->texture())); - GL(gl->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GL(gl->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - sPainter.setBlending(false); - - sPainter.enableClientStates(true, true, true); - sPainter.setColorPointer(4, GL_FLOAT, displayColorList.constData()); - sPainter.setVertexPointer(2, GL_FLOAT, displayVertexList.constData()); - sPainter.setTexCoordPointer(2, GL_FLOAT, displayTexCoordList.constData()); + const auto prj = StelApp::getInstance().getCore()->getProjection2d(); + auto& gl = *QOpenGLContext::currentContext()->functions(); + const int texUnit = 0; + GL(gl.glActiveTexture(GL_TEXTURE0 + texUnit)); + GL(gl.glBindTexture(GL_TEXTURE_2D, buf->texture())); + GL(gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL(gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + + shaderProgram->bind(); + const Mat4f& m = prj->getProjectionMatrix(); + const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]); + shaderProgram->setUniformValue(shaderVars.projectionMatrix, qMat); + shaderProgram->setUniformValue(shaderVars.texture, texUnit); + + bindVAO(); for (int j=0;jglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - GL(gl->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + releaseVAO(); + + shaderProgram->release(); + + GL(gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + GL(gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); } diff --git a/src/core/StelViewportEffect.hpp b/src/core/StelViewportEffect.hpp index eeb9858278d0b..771f239ee3004 100644 --- a/src/core/StelViewportEffect.hpp +++ b/src/core/StelViewportEffect.hpp @@ -20,8 +20,12 @@ #ifndef STELVIEWPORTEFFECT_HPP #define STELVIEWPORTEFFECT_HPP +#include #include "VecMath.hpp" #include "StelProjector.hpp" +#include +#include +#include class QOpenGLFramebufferObject; @@ -54,6 +58,14 @@ class StelViewportDistorterFisheyeToSphericMirror : public StelViewportEffect QString getName() const override {return "sphericMirrorDistorter";} void paintViewportBuffer(const QOpenGLFramebufferObject* buf) const override; void distortXY(qreal& x, qreal& y) const override; + +private: + void setupShaders(); + void setupBuffers(); + void bindVAO() const; + void releaseVAO() const; + void setupCurrentVAO() const; + private: const int screen_w; const int screen_h; @@ -68,6 +80,18 @@ class StelViewportDistorterFisheyeToSphericMirror : public StelViewportEffect QVector displayVertexList; QVector displayColorList; QVector displayTexCoordList; + std::unique_ptr vao; + std::unique_ptr verticesVBO; + std::unique_ptr shaderProgram; + int vboVertexDataOffset; + int vboTexCoordDataOffset; + int vboColorDataOffset; + struct ShaderVars + { + int projectionMatrix; + int texture; + }; + ShaderVars shaderVars; }; #endif // STELVIEWPORTEFFECT_HPP