Created
May 2, 2025 14:38
-
-
Save vittorioromeo/3b3557d8e7d54ab64ee26843ccebbb44 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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