New Graphics System Details

Discussion of all aspects of the game engine, including development of new and existing features.

Moderator: Forum Moderators

Post Reply
mesilliac
Developer
Posts: 81
Joined: November 18th, 2005, 8:09 am
Location: New Zealand

New Graphics System Details

Post by mesilliac »

So with the help of Vultraz i've been working on constructing a compatibility layer for the current rendering system, which should allow everything to be slowly migrated towards three general goals:
  • support for scaling on high resolution displays
  • smooth/high-dpi fonts, images, backgrounds and game map while still having large pixel-based sprites
  • hardware accelerated rendering support
This post is partially for laying out the work that's been done, and partially for documenting the chosen solutions and any alternative options.

Scaling

I've already implemented a somewhat crude pixel scaling option which is in the master branch but hasn't hit a dev release yet. This essentially multiplies the size of a pixel by some small integer number. A 3840x2160 display with a pixel scale of 3 will have an effective drawing resolution of 1280x720, rendering the game low-resolution but playable. This allows basic high-dpi support.

There are two things that are not implemented, and that i am unlikely to implement but might be useful:
1. Non-integer scaling. For a game so heavily focused on pixel graphics, this significantly degrades the visual quality. However some people may still find it useful so it might be worth implementing in the future. It should not be difficult to implement.
2. A separate UI scale option to scale the UI without changing the game resolution. This might be useful but it's unlikely i'll have time to work on it. It would be a relatively easier task if somebody wanted to pick it up later.

High-DPI and hardware acceleration

I've mostly completed a prototype compatibility layer allowing both legacy low-resolution software-manipulated graphics and new high-resolution hardware-accelerated graphics to coexist and be used in parallel. That is, the existing Wesnoth rendering code can still be used, but should be migrated piece by piece to a better system.

The new drawing system will support both 2D hardware acceleration and high-dpi rendering. It supports these naturally by rendering using texture IDs of previously loaded textures, in stead of rendering by copying pixels between SDL surfaces.

Rendering system changes

Previously there were several ways of rendering, all of which invovled getting a pointer directly into graphics memory and blitting pixels onto the memory used to draw to the screen. The new compatibility layer abstracts this all away and removes it.

All direct manipulations of the framebuffer have been removed. Surface blits have been replaced with calls to CVideo::blit_surface, which uses a compatibility system to render the surface. Pixel copies have been replaced with a new interface to read pixels from the hardware-accelerated high-dpi rendering target and return them either in high or low res. These calls should be phased out for everything except screenshots.

The new drawing interface draws using textures. It should be used exclusively going forward, and all old surface drawing code should be migrated to use it. It is a simple CVideo::blit_texture call taking the texture and where it is to be drawn on the screen. There is a new clipping interface to set the clipping area correctly for both old-style and new-style draws, which works equivalently to the old clip_rect_setter.

Resolution, size and scale

To understand the new high-dpi rendering system, it is important to understand that there are now several different coordinate systems in use. This is unavoidable. However the vast majority of game systems can get by with assuming a single universal resolution, just as they have always done. This output resolution that the game will use I have called "game-native" resolution. This resolution matches the coordinates in themes, sizes given to UI widgets, and coordinates of input events.

This game-native resolution also corresponds to the coordinates used for draw calls, and i have also at places referred to it as "draw-space", "drawing space", "drawing resolution" and similar.

Coordinates used for input events i refer to as "input space", "input resolution", or "input size" for the game-visible size of the input area (i.e. the window). These should always match draw-space a.k.a. game-native coordinates. Their only importance is for calls that directly poll the mouse position, as these are not returned by SDL in draw-space coordinates, but rather window-space coordinates. A compatibility function has been added to poll the mouse position in input-space, and this is what should be used in all cases going forwards when the mouse position must be polled actively.

"window-space" is what i use to refer to the coordinate system the native OS-level windowing system uses. The meaning of this differs significantly between Windows, MacOs and Linux. However this is always the coordinate system used for placing a window on the OS desktop, for resizing it, and for reporting the fullscreen and window resolution listed in Wesnoth preferences. It is important when dealing with these events and controls to use the correct coordinate system.

"output space/size/resolution", "render-space", "rendering space", "render size" and "render target size" are interchangeably used to refer to the coordinate system of the final output high-dpi rendering target. In high-dpi contexts this will be higher resolution than game-native / drawing resolution. Most game systems once converted to use the new texture drawing interface will automatically and transparently render at the full output resolution with no knowlede of what it is. The only exception is font rendering, which will need to know the scale factor between drawing space and render space to generate font textures at the appropriate resolution.

Currently render size is restricted to an integer multiple of the drawing size. This is controlled by a user-configurable "pixel scale" option. It currently defaults to "automatic", and will try to match the default game-native resolution supported by Wesnoth. There are also minimum and maximum resolutions that can be set in Wesnoth code, and it will try to respect these. All except the minimum resolution can be overridden by player preference.

