Skip to content
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

New support for controlling the scaling policy/mode of SDL_RenderSetLogicalSize for both letterbox and overscan #1703

SDLBugzilla opened this issue Feb 10, 2021 · 0 comments


Copy link

@SDLBugzilla SDLBugzilla commented Feb 10, 2021

This bug report was migrated from our old Bugzilla tracker.

Reported in version: 2.0.3
Reported for operating system, platform: All, All

Comments on the original bug report:

On 2014-12-03 12:56:48 +0000, Eric wing wrote:

Adds support to control the scaling policy/mode of SDL_RenderSetLogicalSize for both letterbox (current behavior) and a new overscan mode (expan
d to fill the entire screen, even if some parts draw off the screen).

The expected use case is for games that are designed with multiple aspect ratios already in mind and leave optional margins on the edges of the game which won't hurt if they are cut off.

An example use case is a game is designed for wide-screen/16:9, but then wants to deploy on an iPad which is 4:3. Normally, SDL will letterbox, which will shrink things and result in wasted space. But the designer already thought about 4:3 and designed the edges of the game so they could
be cut off without any functional loss. So rather than wasting space with letterboxing, "overscan" mode will zoom the rendering to fill up the
entire screen. Parts on the edges will be drawn offscreen, but since the game was already designed with this in mind, it is fine. The end result
is the iPad (4:3) experience is much better since it feels like a game designed for that screen aspect ratio.

This patch introduces a new SDL_hint: SDL_HINT_RENDER_LOGICAL_SIZE_MODE.
Valid values are "letterbox" or "0" for letterboxing and "overscan" or "1" for overscan.
The default mode is letterbox to preserve existing behavior.

// Example usage:
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);

// Sample picture of Letterbox:

// Sample picture of Overscan:

The patch repository:

On 2016-04-02 14:53:09 +0000, Roberto Prieto wrote:

Hello Eric,

First of all, thanks you very much for your patch, it is quite useful for people that wanted to use the overscan method over the default and unique letterboxing method.

I have tried your patch in current SDL2 code (as of 31-March-2016) and it worked fine for:

  • Software
  • Direct3D 11
  • OpenGL

but with standard Direct3D, all I got is a black screen. I have tested it on Windows 10 and 7, 32 and 64 bits modes and with AMD/Nvidia cards just for discarding a configuration issue, but the same issue on all configuration.

I know a lot of time since your post but if by any chance you can help with this issue, it will be great!!


On 2016-04-02 18:44:10 +0000, Roberto Prieto wrote:

Hi again,

Well, after checking the code it seems that the guilty is Direct3D 9 as the view port is using unsigned int so no negative values can be passed to it the changes made for the "overscan" method used negative values...

OpenGL and Direct3D 11 allow the viewport to be negative...


On 2016-04-02 21:03:23 +0000, Eric wing wrote:

Thank you for discovering and isolating this problem. I admit I'm not a Direct3D guru, so I was wondering if you had any ideas on how we can workaround this problem for D3D9. I would like to fix this if possible.

On 2016-04-02 21:43:41 +0000, Eric wing wrote:

Also, how do you force select D3D9 vs. D3D11?

On 2016-04-02 23:34:39 +0000, Roberto Prieto wrote:

Hi Eric,

As you are modifying the viewport for performing the overscan method, I think it can not be implemented on Direct3D 9:

typedef struct _D3DVIEWPORT9 {
DWORD Y; /* Viewport Top left /
DWORD Width;
DWORD Height; /
Viewport Dimensions /
float MinZ; /
Min/max of clip Volume */
float MaxZ;

Being DWORD=unsigned int

Unless you find a workaround for doing the same without using the viewport, it wont work on Direct3D 9. I spent some time "googling" but didnt find anything that could help.

For using Direct3D 11, you have to enable this flag on SDL_config_windows.h:

and SDL2 will be using it as a renderer. Then, in your code, when creating the renderer:
SDL_CreateRenderer(windows, 1, 0);
Usually, the order is 0 for d3d9, 1 for d3d11, 2 for opengl.

This renderer only works on Windows 8+, I have an article on my blog explaining why (

Hope you can find an alternative way of doing it without using viewports or someone else with more knowledge of Direct3D can show us how to "emulate" a viewport with negative values..


On 2016-04-02 23:59:17 +0000, Eric wing wrote:

Thank you for investigating all this. This is really good information.

So here are my thoughts, though as I said, I am not a D3D guru, so if you know how to actually implement this or see a problem with this idea, I'd like your help.

  1. We add a runtime check for Direct3D inside SDL when the overscan hint is requested. If it is D3D 11 or more, we allow the overscan hint to work as before. (I'm not sure how to do a runtime check on this since you are setting a compile flag.)

  2. If we detect D3D 9 (or less?), then we can either:
    2a) ignore the hint and say it is not supported
    2b) We try to do something with the projection matrix. I found this function via Google: D3DXMatrixOrthoOffCenterLH. I'm thinking we can leave the viewport alone, and zoom in the orthographic projection.

The major downside I see to this (besides the extra complexity of figuring out how to actually do this), is that I think we can only do this for the SDL 2D renderer. We must not interfere with anybody who is directly requesting a D3D context and using it directly. Presumably this call would screw up their own projection matrix. (I don't know offhand if it is actually possible to screw up somebody else's D3D context in SDL since they are probably separate instances and set active at different times, but I want to be confident we don't create some weird/broken subtle interaction bug between the two systems.)

What do you think? Do you have any expertise on the right incantations to do this?

On 2016-04-05 07:45:53 +0000, Eric wing wrote:

First, I pushed a fix to my original overscan repo/patch that checks for Direct3D 9 and ignores the overscan hint/mode for that case. This will avoid the black screen problem.

The request that this be accepted into mainline continues.

Second, I tried some experiments to implement overscan for D3D9, but it hasn't worked so well. I tried two different techniques,

  1. setting the orthographic projection matrix to zoom in to the correct area (adjusting for aspect ratio)
  2. setting a modelview matrix basically to scale everything

In the first case, I thought this idea would be easy...just set the orthographic rect to the region you want to look at and I thought things would just workout, but it's not working out that way. You can kind of see the idea, but the specifics are wonky. Shrinking the window works better than growing it. But in my tests, not everything seems to be centered around the same origin. Some things are centered, but I see other things misaligned sometimes.

In the second case, I tried to change a modelview matrix and basically just scale everything. Since overscan basically just scales until everything fits the screen, I thought this might be an alternative path. This one works a little bit better, however I think this approach is actually less sound than the projection matrix. One problem is that there is no global modelview matrix and seems to be on a per-RenderCopyEx basis. (I hacked RenderCopy to go to RenderCopyEx in the D3D version.) So each object gets transformed separately. I noticed for large window sizes, some of my objects felt like they were bunching up. Also, I was having trouble keeping the screen centered. I kind of got that working in the shrink case, but it breaks on the grow case.

In both cases, there are some other problems. First culling/clipping seems to be happening, and in a different coordinate system than what I'm showing. So for example, if you make the window small, things on the edge of the screen seem to get prematurely culled.

Additionally, both of these cases do not affect the mouse coordinates. So if you are trying to click some object, the coordinates are not lining up. I'm not sure where this code is. But since I didn't need to muck with it before, I assume it is tied with the viewport settings.

So I feel stuck at the moment. I'm posting my (hacky) changes in another repo if you or anybody else wants to play with this.

hg push ssh://
There are two Mercurial bookmarks "overscan_d3d9_projection" and "overscan_d3d9_modelview"

On 2016-04-05 07:47:28 +0000, Eric wing wrote:

I picked the wrong link to copy. This is a better link to find my experiments repo.

On 2016-04-09 10:52:37 +0000, Roberto Prieto wrote:

Hi Eric,

The way I am using SDL2 is through a high-level library which wrap and extend the functionality. As the D3D9 code path for the overscan is not working, I am just disabling it when the user asked for it.

In my case, it does not hurt to much as for Windows 8+, I am using D3D11 and for Android/Linux/MacOS X, OpenGL code path is used. As you see, in my case at least, no real rush for having a functional D3D9 code.

I now it is a pity not having it using a clean way but is the D3D9 which imposes the restriction of not having negative values on the viewport. Hacking too much around the SDL2 source code for getting it, IMHO does not worth it.

Unfortunately, my D3D knowledge is very limited so I could not help you.

I really appreciate your efforts for trying to fix it and probably your 2 alternatives solution could help someone else. For me, your patches were really important and they will use for sure :)

Thanks you very much Eric!


On 2017-06-06 18:10:32 +0000, Ryan C. Gordon wrote:

This patch is now, thanks!


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

No branches or pull requests

1 participant