Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: How to read pixels asynchronously using OpenGL & PBO  (Read 1530 times)

0 Members and 1 Guest are viewing this topic.

karagal

  • Newbie
  • *
  • Posts: 3
    • View Profile
How to read pixels asynchronously using OpenGL & PBO
« on: January 31, 2022, 07:31:28 pm »
Hello!

I am drawing to a sf::RenderTexture and need to get the drawn image at each frame into an array.
Something like this but faster:

renderTexture.getTexture().copyToImage().getPixelsPtr();

I encountered Pixel Buffer Objects (PBOs) that would allow me to do this by copying from framebuffer to PBO asynchronously and alternating between two PBOs (ie i'd get the pixels with a 1 frame delay). However I'm not familiar with these and my current implementation is not working.

Here is what I am currently doing from what I've found so far:

initialization
GLuint pbo[2];
int index = 0;
int nextIndex = 1;

then at every frame
// several calls to renderTexture.draw(...);

index = (index + 1) % 2;
nextIndex = (nextIndex + 1) % 2;

glReadBuffer(GL_FRONT); // set target framebuffer to read

// read pixels from framebuffer to PBO asynchronously
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[index]);
glReadPixels(0, 0, textureWidth, textureHeight, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);

// now read other PBO which should be already in CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo[nextIndex]);
unsigned char* ptr = (unsigned char*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);

if (ptr)
{    
    pixels_vector.assign(ptr, ptr + textureWidth * textureHeight * 4);
    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}

// back to conventional pixel operation
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

 Currenty my code never enters the condition, meaning nothing is drawn to the buffer. I tried doing

glBindTexture(GL_TEXTURE_2D, renderTexture.getTexture().getNativeHandle());


but I feel like I'm missing something, everything doesn't seem to be bound together correctly. In particular I can't figure out how to make it so that GL_FRONT is linked to the texture I'm drawing to. If I could get help or pointers that would be very appreciated, as I haven't yet found an answer to that online and I'm not sure where to look anymore.

Thanks a lot!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11035
    • View Profile
    • development blog
    • Email
Re: How to read pixels asynchronously using OpenGL & PBO
« Reply #1 on: March 08, 2022, 02:10:48 pm »
I'm not a 100% certain, but you might be able to make use of the sf::Texture::bind() function, so you can remove some of the custom OpenGL code, other than that, I have no knowledge about PBOs.

Depending on what you're doing, I recommend to either move the pixel manipulation into a shader, which can be executed directly on the GPU with the texture.
Or to use a recording software like OBS to capture individual frames. They have great and quite stable low-level hooks.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/