I can't figure it out how to properly write and read from a QOpenGLBuffer:: PixelUnpackBuffer
.
- What is the proper setup before writing into a PBO?
QOpenGLBuffer::write
will not work using with a simpleQImage.bits()
, orglReadPixels()
to pass the FBO render into the PBO. It has to be a specific type of data?- How do you use a written PBO with
Texture::setData()
? A simpleTexture.setData(*format*, *pixel_type*, pubo, nullptr)
will suffice?
Here some code to exemplify what I'm doing:
QImage ScribbleArea::proImg(const QImage& image,
const QImage& tip,
const QString& vertexPosVar,
const QString& textureCoordVar){
QOpenGLContext context;
QOffscreenSurface offSurface;
offSurface.setFormat(context.format());
offSurface.create();
// I'm sharing the context to show the offscreen Render into a
// QOpenGLTextureBlitter under PaintGL()
context.setShareContext(ScribbleArea::context());
context.create();
context.makeCurrent(&offSurface);
m_fbo = new QOpenGLFramebufferObject(image.size());
m_fbo->bind();
context.functions()->glViewport(0, 0, image.width(), image.height());
QOpenGLShaderProgram program(&context);
program.addShaderFromSourceFile(QOpenGLShader::Vertex, "path to vertex shader");
program.addShaderFromSourceFile(QOpenGLShader::Fragment, "path to fragment shader");
program.link();
program.bind();
// The next block is basically what I understood how to setup a PBO using
// Qt's OpenGL wrapper.
QOpenGLBuffer *pubo = new QOpenGLBuffer(QOpenGLBuffer::PixelUnpackBuffer);
pubo->setUsagePattern(QOpenGLBuffer::DynamicCopy);
pubo->create();
pubo->bind();
pubo->map(QOpenGLBuffer::ReadWrite);
pubo->allocate(image.bits(),image.sizeInBytes());
pubo->write(0,image.bits(),image.sizeInBytes());
pubo->unmap();
pubo->release();
// Testing how to use texture::setData() using straight bytes instead of the
// baked method of setData(QImage).
// I believe this is how to use the PBO's content to set the texture using QOpenGL.
QOpenGLTexture textu(QOpenGLTexture::Target2D);
textu.setSize(image.width(),image.height());
textu.setFormat(QOpenGLTexture::RGBA8_UNorm);
textu.allocateStorage();
textu.setData(QOpenGLTexture::BGRA,QOpenGLTexture::UInt8,image.bits(),nullptr);
// The texture bellow is a test to see if I was able to set up two textures and
// change which one the shader should use.
QOpenGLTexture brush(QOpenGLTexture::Target2D);
brush.setData(tip);
// Using native OpenGL snippets never work. The texture remain black.
// GLuint tex;
// glGenTextures(1, &tex);
// glBindTexture(GL_TEXTURE_2D, tex);
// glTexImage2D(GL_TEXTURE_2D, 0, 3, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glBindTexture( GL_TEXTURE_2D, 0);
GLint brTip = 1;
brush.bind(brTip);
GLint oriTxt = 0;
textu.bind(oriTxt);
//Rest of the code. Following Amin Ahmadi tutorial.
You have some misunderstandings, and most of these are not related to Qt's abstraction classes, but to how these objects work in the GL itself:
So far, so good...
Now you try to map the buffer to memory. THis can't work, because the buffer object does not have any storage allocated to it, so this call should fail with a GL error. Furthermore,
map
will return the memory address to where the memory would have been mapped, which you never care about here, so even if the mapping would work, you could not use it. Even worse, while a buffer is mapped, you must not do any GL operations with it (unless you create a persistent mapping).OK, now you create some storage. But only because the mapping operation failed earlier.
This also should work. Also only because you don't have a memory mapping active here.
This will fail because the buffer isn't mapped. But doesn't matter. You never needed nor intended to use the buffer mapping anyway.
Create the buffer object, and allocate (enough) storage for it.
No idea what you're talking about. Writing the data from an
QImage
to it will work. What you mean byglReadPixels
here is unclear. If you want to read pixels into a buffer object, you need to bind it asGL_PIXEL_PACK_BUFFER
, not_UNPACK_BUFFER
.Why do you say "it doesn't work"?
The is no overload of
QOpenGLTexture::setData()
that I'm aware of (i.e. can find in the docs) which would ever take anyQtOpenGLBuffer
parameter.In OpenGL, when a
GL_PIXEL_UNPACK_BUFFER
is bound, thedata
pointer ofglTexImage...()
functions will be treated as byte offset into that buffer object. Hence, you just need to bind yourpobo
, and callsetData
with the proper values, but you never passpobo
as a parameter tosetData
obviously.Btw., those Qt OpenGL abstractions are creating more issues than they are solving (for example,
QtOpenGLBuffer
abstraction makes it seem like GL buffer objects were typed, which is completely wrong - the same buffer object can be bound to multiple binding targets simultaneously). However, no matter what your opinion on those abstractions is, they in no way spare you from learning how the actual underlying GL objects are working - actually, with them you have to learn both the GL and Qt's sometimes quite arbitrary semantics of the abstractions of those.