SDL 1.3 scaling

Hi

This keeps cropping up time and again, and it’s probably me not being able to work it out right, but I have a window that is 1280x1024 (or larger, possibly), and all my graphics are
produced to fit a 1024x768 window.

I want to (and should be able to) blit everything at 1024x768 and then simply scale that frame up to 1280x1024 when the next render is required. I cannot see how to do this in SDL.

If you cheat and specify a larger destination rectangle to SDL_RenderCopy, you get a lot of “artifacts” left on screen where the scaling calculation is out by +/- 1 pixel,
which looks terrible.

Can someone help? Scanning back through the forum, it looks like others are struggling with this also.

Thanks
Ed

You may be scaling wrong, or placing items wrong. Are you simply casting back to int after the calculation, or using a function like ceil or floor?

As for a proper solution, the only decent option you have is to change the monitor’s resolution to the ideal using SDL_SetDisplayMode. But your users may not enjoy that.------------------------
EM3 Nathaniel Fries, U.S. Navy

http://natefries.net/

Hi Nathaniel

My calculation is just:

srcWCalc = screenW / 1024.0;
srcHCalc = screenH / 768.0

(srcWCalc & srcHCalc are floats, screenW and screenH are ints). Then I just multiply the w,h, dest x and dest y of the image by scrWCalc or scrHCalc.
It works - but I get things 1 pixel out. I don’t use ceil or floor.

I can’t change the monitor’s resolution on the fly, this is not allowed on the system and game I am writing.

I could just do everything as an SDL surface, then convert the entire surface to a texture and scale it every frame, but it sounds like a backwards step and would probably be very inefficient.
I find it quite hard to believe there isn’t an intermediate texture which can then be rendered to, then just send that frame to the screen. I have seen other pure DirectX games do this - but I
don’t know how they do it :frowning:

Cheers
Ed

Most games have different graphics for different aspect ratios. I don’t
know if that helps you or not, but it may alleviate some of the issues
you’ve been having.
Take care,
-OzOn Fri, Apr 29, 2011 at 4:00 AM, ebyard <e_byard at yahoo.co.uk> wrote:

Hi Nathaniel

My calculation is just:

srcWCalc = screenW / 1024.0;
srcHCalc = screenH / 768.0

(srcWCalc & srcHCalc are floats, screenW and screenH are ints). Then I just
multiply the w,h, dest x and dest y of the image by scrWCalc or scrHCalc.
It works - but I get things 1 pixel out. I don’t use ceil or floor.

I can’t change the monitor’s resolution on the fly, this is not allowed on
the system and game I am writing.

I could just do everything as an SDL surface, then convert the entire
surface to a texture and scale it every frame, but it sounds like a
backwards step and would probably be very inefficient.
I find it quite hard to believe there isn’t an intermediate texture which
can then be rendered to, then just send that frame to the screen. I have
seen other pure DirectX games do this - but I
don’t know how they do it [image: Sad]

Cheers
Ed


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

…converting a 1024x768 SDL_Surface to a texture takes ~45ms on my Core i3 + GeForce CUDA, so this is not a viable option. I’d be lucky to get 10fps once all other rendering to the surface is done!

MrOzBarry wrote:

Most games have different graphics for different aspect ratios. ?I don’t know if that helps you or not, but it may alleviate some of the issues you’ve been having.Take care,
-Oz

True, but getting another set of graphics done is very expensive (and time consuming), not to mention a complete hassle in software with look-up tables for XY positions etc. I haven’t been doing graphics stuff for very long (my background is in embedded systems), but it just seems odd that the most obvious way to solve what looks to be a common problem hasn’t been implemented. I freely admit I could be misunderstanding the “right” way to do things, so any pointers are very welcome.

Just looking through the SDL code, the SDL_UpdateTexture function would fit the bill, but the problem is it’s speed (as in previous post - SDL_ConvertSurfaceToTexture calls SDL_UpdateTexture under the hood).

Cheers

Anything to do with textures should be done on hardware, which should be
fairly fast. If it’s not fast enough, OpenGL might be the route to take,
which is also hardware, but may have some more verbose ways to resize
textures.
Take care,
-OzOn Fri, Apr 29, 2011 at 7:33 AM, ebyard <e_byard at yahoo.co.uk> wrote:

MrOzBarry wrote:

Most games have different graphics for different aspect ratios. I don’t
know if that helps you or not, but it may alleviate some of the issues
you’ve been having.Take care,
-Oz

True, but getting another set of graphics done is very expensive (and time
consuming), not to mention a complete hassle in software with look-up tables
for XY positions etc. I haven’t been doing graphics stuff for very long (my
background is in embedded systems), but it just seems odd that the most
obvious way to solve what looks to be a common problem hasn’t been
implemented. I freely admit I could be misunderstanding the “right” way to
do things, so any pointers are very welcome.

Just looking through the SDL code, the SDL_UpdateTexture function would fit
the bill, but the problem is it’s speed (as in previous post -
SDL_ConvertSurfaceToTexture calls SDL_UpdateTexture under the hood).

Cheers


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Anything to do with textures should be done on hardware, which should be
fairly fast. If it’s not fast enough, OpenGL might be the route to take,
which is also hardware, but may have some more verbose ways to resize
textures.
Take care,
-Oz

Second that. The game Doom3 had to render a consistent (mean here:
consistent size %) UI with varying resolutions and one set of images. They
used a virtual coordinate grid (640x480 I believe) and mapped coordinates
along that grid. Then, using simple linear algebra (matrix transform), they
transformed the 640x480 resolution to the native resolution. So, in effect,
they laid out their elements on this virtual grid, then scaled the points
that made up the images (each corner of the rectangle), then told the
hardware to render using those points. In OpenGL, gluOrtho2D() will create
such a transformation. Scaling for free is one of the big advantages of
using hardware accelerated OpenGL rendering.

PatrickOn Fri, Apr 29, 2011 at 6:58 AM, Alex Barry <alex.barry at gmail.com> wrote:

I guess you have a couple options:

  1. In windowed mode, keep the resolution that your graphics are optimized for.

  2. In fullscreen mode, set the resolution to 1024x768 and leave the
    monitor do the scaling for you.

  3. If you absolutely want to.scale yourself, set a better scale mode.
    By default SDL 1.3 uses GL_NEAREST for scaling (or the D3D
    equivalent). You could change that by setting

SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, “linear”);

once before your main loop start.

Option (1) will look good, but might be too small on large desktops.
Option (2) and (3) will be better than what you have now, but probably
not the quality you’d like to have. In general, upscaling does not
really do any good.

What we ended up doing is option no. 4:

Choose the internal view size of the game such that an integer scale
to desktop resolution is possible. That has two advantages:

  1. The image will always be crystal clear (if you use the default
    SCALE_QUALITY).
  2. You get support for different screen aspect ratios for free.

The downside is, a user with an old 15" 1024x768 LCD will get a bigger
view on your game world (1024x768, unscaled) than one with a big 21"
at 1680x1050, who will only see 840x525, scaled by factor 2. And of
course, your HUD needs to be dynamic as well.

KaiOn Thu, Apr 28, 2011 at 1:55 PM, ebyard <e_byard at yahoo.co.uk> wrote:

Hi

This keeps cropping up time and again, and it’s probably me not being able
to work it out right, but I have a window that is 1280x1024 (or larger,
possibly), and all my graphics are
produced to fit a 1024x768 window.

I want to (and should be able to) blit everything at 1024x768 and then
simply scale that frame up to 1280x1024 when the next render is required. I
cannot see how to do this in SDL.

ebyard wrote:

Hi Nathaniel

My calculation is just:

srcWCalc = screenW / 1024.0;
srcHCalc = screenH / 768.0

(srcWCalc & srcHCalc are floats, screenW and screenH are ints). Then I just multiply the w,h, dest x and dest y of the image by scrWCalc or scrHCalc.
It works - but I get things 1 pixel out. I don’t use ceil or floor.

I can’t change the monitor’s resolution on the fly, this is not allowed on the system and game I am writing.

I could just do everything as an SDL surface, then convert the entire surface to a texture and scale it every frame, but it sounds like a backwards step and would probably be very inefficient.
I find it quite hard to believe there isn’t an intermediate texture which can then be rendered to, then just send that frame to the screen. I have seen other pure DirectX games do this - but I
don’t know how they do it :frowning:

Cheers
Ed

Try using ceil.------------------------
EM3 Nathaniel Fries, U.S. Navy

http://natefries.net/

Try using ceil.

It won’t work. Consider the following with a screen resolution of 1600 x 900:

Code:

scrWCalc = ((float)config->getScrW() / 1024.0); // result is 1.5625000
scrWCalc = ceil(scrWCalc); // scrWCalc is now 2.00
scrHCalc = ((float)config->getScrH() / 768.0); // result is 1.1718750
scrWCalc = ceil(scrHCalc); // scrHCalc is now 2.00

So everything is drawn far too big (off the side of the screen), and doesn’t fix the artifact issue ?

Regards
Ed

ebyard wrote:

Try using ceil.

It won’t work. Consider the following with a screen resolution of 1600 x 900:

Code:

scrWCalc = ((float)config->getScrW() / 1024.0); // result is 1.5625000
scrWCalc = ceil(scrWCalc); // scrWCalc is now 2.00
scrHCalc = ((float)config->getScrH() / 768.0); // result is 1.1718750
scrWCalc = ceil(scrHCalc); // scrHCalc is now 2.00

Everything is therefore drawn 2x the original size which is clearly wrong ? Am I missing something, other than a brain, perhaps??

Regards
Ed

Not on those! When you do the actual calculations for the rendering positions.------------------------
EM3 Nathaniel Fries, U.S. Navy

http://natefries.net/

What you really need is a distinct “logical size” for your rendering window,
independent of the physical size in pixels.

I’ve implemented this locally, but it would be a big hassle to try to submit a
patch for it because it involves a lot of the same source files as my render
targets submission, and until that gets applied to the codebase it would be
really messy to make a patch that would work right.________________________________
From: nfries88@yahoo.com (Nathaniel J Fries)
Subject: Re: [SDL] SDL 1.3 scaling

ebyard wrote:

Quote:
Try using ceil.

It won’t work. Consider the following with a screen resolution of 1600 x 900:

Code:

scrWCalc = ((float)config->getScrW() / 1024.0); // result is 1.5625000
scrWCalc = ceil(scrWCalc); // scrWCalc is now 2.00
scrHCalc = ((float)config->getScrH() / 768.0); // result is 1.1718750
scrWCalc = ceil(scrHCalc); // scrHCalc is now 2.00

Everything is therefore drawn 2x the original size which is clearly wrong ? Am I
missing something, other than a brain, perhaps??

Regards
Ed
Not on those! When you do the actual calculations for the rendering positions.


EM3 Nathaniel Fries, U.S. Navy

http://natefries.net/

Mason Wheeler wrote:

What you really need is a distinct “logical size” for your rendering window, independent of the physical size in pixels.

I’ve implemented this locally, but it would be a big hassle to try to submit a patch for it because it involves a lot of the same source files as my render targets submission, and until that gets applied to the codebase it would be really messy to make a patch that would work right.

Indeed. Render targets are the only way to do this “right”, and currently the only way to do anything like render targets would be through the 1.2 API.------------------------
EM3 Nathaniel Fries, U.S. Navy

http://natefries.net/

Nathaniel J Fries wrote:

Mason Wheeler wrote:

What you really need is a distinct “logical size” for your rendering window, independent of the physical size in pixels.

I’ve implemented this locally, but it would be a big hassle to try to submit a patch for it because it involves a lot of the same source files as my render targets submission, and until that gets applied to the codebase it would be really messy to make a patch that would work right.

Indeed. Render targets are the only way to do this “right”, and currently the only way to do anything like render targets would be through the 1.2 API.

Yeah, I am quickly realising this. I’ve been googling some 2D DX related stuff, and what others say is that you should use a kind of double-buffering, blit everything to the back buffer then copy that to the front buffer and present that (scaled). I don’t know if this is relevant to SDL 1.3, especially since all the old renderer flags (SDL_RENDERER_PRESENTDISCARD etc) were removed with the recent overhaul.

Thanks

I don’t know if this is a useful answer to your question or not, but in my quake engine I recently implemented scaling in OpenGL by simply setting the glViewport to a corner of the screen at the
desired resolution, then copying that to a texture and rendering it fullscreen to scale up, you can pick GL_NEAREST or GL_LINEAR filtering for this (or write your own in a shader if you want).

The main novelty of this is running at full desktop resolution in fullscreen, and rendering at a reduced resolution to reduce the cost of overdraw/blending/shaders.

Unreal Tournament 3 does this as well, with the 2D art being drawn after the 3D view in full resolution, so you still get crisp text.–
LordHavoc
Author of DarkPlaces Quake1 engine - http://icculus.org/twilight/darkplaces
Co-designer of Nexuiz - http://alientrap.org/nexuiz
"War does not prove who is right, it proves who is left." - Unknown
"Any sufficiently advanced technology is indistinguishable from a rigged demo." - James Klass
"A game is a series of interesting choices." - Sid Meier

Forest Hale wrote:

I don’t know if this is a useful answer to your question or not, but in my quake engine I recently implemented scaling in OpenGL by simply setting the glViewport to a corner of the screen at the
desired resolution, then copying that to a texture and rendering it fullscreen to scale up, you can pick GL_NEAREST or GL_LINEAR filtering for this (or write your own in a shader if you want).

The main novelty of this is running at full desktop resolution in fullscreen, and rendering at a reduced resolution to reduce the cost of overdraw/blending/shaders.

Unreal Tournament 3 does this as well, with the 2D art being drawn after the 3D view in full resolution, so you still get crisp text.

Thanks for the info. This, in a roundabout way, sounds exactly like what I need to do, which is to essentially copy (or blit) to an intermediate texture and then render that but scaled up to the desired size. Why you can do this (seemingly easily?) in OpenGL and not DirectX, I don’t know. I have no experience with OpenGL and really, the point of using SDL for me is to abstract all that graphics/OS specific stuff away, so that I just call SDL_whatever and it does it, and what’s under the hood, I care very little about.

Is 2D in OpenGL, using SDL 1.3, fairly simple to implement? I’m really doing nothing advanced - no 3D at all.

Thanks again

Ed

Blitting to an intermediate texture in SDL 1.3 requires the use of render
targets. I submitted a patch to enable render targets in OpenGL a long time
ago, but no one’s ever gotten around to merging it into the codebase. :(________________________________
From: e_byard@yahoo.co.uk (Edward Byard)
Subject: Re: [SDL] SDL 1.3 scaling

Forest Hale wrote:
I don’t know if this is a useful answer to your question or not, but in my quake
engine I recently implemented scaling in OpenGL by simply setting the glViewport
to a corner of the screen at the

desired resolution, then copying that to a texture and rendering it fullscreen
to scale up, you can pick GL_NEAREST or GL_LINEAR filtering for this (or write
your own in a shader if you want).

The main novelty of this is running at full desktop resolution in fullscreen,
and rendering at a reduced resolution to reduce the cost of
overdraw/blending/shaders.

Unreal Tournament 3 does this as well, with the 2D art being drawn after the 3D
view in full resolution, so you still get crisp text.

Thanks for the info. This, in a roundabout way, sounds exactly like what I need
to do, which is to essentially copy (or blit) to an intermediate texture and
then render that but scaled up to the desired size. Why you can do this
(seemingly easily?) in OpenGL and not DirectX, I don’t know. I have no
experience with OpenGL and really, the point of using SDL for me is to abstract
all that graphics/OS specific stuff away, so that I just call SDL_whatever and
it does it, and what’s under the hood, I care very little about.

Is 2D in OpenGL, using SDL 1.3, fairly simple to implement? I’m really doing
nothing advanced - no 3D at all.

Thanks again

Ed

I’ve spent the past few hours looking through the SDL code and googling a whole load of DX related stuff, and there looks to be no other way around it.
I had even looked into creating an invisible window with it’s own renderer etc, then trying to copy one window to another…which is a no go. Shame I can’t
just move the pointer around :frowning:

There is no quick & dirty fix for this, ie. just to implement a function to blit to a “destination” texture rather than some obfuscated display memory
somewhere. I guess the days of “just” being able to blit between here and there are gone, which is a pity.

ebyard wrote:

I’ve spent the past few hours looking through the SDL code and googling a whole load of D3D related stuff, and there looks to be no other way around it without
spending a massive amount of time re-writing the SDL/D3D stuff.

There is no quick & dirty fix for this, ie. just to implement a function to blit to a “destination” texture rather than some obfuscated display memory
somewhere. I guess the days of “just” being able to blit between here and there are gone, which is a pity.

IDirect3DDevice::SetRenderTarget(IDirect3DSurface9*) seems to be the simplest way.
It would still require some heavy reconstruction of the D3D backend, though. I was also investigating. :wink:

ebyard wrote:

I’m pretty much resigned to having to get a set of graphics done for every screen res that can be used, which as a very small business is a massive
cost, so bang goes hiring a graduate this year :frowning:

Whoa, whoa. Just get one really large set made, and scale them down to the appropriate sizes.------------------------
EM3 Nathaniel Fries, U.S. Navy

http://natefries.net/