Allow games to specify their pixel aspect ratio - DO NOT MERGE #1132
DO NOT MERGE: This pull request is incomplete and is here to ask for feedback.
The way the aspect ratio correction works in ScummVM is currently too restrictive for some games. Backends hardcode a 6:5 correction designed to go from 320x200 to 320x240 or 640x400 to 640x480. When aspect ratio correction is on, the SDL backends (both surface and OpenGL) for example systematically apply this 6:5 correction when the game original resolution is either 320x200 or 640x400 and do no correction otherwise.
Here are some cases where it fails:
The approach that I have taken here is to modify Graphics::Mode to contain a pixel aspect ratio in addition to the width and height of the game. I then modified
All other backends are broken since I did not report the change in the OSystem API to them yet.
Another limitation of this pull request is that the SurfaceSdl backend only supports 1:1 or 6:5 corrections. So any other correction is ignored. To test those currently you have to use the OpenGL mode.
Note that in theory this approach allows the backend to choose the correction based on the given game pixel aspect ratio and the current display device (i.e screen) pixel aspect ratio. In the changes I made the backends assume the display uses square pixel when doing the correction.
At this points this allows to see that the approach works. Before I continue further I would like some feedback:
The text was updated successfully, but these errors were encountered:
The main idea is to allow engines to pass the pixel aspect ratio the game was designed for and let the backend use this information to correct for the game pixel aspect ratio depending on the pixel aspect ratio of the device or computer on which ScummVM is running. This replaces the hardcoded 6/5 correction that was used until now. The OpenGL graphics backend has been updated to handle the new pixel aspect ratio information. The SurfaceSdl graphics backend has been partially updated but will currently ignore any pixel aspect ratio different from 1 or 6/5. Compilation for other backends is likely to be broken. In engines initGraphics() has also be updated. By default engines will use a pixel aspect ratio of 6/5 if the game size is 320x200 or 640x400 and a ratio of 1 otherwise (as the backend was doing previously). Bug games now have the possibility to explicitly specify the game pixel aspect ratio.
…n Graphics::Mode The reason for this change is to work around precision issue in frac_t. It uses integer division and this means that the fraction stored can actually be a bit smaller than its real value. When it was stored as pixel height/width, to get the correct screen height we were multiplying the fraction with the screen height and could get a height slightly too low. For example 640x400 was corrcted to 640x479. Inverting the fraction still stores a value that can be a bit lower than the real value, but as it is now used as the denominator in an integer division to get the corrected screen, dividing by a value too small and rounding down the result more or less cancel each others. An alternative here would be to use Common::Rational instead of frac_t to store and handle the game pixel aspect ratio.
Do you have a more complete list of cases anywhere? I believe NES Maniac Mansion also belongs on this list since it is supposedly around 8:7 PAR, and @rsn8887 mentioned that at least some of Monkey Island 1’s assets appeared to be designed for square pixels. Maybe this ticket can be repurposed for this AR work if you don’t have one already since it discusses this a bit.
So far the changes are in line with what I was expecting when
The dimensions-only constructor is convenient, and after thinking about it, I’m still leaning toward wanting to always have engines give a PAR instead of having a “guess the PAR from the dimensions” magic. Adding some predefined constants for the common PARs would be helpful so developers have an easier time picking the right one. I’ve also been wondering whether a helper function to generate the PAR from a width + height + display aspect ratio might be convenient (or maybe it just ends up being confusing and unnecessary, I’m not sure).
Probably so. In absence of a specific performance problem requiring reduced precision, it makes more sense to me to default to
I don’t have a good sense of how to address this. While theoretically generic, it seems like the OSystem “graphics mode” is used in practice to define different ways of scaling the video output, so maybe it should have a different name using a word like “scaler” or “filter” or “effect” or “shader” instead. I’m not sure how to successfully avoid confusion by changing
SDL2’s own scaling does seem preferable for the final pass for the reasons you’ve mentioned. There is also some arbitrary scaling code in TransparentSurface which I’ve wanted moved out for some time now which could also be used if needed. I had some trouble when trying to use the SDL scaling code for 32bpp cursors (IIRC 2.0.4 on Windows would not render anything), though that trouble may have been also from the broken RLE optimisation since it happened around the same time.
As much as I would like to eliminate the legacy baggage of SDL1, I think it needs to stick around until we don’t have any more platforms without an SDL2 port. That said, I don’t think those legacy platforms need to receive first-class support at this point, so accurate scaling only with SDL2 & OpenGL seems like a reasonable compromise.
Finally, mentioning this at the end only since you added a docblock on it: the
The main reason for this change is to try to avoid confusion with OSystem::GraphicsMode.