0

I'm using opengl calls on Qt with c++, in order to display images to the screen. In order to get the image to the texture, I first read it as a QImage, and then use the following code to load to texture:

void imageDisplay::loadImage(const QImage &img){
    glEnable(GL_TEXTURE_2D); // Enable texturing
    glBindTexture(GL_TEXTURE_2D, texture); // Set as the current texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, img.width(),
                  img.height(),
                  0, GL_BGRA,      GL_UNSIGNED_BYTE, img.bits() );
    glFinish();
    glDisable(GL_TEXTURE_2D);
}

However, when profiling performance, I suspect this is not the most efficient way of doing this. Performance is critical for the application that I am developing, and I would really appreciate any suggestions on how to improve this part. (BTW - reading the image is done on a separate module than the one that is displaying it - is it possible to read and load to a texture, and then move the texture the displaying object?)

Thank you

JLev
  • 705
  • 1
  • 9
  • 30

3 Answers3

3

Kick that glFinish out, it decreases the performance heavily while you don't need it at all.

The Techel
  • 918
  • 8
  • 13
  • It depens if you need to synchronize the GPU with the CPU. – Zezura Mar 26 '17 at 16:06
  • 2
    Which is probably not the case here. – The Techel Mar 26 '17 at 16:07
  • 1
    There are proper ways to achieve synchronization. `glFinish` should never be used in new code. – peppe Mar 26 '17 at 19:32
  • Generally it's correct that glFinish() should be avoided in modern code, but it's not an absolute never. There are cases, such as VR rendering where timing needs to be more tightly controlled, where it is still useful. We currently use it to kick off the beginning of work on the next frame before vsync instead of after, thereby eliminating a bit of GPU bubble in some drivers. – Yasser Malaika Mar 31 '17 at 23:46
1

It's hard to say without looking at your profiling results, but a few things to try:

  1. You are sending your data via glTexImage2D() in GL_BGRA format and having the driver reformat. Does it work any faster when you pre-format the bits?: (would be surprising, but you never know what drivers do under the hood.)

    QImage imageUpload = imageOriginal.convertToFormat( QImage::Format_ARGB32 ).rgbSwapped(); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits() );

  2. Are you populating that QImage from a file on disk? How big is it? If the sheer volume of image data is the problem, and it's a static texture, you can try compressing the image to a DXT/St3 format offline and saving that for later. Then read and upload those bits at runtime instead. This will reduce the number of bytes being transferred to the GPU (and stored on GPU memory) to 1/6 or 1/4 the original. If you need to generate the QImage at runtime and can't precompress, then this will probably slow things down, so keep that in mind.

  3. Is the alpha combine important? i.e. if you remove glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); does it help? I wonder if that's causing some unwanted churn. I.e. it to be downloaded to host, modified, then sent back or something...

  4. I agree that you should remove the glFinish(); unless you have a VERY specific reason for it.

  5. How often are you needing to do this? every frame?

  • First of all, thanks! I'll try what you suggested in 1. Regarding 2 + 3 - sadly I can't change both - I receive the images during runtime, and alpha is important (if I remove this live, the image looks pale and not how it should be). Regarding 4 - you can see here where I started using it - http://stackoverflow.com/questions/41999427/display-image-with-qt-opengl-timing-accuracy-and-vsync-issues-c About 5 - I need to swap the image at some not pre-defined rate (1-10 Hz) – JLev Mar 29 '17 at 07:48
  • Ah, I see regarding 4. Yes, that makes sense in those types of timing sensitive cases. And I see that you are using a vsync context... Since that's the case, are you uploading those textures on the same thread as the one running the rendering loop? – Yasser Malaika Mar 31 '17 at 23:27
  • Loading is in the same thread, but it is always called right after rendering and always finished before rendering starts. – JLev Apr 02 '17 at 06:58
0

What about STB image loader: its raw pixel data in a buffer, it returns a char pointer to a byte buffer which you can use and release after its loaded in OpenGL.

int width, height comp;
unsigned char *data = stbi_load(filename, &width, &height, &comp, 4); // ask it to load 4 components since its rgba  // demo only

    glGenBuffers(1, &m_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
    glBufferData(GL_ARRAY_BUFFER, vertexByteSize), this->Vertices, GL_STATIC_DRAW);
    glGenTexture(...)
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D( ... );

    // you can generate mipmaps here

    // Important
    stbi_image_free(data);

You can find STB here: get the image load header: https://github.com/nothings/stb

Drawing with mipmaps using openGL improves performance. generate mipmaps after you have used glTexImage2D

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);

Good luck

Zezura
  • 128
  • 1
  • 9
  • How would that be faster than using a QImage and releasing that afterwards? – BDL Mar 26 '17 at 16:20
  • Its a very easy way to load all kinds of images and easy to use method certainly better than QImage for beginners, you also dont need Qt for it. – Zezura Mar 26 '17 at 16:23
  • 1
    Since op has a performance problem while **uploading** the data, I don't see how using a different file loading library would help. It looks as if you would make exactly the same OpenGL calls that are already in the question (although you left most of them away), so the performance will be the same. – BDL Mar 26 '17 at 16:29
  • I told a very important fact: use mipmapping which increases performance when filtering is used. – Zezura Mar 26 '17 at 16:30
  • That is true, but still doesn't address the question about optimizing the image uploading code. In fact, generating mipmaps will make the loading code in question slower while improving the rendering performance. – BDL Mar 26 '17 at 16:33