haggi krey
haggi krey

Reputation: 1978

How can I solve GL_INVALID_OPERATION error with QOpenGLWidget?

I have a OpenGL 3d texture and a 2d texture which I want to combine in a fragment shader. The whole UI is done with a QOpenGLWidget which simplifies the workflow a lot. Now I have a problem. As soon as I try to do something like this:

vec4 col = texture(tex, uvCoord);
outColor = texture(lookUp, col.rgb);

In my fragment shader, I get an GL_INVALID_OPERATION error during drawing of the geometry. The error occurs in the method paintGL() as soon as the rectangle quad is drawn. If I do this in the fragment shader:

outColor = texture(lookUp, uvCoord);

I do not get the error and I see the expected color in the displayed window. I'd appreciate any hints where I can search for a solution.

#include "tex3dtest.h"


Tex3dtest::Tex3dtest(QWidget *parent)
    : QMainWindow(parent)
{
    setCentralWidget(new ImageGLWidget());
}

ImageGLWidget::ImageGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    texture = Q_NULLPTR;
    setFixedSize(512, 512);

    QSurfaceFormat format;
    format.setRenderableType(QSurfaceFormat::OpenGL);
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setVersion(3, 3);

    setFormat(format);
}

ImageGLWidget::~ImageGLWidget()
{}


const int LUT3D_EDGE_SIZE = 32;

void ImageGLWidget::printError(GLuint error)
{
    switch (error)
    {
    case GL_NO_ERROR:
        qDebug() << "NoError";
        break;
    case GL_INVALID_ENUM:
        qDebug() << "OpenGL ERROR: GL_INVALID_ENUM";
        break;
    case GL_INVALID_VALUE:
        qDebug() << "OpenGL ERROR: GL_INVALID_VALUE";
        break;
    case GL_INVALID_OPERATION:
        qDebug() << "OpenGL ERROR: GL_INVALID_OPERATION";
        break;
    case GL_STACK_OVERFLOW:
        qDebug() << "OpenGL ERROR: GL_STACK_OVERFLOW";
        break;
    case GL_STACK_UNDERFLOW:
        qDebug() << "OpenGL ERROR: GL_STACK_UNDERFLOW";
        break;
    case GL_OUT_OF_MEMORY:
        qDebug() << "OpenGL ERROR: GL_OUT_OF_MEMORY";
        break;
    }
}

void ImageGLWidget::createTexture()
{
    qDebug() << "ImageGLWidget::createTexture";
    GLenum err;
    int num3Dentries = 3 * LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
    textureContent.resize(num3Dentries);
    for (unsigned int i = 0; i < num3Dentries; i++)
        textureContent[i] = ((float)i)/num3Dentries * 100.0f;

    texture = new QOpenGLTexture(QOpenGLTexture::Target::Target3D);
    bool is3d = texture->hasFeature(QOpenGLTexture::Feature::Texture3D);
    texture->setFormat(QOpenGLTexture::TextureFormat::RGB32F);
    texture->setSize(LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE);
    texture->allocateStorage(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32);
    texture->setMagnificationFilter(QOpenGLTexture::Linear);
    texture->setMinificationFilter(QOpenGLTexture::Linear);
    texture->setWrapMode(QOpenGLTexture::ClampToEdge);
    texture->setData(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32, &textureContent[0]);

    int num2Dentries = 256 * 256 * 3;
    textureContent1.resize(num2Dentries);
    for (unsigned int i = 0; i < num2Dentries; i++)
        textureContent1[i] = ((float)rand())/RAND_MAX;

    texture1 = new QOpenGLTexture(QOpenGLTexture::Target::Target2D);
    texture1->setFormat(QOpenGLTexture::TextureFormat::RGB32F);
    texture1->setSize(256, 256, 0);
    texture1->allocateStorage(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32);
    texture1->setMagnificationFilter(QOpenGLTexture::Linear);
    texture1->setMinificationFilter(QOpenGLTexture::Linear);
    texture1->setWrapMode(QOpenGLTexture::ClampToEdge);
    texture1->setData(QOpenGLTexture::PixelFormat::RGB, QOpenGLTexture::PixelType::Float32, &textureContent1[0]);

}

static const float vertexData[] = {
    -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
    -1.0f,  1.0f, 0.0f, 0.0f, 1.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, 0.0f, 1.0f, 0.0f,
    -1.0f, -1.0f, 0.0f, 0.0f, 0.0f
};

static const char *vtxVBO =
"#version 330\n"
"layout(location = 0) in vec3 position;\n"
"layout(location = 1) in vec2 uv;\n"
"out vec2 uvCoord;\n"

"void main()\n"
"{\n"
"   gl_Position = vec4(position, 1.0);\n"
"   uvCoord = uv;\n"
"}\n";

static const char *frgVBO =
"#version 330\n"
"in vec2 uvCoord;\n"
"out vec4 outColor;\n"
"uniform sampler2D tex;\n"
"uniform sampler3D lookUp;\n"
"void main()\n"
"{\n"
"   vec4 col = texture(tex, uvCoord);\n"
"   outColor = texture(lookUp, col.rgb);\n"
"// outColor = texture(tex, uvCoord);\n"
"}\n";

void ImageGLWidget::initializeGL()
{
    GLenum err;
    qDebug() << "initializeGL";
    initializeOpenGLFunctions();

    createTexture();

    program = new QOpenGLShaderProgram();
    program->addShaderFromSourceCode(QOpenGLShader::Vertex, vtxVBO);
    program->addShaderFromSourceCode(QOpenGLShader::Fragment, frgVBO);
    program->link();
    program->bind();
    vertexbuffer.create();
    vertexbuffer.bind();
    vertexbuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
    vertexbuffer.allocate(vertexData, sizeof(float) * 6 * 5);

    vao.create();
    vao.bind();
    program->enableAttributeArray(0);
    program->enableAttributeArray(1);
    int stride = 5 * sizeof(float);
    int uvOffset = 3 * sizeof(float);
    program->setAttributeBuffer(0, GL_FLOAT, 0, 3, stride);
    program->setAttributeBuffer(1, GL_FLOAT, uvOffset, 2, stride);

    vao.release();
    vertexbuffer.release();
    program->release();
}

void ImageGLWidget::paintGL()
{
    qDebug() << "ImageGLWidget::paintGL";
    GLenum err;
    glClear(GL_COLOR_BUFFER_BIT);
    texture->bind();
    texture1->bind();
    program->bind();
    vao.bind();
    glDrawArrays(GL_TRIANGLES, 0, 6);
    vao.release();
    program->release();
}

Header file is this:

#pragma once

#include <QtWidgets/QMainWindow>
#include <qopenglwidget.h>
#include <qopenglfunctions.h>
#include <qopenglshaderprogram.h>
#include <qopengltexture.h>
#include <qopenglvertexarrayobject.h>
#include <qopenglbuffer.h>

class Tex3dtest : public QMainWindow
{
    Q_OBJECT

public:
    Tex3dtest(QWidget *parent = Q_NULLPTR);

private:
};


class ImageGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
    Q_OBJECT;
public:
    ImageGLWidget(QWidget* parent = Q_NULLPTR);
    ~ImageGLWidget();

    virtual void initializeGL();
    virtual void paintGL();
    void printError(GLuint error);
    void createTexture();

private:
    QOpenGLShaderProgram *program;
    QOpenGLTexture *texture;
    QOpenGLTexture *texture1;
    QOpenGLVertexArrayObject vao;
    QOpenGLBuffer vertexbuffer;
    std::vector<float> textureContent;
    std::vector<float> textureContent1;
};

Upvotes: 1

Views: 574

Answers (1)

haggi krey
haggi krey

Reputation: 1978

The problem could be solved by setting uniform values in the shader program. In initializeGL I add:

programOCIO->bind();
texture2DLoc = programOCIO->uniformLocation("tex");
texture3DLoc = programOCIO->uniformLocation("lookUp");

and later in the paintGL method I added:

glActiveTexture(GL_TEXTURE0);
texture->bind();
glActiveTexture(GL_TEXTURE1);
lut3dTex->bind();
programOCIO->setUniformValue(texture2DLoc, 0);
programOCIO->setUniformValue(texture3DLoc, 1);

What now works fine.

Upvotes: 2

Related Questions