Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using QOpenGLTexture without QImage



  • Hi!

    I'm developing an application that (for the moment) has to use 128-bit textures to store boolean values (it's an extreme waste of bandwidth, it will later be a single 8-byte Alpha channel, might even be bitcoded, once the external bug is fixed, which may take months). The sample app will be a Conways Game of Life and I wanted to draw black-white cells using the Alpha channel of all white pixels in the entire window.

    I have already seen in the commented parts of the fragment shader, that if I color the quad with the UV coordinates, it is the exact red-green-black-yellow gradient I'd expect. reading the sampler however does not work. However, no matter what I seem to do, the resulting texture read seems to be zeroes all around and I don't know why. Most likely I bind my sampler wrong, but I can't seem to figure out how to do it properly. All the examples around load some data from an image, but my data format currently differs from anything QImage supports.

    No matter if I do random numbers in the texture or fill it with red or any other color, it doesn't display.

    This is my init:

    // Override unimplemented InteropWindow function
    void Conway::initializeGL()
    {
        qDebug("Conway: Entering initializeGL");
        std::unique_ptr<QOpenGLDebugLogger> log(new QOpenGLDebugLogger(this));
        if (!log->initialize()) qWarning("Conway: QDebugLogger failed to initialize");
    
        // Initialize OpenGL resources
        vs = std::make_unique<QOpenGLShader>(QOpenGLShader::Vertex, this);
        fs = std::make_unique<QOpenGLShader>(QOpenGLShader::Fragment, this);
        sp = std::make_unique<QOpenGLShaderProgram>(this);
        vbo = std::make_unique<QOpenGLBuffer>(QOpenGLBuffer::VertexBuffer);
        vao = std::make_unique<QOpenGLVertexArrayObject>(this);
        texs = { std::make_unique<QOpenGLTexture>(QOpenGLTexture::Target::TargetRectangle),
                 std::make_unique<QOpenGLTexture>(QOpenGLTexture::Target::TargetRectangle) };
    
        // Initialize frame buffer
        glFuncs->glViewport(0, 0, width(), height());   checkGLerror();
        glFuncs->glClearColor(0.0, 0.0, 0.0, 1.0);      checkGLerror();
        glFuncs->glDisable(GL_DEPTH_TEST);              checkGLerror();
        glFuncs->glDisable(GL_CULL_FACE);               checkGLerror();
    
        // Create shaders
        qDebug("Conway: Building shaders...");
        if (!vs->compileSourceFile( (shader_location + "/Vertex.glsl").c_str())) qWarning("%s", vs->log().data());
        if (!fs->compileSourceFile( (shader_location + "/Fragment.glsl").c_str())) qWarning("%s", fs->log().data());
        qDebug("Conway: Done building shaders");
    
        // Create and link shaderprogram
        qDebug("Conway: Linking shaders...");
        if (!sp->addShader(vs.get())) qWarning("Conway: Could not add vertex shader to shader program");
        if (!sp->addShader(fs.get())) qWarning("Conway: Could not add fragment shader to shader program");
        if (!sp->link()) qWarning("%s", sp->log().data());
        qDebug("Conway: Done linking shaders");
    
        // Init device memory
        qDebug("Conway: Initializing OpenGL buffers...");
    
        std::vector<float> quad =
            //  vertices  , tex coords
            //  x  ,   y  ,  u  ,   v
            { -1.0f, -1.0f, 0.0f, 0.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 };
    
        if (!vbo->create()) qWarning("Conway: Could not create VBO");
        if (!vbo->bind()) qWarning("Conway: Could not bind VBO");
        vbo->setUsagePattern(QOpenGLBuffer::StaticDraw);                checkGLerror();
        vbo->allocate(quad.data(), (int)quad.size() * sizeof(float));   checkGLerror();
        vbo->release();
    
        qDebug("Conway: Done initializing OpenGL buffers");
    
        // Setup VAO for the VBO
        if (!vao->create()) qWarning("Conway: Could not create VAO");
    
        vao->bind();
        {
            if (!vbo->bind()) qWarning("Conway: Could not bind VBO");
    
            // Setup shader attributes (can only be done when a VBO is bound, VAO does not store shader state
            if (!sp->bind()) qWarning("Conway: Failed to bind shaderprogram");
            sp->enableAttributeArray(0);  checkGLerror();
            sp->enableAttributeArray(1);  checkGLerror();
            sp->setAttributeArray(0, GL_FLOAT, (GLvoid *)(NULL), 2, sizeof(cl::sycl::float4));                      checkGLerror();
            sp->setAttributeArray(1, GL_FLOAT, (GLvoid *)(NULL + 2 * sizeof(float)), 2, sizeof(cl::sycl::float4));  checkGLerror();
            sp->release();
        }
        vao->release();
    
        std::vector<std::array<std::uint32_t, 4>> texels;
        std::generate_n(std::back_inserter(texels),
                        width() * height(),
                        [prng = std::default_random_engine{},
                         dist = std::uniform_int_distribution<std::uint32_t>{ 0, 1 }]() mutable
        {
            return std::array<std::uint32_t, 4>{ 1, 1, 1, dist(prng) };
        });
    
        // Quote from the QOpenGLTexture documentation of Qt 5.12
        //
        // The typical usage pattern for QOpenGLTexture is:
        //  -  Instantiate the object specifying the texture target type
        //  -  Set properties that affect the storage requirements e.g.storage format, dimensions
        //  -  Allocate the server - side storage
        //  -  Optionally upload pixel data
        //  -  Optionally set any additional properties e.g.filtering and border options
        //  -  Render with texture or render to texture
    
        for (auto& tex : texs)
        {
            tex->setSize(width(), height());
            tex->setFormat(QOpenGLTexture::TextureFormat::RGBA32U);
            tex->allocateStorage(QOpenGLTexture::PixelFormat::RGBA_Integer, QOpenGLTexture::PixelType::UInt32);
            tex->setData(QOpenGLTexture::PixelFormat::RGBA_Integer, QOpenGLTexture::PixelType::UInt32, texels.data());
            tex->setMinificationFilter(QOpenGLTexture::Filter::Nearest);
            tex->setMagnificationFilter(QOpenGLTexture::Filter::Nearest);
            tex->setWrapMode(QOpenGLTexture::WrapMode::Repeat);
            tex->setMipMaxLevel(0);
        }
    
        for (const QOpenGLDebugMessage& message : log->loggedMessages()) qDebug() << message << "\n";
    
         qDebug("Conway: Leaving initializeGL");
    }
    

    I have two textures, because I will need double buffering to step the lattice. The textures will be updated via OpenCL-OpenGL interop. Uploading the data makes the assumption that reinterpet_casting the std::vector<std::array<std::uint32_t, 4>>::data() pointer through the void* taken by the API will actually be 32-bit RGBA values packed tightly together.

    My rendering looks like:

    // Override unimplemented InteropWindow function
    void Conway::render()
    {
        std::unique_ptr<QOpenGLDebugLogger> log(new QOpenGLDebugLogger(this));
        if (!log->initialize()) qWarning("Conway: QDebugLogger failed to initialize");
    
        // Update matrices as needed
        if(needMatrixReset) setMatrices();
    
        // Clear Frame Buffer and Z-Buffer
        glFuncs->glClear(GL_COLOR_BUFFER_BIT); checkGLerror();
    
        // Draw
        if(!sp->bind()) qWarning("QGripper: Failed to bind shaderprogram");
        vao->bind(); checkGLerror();
    
        //glFuncs->glActiveTexture(GL_TEXTURE0);
        //texs[Buffer::Front]->bind();
        sp->setUniformValue("texsampler", texs[Buffer::Front]->textureId());
    
        glFuncs->glDrawArrays(GL_TRIANGLE_STRIP, 0, static_cast<GLsizei>(4)); checkGLerror();
    
        texs[Buffer::Front]->release();
        vao->release(); checkGLerror();
        sp->release(); checkGLerror();
    
        // Wait for all drawing commands to finish
        if (!cl_khr_gl_event_supported)
        {
            glFuncs->glFinish(); checkGLerror();
        }
        else
        {
            glFuncs->glFlush(); checkGLerror();
        }
        imageDrawn = true;
    
        for (const QOpenGLDebugMessage& message : log->loggedMessages()) qDebug() << message << "\n";
    }
    

    The shaders are simple.

    #version 330
    
    // VS locations
    #define POSITION    0
    #define TEXCOORD    1
    
    // FS locations
    #define COORDINATE 0
    
    layout(location = POSITION) in vec2 in_Position;
    layout(location = TEXCOORD) in vec2 in_TexCoord;
    
    out block
    {
        vec2 TexCoord;
    } VS_Out;
    
    uniform mat4 mat_MVP;
    
    void main()
    {
        gl_Position = mat_MVP * vec4(in_Position, 0.0, 1.0);
    
        VS_Out.TexCoord = in_TexCoord;
    }
    
    #version 330
    
    // VS locations
    #define POSITION    0
    #define TEXCOORD    1
    
    // FS locations
    #define COORDINATE 0
    
    in block
    {
        vec2 TexCoord;
    } FS_In;
    
    out vec4 FragColor;
    
    uniform sampler2D texsampler;
    
    void main()
    {
        //FragColor = vec4(FS_In.TexCoord, 0.0, 1.0);
        //FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        
        FragColor = texture(texsampler, FS_In.TexCoord);
    }
    
    

    I suppose it's only the QOpenGLTexture-Sampler binding I'm not doing right, though I might be making other mistakes as well. First time trying to use textures in OpenGL.


Log in to reply