These different coordinate systems are mostly supported by SDL's built-in "logical size" compatibility system. "logical size/scale/resolution" is equal to game-native resolution. In the case that output-size is not a perfect integer multiple of logical size (such as if the window size is odd by one or two pixels), an appropriate viewport is chosen automatically. This should be completely invisible to the game, but is accounted for in some of the compatibility code which pulls pixels from the render target.

SDL will automatically convert most relevant events and rendering calls (such as mouse events, pixel drawing calls, texture drawing calls etc) to and from logical resolution. As such, the vast majority of the game only ever needs to care about this resolution, and most existing code can continue to be used as-is.

Summary of coordinate systems

That was confusing, but in summary what it comes down to is:

The game uses "game-native", "drawing", "draw-space", or "input" coordinates. These are all the same, and equivalent to what the game was previously using.

There are also "window" coordinates which the game mostly doesn't need to care about, except for some systems dealing with raw input, window sizing/movement/resizing, and fullscreen resolution.

There are also "output" or "render" coordinates. These are what the final output of the game will use, but the game for the most part does not need to know or care about them. The only part that does is font rendering, so that text can be rendered by the game at the best size to use the full available resolution.

Different OS approaches to high-dpi

Different operating systems use different approaches to high-dpi rendering. I will try to list what i have learned, but let me know if anything is known to be incorrect as i only have one of these systems. Available information on this is understandably confused and often conflicting.

Linux (X11): Window size and output size are equal, and represent the full render-target resolution even in high-dpi contexts. Pixel scaling must be used to make the game playable on high resolution displays.
Linux (Wayland): Output size may be greater than window size, in high-dpi contexts. Window sizing and placement events use window size. Input events natively use window size, but are converted by SDL to use logical size where possible. Non-high-dpi-aware games will see output size as window size, and have their output scaled automatically.
Windows (OS scaling): If OS high-dpi scaling is used and the app isn't marked as high-dpi aware, the window size will be scaled by the OS scale factor. The game will render at this size, and the output will be automatically scaled.
Windows (high-dpi-aware): For apps marked as high-dpi-aware, window size will be output size. The app is responsible for scaling appropriately. Wesnoth is currently marked as high-dpi aware and will use pixel scaling automatically.
MacOS: Handling is similar to Wayland on Linux. Output size may be greater than window size, and window size is used for windowing events. I am not sure how rendering is handled natively, but SDL will translate draw events correctly using logical size.

Solutions to the original goals

In all cases SDL's logical size can be used as the game-native drawing and input resolution, with the occasional caveat mentioned above. Thus the original scaling goal has already been achieved, mostly by just setting SDL's logical size appropriately.

Hardware acceleration support can be achieved mostly by using textures to draw in stead of SDL surfaces. A lot of work was already done towards this goal back in 2018, and is still available in the "old_master_20181015" branch on github. Once the rendering compatibility layer is in place, most if not all of this will be able to be ported forwards.

High-dpi rendering support is mostly automatic using SDL's logical size adaptor. The only thing that will need to be aware of the difference is font rendering, which should be able to simply use the scale factor between output size and game-native drawing resolution to scale font sizes.

Work done and what needs doing

This post is already pretty long, but i'll add a quick summary of what has been done so far and what will need to be done in the future.

Done:
  • Add pixel scaling option, using SDL's built in "logical size" scaling support. It can be set in preferences, and will update immediately.
  • Choose pixel scale automatically if output size is too large. This can be disabled in preferences.
  • Add compatibility later for all old rendering calls.
  • Add new hardware-accelerated rendering interface.
  • Convert all old rendering calls to use the compatibility layer.
To do:
  • Convert fonts to render in high-dpi, and display using the new interface.
  • Convert all old drawing systems to use textures in stead of surfaces.
The last to-do will likely be ongoing work for some time. However with the compatibility layer in place, it should be able to be done piece by piece with minimal disruption to other systems while in progress.
entonio
Posts: 7
Joined: February 1st, 2019, 12:09 am

Re: New Graphics System Details

Post by entonio »

Impressive work, thank you.

Will this allow something to the same effect as the pre-1.13 choice of resolution in fullscreen mode? I'm the kind for which Wesnoth is only comfortable if it looks like 1280x720 on a 27".
User avatar
doofus-01
Art Director
Posts: 4121
Joined: January 6th, 2008, 9:27 pm
Location: USA

Re: New Graphics System Details

Post by doofus-01 »

There is a "pixel scale multiplier" option that probably doesn't directly solve your problem, but it does at least allow some control over resolution in full screen. It's on "auto" by default, and doesn't seem to do much outside of full screen, so it might be worth testing out.
BfW 1.12 supported, but active development only for BfW 1.13/1.14: Bad Moon Rising | Trinity | Archaic Era |
| Abandoned: Tales of the Setting Sun
GitHub link for these projects
entonio
Posts: 7
Joined: February 1st, 2019, 12:09 am

Re: New Graphics System Details

Post by entonio »

Thank you. That works well enough. A non-integer multiplier might be better, but aiui that's not doable.
Post Reply