Opened 18 years ago

Closed 12 years ago

Last modified 6 years ago

#8578 closed patch (outdated)

new Edge3x/2x filter

Reported by: SF/ewelsh42 Owned by:
Priority: normal Component: Graphics: Scalers
Version: Keywords:
Cc: Game:


I have created a new anti-aliasing resize filter which I thought may be of interest to the ScummVM team. It includes a 3x and 2x nearest neighbor resizer, as well as a 2x interpolating resizer. It also detects when overlays are being drawn, such as the mouse, assumes that they have transparancy, and handles transparancy in a reasonable manner so that the anti-aliasing of mouse pointers looks good now (as compared to AdvMame). See the mouse pointer for Maniac Mansion for a good example. The overall image quality is higher than the AdvMame and HQ filters. More edges are anti-alised, fewer edge directions are mis-detected and anti-aliased in the wrong direction, and the shapes and shadings of the original image are better preserved. The new filters give sharpness without the common font edge direction misdetection artifacts of AdvMame, and good anti-aliasing without the common heavy blur of the HQ filters when they are unsure of how best to anti-alias a given pixel. The filters are also reasonably robust to various odd color and shading combinations that give the other filters difficulty. The improved image quality is worth the speed hit, at least to me.

Unfortunately, the improved accuracy comes at a hefty cost in speed. However, since many ScummVM supported games only redraw small amounts of the screen each frame, this is not so much of a problem. But the filter is slow enough that dirty rects still don't help it enough. To speed it up a bit more, the filter keeps local copies of the src and dst buffers so that it can do its own unchanged pixel detection and only redraw pixels that have actually changed between frames, even if a full screen refresh is requested due to color cycling, etc.. It detects all current instances of ScummVM writing to the screen outside of the filter and forces an internal full screen refresh when this occurs, so there should be no artifacts from messages, menus, etc. that get drawn outside of the filter. Unchanged pixel detection and skipping appears to be stable. The cached dst buffer lets it work with aspect ratio correction as well. If at any point this breaks in the future when ScummVM writes outside the filter in a way that the filter does not expect, unchanged pixel skipping can be disabled by simply setting the skip_unchanged_pixels_flag variable in the filter to 1, or figuring out what new case to check for in the function that contains the flag.

With the unchanged pixel detection, most games are smoothly playable for me on my 1.53 GHz Athlon. Full screen pans can get a little jerky, but they still aren't too bad. Modern CPUs should have no problems.

I have attached a diff of the changes, made from a snapshot a few months ago. I applied it to a fresh svn download tonight, and it patched and compiled without errors, so it should still be fine. Minimial changes were made to all of the existing files, just what was required to add basic support of a new filter. The new filter is included in graphics/scaler/edge3x.cpp. See code comments for better descriptions of the edge detection algorithms used, handling of transparancy, unchanged pixel skipping, etc.. The code enclosed in DEBUG defines can be removed, but I thought I would leave it in there for now, as those defines can be very interesting for visualizing which pixels are changing between frames and seeing the outlines of dirty rects.

The default hot-keys are ctl-alt-9, and ctl-alt- +/- switch between the 2x interpolating resizer and the 3x nearest neighbor resizer. It is impossible for a 2x nearest neighbor resizer to get diagonals correct, which is why I chose to default it to the 2x interpolating resizer instead of nearest neighbor.

I forsee the following objections being raised against including this filter in ScummVM:

We don't need yet another filter And I thought HQ3x was slow.... Unchanged pixel detection is a bit of a hack Transparancy handling is also a bit of a hack

I don't necessarily disagree with the last three of those, but I think that the much increased image quality at least warrants giving it a try before turning it down.

Ticket imported from: #1574256. Ticket imported from: patches/683.

Attachments (1)

edge3x.dif (141.4 KB ) - added by SF/ewelsh42 18 years ago.
diff to add new Edge3x/2x anti-aliasing resizer filter

