-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SDL_RenderReadPixels() doesn't seem to work with offscreen render-targets. #11776
Comments
What platform are you testing on and which renderer are you using? |
This is on a Mac, and the renderer is the 2D renderer ( Created via |
What is the output of SDL_GetRendererName()? |
Ah, sorry, not really understanding your question there. It outputs 'metal'. |
Okay, thanks for the info! |
I'll try to reproduce, this sounds like a legit bug. |
This is working here with this test program: #include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
static void take_snapshot(SDL_Renderer *renderer, const char *fname)
{
SDL_Surface *surface = SDL_RenderReadPixels(renderer, NULL);
if (surface) {
SDL_SaveBMP(surface, fname);
SDL_DestroySurface(surface);
}
}
int main(int argc, char **argv)
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer("Hello SDL", 640, 480, 0, &window, &renderer);
SDL_Texture *rt = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, 640, 480);
SDL_Log("Current SDL 2D render backend: '%s'", SDL_GetRendererName(renderer));
bool done = false;
while (!done) {
bool snap = false;
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_EVENT_QUIT) {
done = true;
} else if ((e.type == SDL_EVENT_KEY_DOWN) && (e.key.key == SDLK_SPACE)) {
snap = true;
}
}
/* window framebuffer is blue, render target is red. */
SDL_SetRenderTarget(renderer, rt);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderClear(renderer);
if (snap) {
take_snapshot(renderer, "render-target.bmp");
}
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderClear(renderer);
if (snap) {
take_snapshot(renderer, "framebuffer.bmp");
}
SDL_RenderPresent(renderer);
}
SDL_Quit();
return 0;
} Basically it clears the window to blue, clears a render target to red, and when you press the space bar it calls SDL_RenderReadPixels on each and saves the data to .bmp files ... both files are correct when I do it here on a M1 Mac Mini, using either the Metal or OpenGL backends. Running macOS Sonoma 14.4.1, using the latest in SDL3's revision control. If this test program works for you, too, take another look at your code to make sure it's not something silly like SDL_SetRenderTarget() accidentally got called with a NULL pointer before the ReadPixels operation. If it's still a mystery after that, let's try to figure out next steps to solve your problem. |
Ok, so this works (sort of, see [*] below) for me too - so I must have a set-to-NULL somewhere in the chain. It's can be a long, convoluted chain, which I thought I'd worked through, but presumably I missed something. Thanks for doing the legwork, sorry for the noise :) [*] First off, I couldn't find where the files were being written to. Apple's sandbox is just annoying. Forcing a write to /tmp/... made the files appear, but they couldn't be loaded by Preview. I'd get: However, if I ran 'file' on the outputted file, it reported it correctly:
I got the same 'unrecognised file' when I tried to load it using "xv" (yes, I am that old). If I ran the file through So I'm wondering if there's an endian issue in the SDL_SaveBMP() method, or maybe Preview doesn't support the "Windows 95/NT4" format. Or perhaps it's just an OS bug... I don't know... :) In any event, it looks as though I need to track down where the renderer target is being set to NULL... |
Just to follow up on this - I found the bug and it was in my code [blush] The problem wasn't the render-target being set to NULL explicitly . It was that I was creating some textures with Anyway, now I create my texture from the surface and immediately create another texture and copy into it, throwing away the old one that was generated from the surface, and setting It was all in the documentation. I should maybe try reading that sometime... :) |
I'm glad it's working now! While working on this, I also noticed that Preview doesn't like our (32-bit) bitmaps, so we're tracking that over in #11903, if you're curious. |
I've got an app that is creating a bunch of background targets and switching the renderer between them frequently. Basically every view or image is a texture. To make this easier, there is a texture-manager, and I refer to all the textures by an integer id.
All the imagery is backed by a texture, but sometimes I might want to write an image to disk, so I've been trying to use
SDL_RenderReadPixels()
to pull the data back from the GPU into CPU land. The problem is that even though I'm setting the render-target, what I get back is the main window's pixels, not the pixels of the offscreen render-target I just chose.The below is the test-app for the framework. As a debugging tool, when I change the radio buttons, it tries to load an image, then immediately save it to /tmp/test.png.
I put in some logging for:
And I see: (trimming a whole bunch of render-target selection before I press the button as the UI is rendered out)
(The last two, 15 and 16, are the radio buttons redrawing themselves, so we can ignore). The point is that the renderer is switched to the texture representing the image (texture id 29) all the time the save operation is in progress, but the output I get is this exact screen in the image above, not the image I told it to load.
The load-image process is wrapped up in framework code, but basically boils down to:
I did look at the example code for
SDL_RenderReadPixels()
but it doesn't seem to deal with offscreen textures, just with copying from the main window. Which definitely works! :)This is with the 2D render API btw. Created via
SDL_CreateWindowAndRenderer()
The text was updated successfully, but these errors were encountered: