Description
Hello.
I encountered something very weird and I'm not sure if this is correct behavior or not, whether it is a bug or not. Still, before trying workarounds to this problem in SDL my application, I want to ask. I wasted already enough hours without figuring out what I'm doing wrong, if I do.
In my application I use hardware accelerated rendering to render normally to the window but also to render to an offscreen texture with the size of the window and rendering that to the window for some graphical effects. I also use letterbox logical presentation, because my application needs a certain aspect ratio.
I do as per the documentation of SDL_SetRenderLogicalPresentation
:
It might be useful
to draw to a texture that matches the window dimensions with logical
presentation enabled, and then draw that texture across the entire window
with logical presentation disabled. Be careful not to render both with
logical presentation enabled, however, as this could produce
double-letterboxing, etc.
Here is a MCVE:
int main() {
SDL_Window *win = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *backTex = NULL;
int width = 640, height = 360;
bool loopShouldStop = false;
SDL_FRect rect1 = { 100, 100, 50, 50 };
SDL_FRect rect2 = { 150, 150, 50, 50 };
SDL_Init(SDL_INIT_VIDEO);
win = SDL_CreateWindow("Hello World", width, height, SDL_WINDOW_RESIZABLE);
SDL_SetRenderLogicalPresentation(renderer, width, height, SDL_LOGICAL_PRESENTATION_LETTERBOX); // Window default letterbox
renderer = SDL_CreateRenderer(win, NULL);
backTex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
SDL_SetRenderTarget(renderer, backTex);
SDL_SetRenderLogicalPresentation(renderer, width, height, SDL_LOGICAL_PRESENTATION_LETTERBOX); // Offscreen texture default letterbox
SDL_SetRenderTarget(renderer, NULL);
while (!loopShouldStop)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_EVENT_QUIT:
loopShouldStop = true;
break;
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
SDL_DestroyTexture(backTex);
backTex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, event.window.data1, event.window.data2);
SDL_SetRenderTarget(renderer, backTex);
SDL_SetRenderLogicalPresentation(renderer, width, height, SDL_LOGICAL_PRESENTATION_LETTERBOX); // Offscreen texture default letterbox
SDL_SetRenderTarget(renderer, NULL);
break;
}
}
// Render first rect on window
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderRect(renderer, &rect1);
// Render second rect on offscreen texture
SDL_SetRenderTarget(renderer, backTex);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderRect(renderer, &rect2);
SDL_SetRenderTarget(renderer, NULL);
// Render offscreen texture
SDL_SetRenderLogicalPresentation(renderer, width, height, SDL_LOGICAL_PRESENTATION_DISABLED);
SDL_RenderTexture(renderer, backTex, NULL, NULL);
SDL_SetRenderLogicalPresentation(renderer, width, height, SDL_LOGICAL_PRESENTATION_LETTERBOX);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(backTex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
}
In the previous example there are two rects rendered right near each other on the diagonal. One is rendered on the window and the other on the offscreen texture. The problem is that, when resizing the window, the second rect is displaced, as if the offscreen texture is rendered not at (0, 0), but starting from the top side or left side black bar. I expected the offscreen texture to be rendered at the origin of the window, because I disabled the logical presentation.
Is this the correct behavior and it is me who didn't understand the API and the details?
I tested this on Linux, SDL3 main branch at commit 390fe65. It is the same on OpenGL, Vulkan and OpenGL ES.
I saved the offscreen texture to a PNG file and it is correct. That's why I think there is an issue with rendering the offscreen texture with letterboxing involved.