Download all attachments as: .zip

Change History (7)

by SF/ewelsh42, 18 years ago

Attachment: edge3x.dif added

diff to add new Edge3x/2x anti-aliasing resizer filter

comment:1 by sev-, 18 years ago

Summary: new Edge3x/2x resize filter submittednew Edge3x/2x filter

comment:2 by fingolfin, 18 years ago

No scalers are likely to be accepted. Even if that wasn't the case, this patch as it is would not be acceptable due to the hacks it uses. Like messing with the backend settings -- that is not the way to do it.

The auto-dirty-rects code indeed is far from optimal. And on modern machines, detecting changes by keeping a copy of the full frame buffer is possible (memory and mem speed limitations are mostly gone)... But that should be implemented in the backend, not the scaler. I.e. the backend should manage this (and the scaler funcs would need a new additional param, pointing to the content of the "old" screen). You might want to work on such a patch first, if this new scaler needs it to work with acceptable speeds...

comment:3 by SF/ewelsh42, 18 years ago

It doesn't touch the backend settings at all, all the hacks are in the filter itself to work around things that aren't currently in the backends (such as passing transparent overlay information and buffering the screen). No hacks are made to the backends, nor are any backend settings changed or even read, it is all internal to the filter itself. Everything is done by detecting different behaviors, such as the src address being outside the bounds of what the filter guesses to be the full src screen (must be drawing a transparent overlay), the scale, screen dimensions, or overlay dimensions change (resolution change, mouse pointer change like in Sam and Max, drawing messages outside the filter, etc.). I figured it would be "cleaner" to keep the work arounds in the filter, rather than modify the backends and then have to modify all the other filters to work with the new filter parameter passing conventions. I agree that adding buffering and transparancy flags to the backends that get passed as extra filter parameters would be the "right way" to do things, but again, I thought it would be cleaner to just keep it all self-contained in the filter to minimize changes elsewhere. It doesn't do anything to the backends, it just detects some behaviors that, if they change in future builds, may break the filter. Even though they are hacks, they are still pretty stable, they've been working ever since the big change was made in the backends a while ago to draw the original screen and overlays/menus separately, rather than render everything to the screen directly and then apply the filters to the final product (this change led to the need for all the hacks, the transparent pixel handling, etc.). If the filter had a chance at being accepted, I'd modify at least the SDL backend to move stuff out of the filter and into the backend and do things the right way, but since no new filters are likely to be accepted, keeping it self-contained makes it far simpler for me to patch the latest src and not worry about having to continually modify backend changes every time the backends undergo a major revision, or continually having to repatch all the other filters to support new scaler function prototypes with additional paramaters.

If no new filters are likely to be accepted, and the other filters don't really need the features in the backends that my work arounds provide, then I guess there's not much need to add that extra functionality to the backends. It might be nice to add transparency info to the filter arg passing, though, and modify the existing filters to edge detect transparent pixels similar to how I handle it so that transparent pixels provide maximal contrast and thus a more correct edge detection than just using whatever the color chosen to be transparent happens to be. Mouse pointers would look a lot better that way.

I'd hoped the filter might have a chance at being accepted, even with some of the workarounds, since it really looks much better to me than the existing filters (which bugged me enough to make me want to develop this filter in the first place). Oh well, at least someone might still download the patch, try it out, and be happy with the results. Or maybe it can inspire the other filters to have their transparent pixel handling improved so that mouse pointers look better :)

comment:4 by bluegr, 12 years ago

Resolution: outdated
Status: newclosed

comment:5 by bluegr, 12 years ago

As suggested by singron, this has been added in his GSoC pull request here:

Thus this patch is now obsolete, and will be eventually merged together with the rest of singron's changes.

Closing as out of date, and changing the group to GSoC

comment:6 by digitall, 6 years ago

Component: Graphics: Scalers
Note: See TracTickets for help on using tickets.