Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vittorioromeo/3b3557d8e7d54ab64ee26843ccebbb44 to your computer and use it in GitHub Desktop.
Save vittorioromeo/3b3557d8e7d54ab64ee26843ccebbb44 to your computer and use it in GitHub Desktop.
int main()
{
//
//
// Setup globals and hidden shared OpenGL context (for resource sharing)
// (uses `SDL_GLContext` internally)
auto graphicsContext = sf::GraphicsContext::create().value();
sf::priv::GlContext& sharedCtxPtr = sf::WindowContext::getSharedGlContextPtr();
//
//
// Create window (uses `SDL_Window` and `SDL_GLContext` internally)
sf::RenderWindow window({.size = {256u, 256u}});
assert(window.setActive()); // calls `SDL_GL_MakeCurrent`
sf::priv::GlContext* windowCtxPtr = sf::WindowContext::getActiveThreadLocalGlContextPtr();
//
//
// Create OpenGL texture on the shared context, then revert to previous context and bind it
GLuint glTexture{};
assert(sharedCtxPtr.makeCurrent(true)); // calls `SDL_GL_MakeCurrent`
glCheck(glGenTextures(1, &glTexture));
assert(glTexture);
assert(windowCtxPtr->makeCurrent(true)); // calls `SDL_GL_MakeCurrent`
glCheck(glBindTexture(GL_TEXTURE_2D, glTexture));
glCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
//
//
// Set window context to active and calls `glClearColor` + `glClear`
window.clear(sf::Color::Red);
// Intentionally not calling `window.display()` to avoid `SDL_GL_SwapWindow` call
//
//
// Create destination framebuffer and bind the previously created texture to it
GLuint destFrameBuffer{};
glCheck(glGenFramebuffers(1, &destFrameBuffer));
assert(destFrameBuffer);
// Read from the window FBO, write to the texture FBO
glCheck(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0u /* default FBO */));
glCheck(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destFrameBuffer));
glCheck(glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture, 0));
assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
//
//
// This context switching should be idempotent, but commenting out `sharedCtxPtr.makeCurrent(true)` FIXES THE ISSUE
assert(sharedCtxPtr.makeCurrent(true)); // calls `SDL_GL_MakeCurrent`
assert(windowCtxPtr->makeCurrent(true)); // calls `SDL_GL_MakeCurrent`
//
//
// This query should be a noop, but commenting out `glGetIntegerv` FIXES THE ISSUE
GLint out{};
glCheck(glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &out));
// (!) EITHER (!) the context switching or the query must be commented out to FIX THE ISSUE
//
//
// Blit the framebuffer from the window FBO to the texture FBO, then delete the framebuffer
glCheck(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0u));
glCheck(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destFrameBuffer));
glCheck(glBlitFramebuffer(0, 0, 256, 256, 0, 0, 256, 256, GL_COLOR_BUFFER_BIT, GL_NEAREST));
glCheck(glDeleteFramebuffers(1, &destFrameBuffer));
//
//
// Write texture data into a pixel array and read it back
glCheck(glBindTexture(GL_TEXTURE_2D, glTexture));
sf::base::U8 pixels[256 * 256 * 4]{};
GLuint imageFBO{};
glCheck(glGenFramebuffers(1, &imageFBO));
assert(imageFBO);
glCheck(glBindFramebuffer(GL_FRAMEBUFFER, imageFBO));
glCheck(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture, 0));
glCheck(glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
glCheck(glDeleteFramebuffers(1, &imageFBO));
const auto index = (64 + 64 * 256) * 4; // pixel at (64, 64)
const sf::base::U8* pixel = &pixels[index];
//
//
// These assertions will fail unless EITHER the context switching or the query is commented out
assert(pixel[0] == 255); // Red
assert(pixel[1] == 0); // Green
assert(pixel[2] == 0); // Blue
assert(pixel[3] == 255); // Alpha
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment