Opened 13 years ago

Closed 7 years ago

Last modified 13 months ago

#8578 closed patch (outdated)

new Edge3x/2x filter

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


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 13 years ago.
diff to add new Edge3x/2x anti-aliasing resizer filter

Download all attachments as: .zip

Change History (7)

by SF/ewelsh42, 13 years ago

Attachment: edge3x.dif added

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

comment:1 by sev-, 13 years ago

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

comment:2 by fingolfin, 13 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, 13 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, 7 years ago

Resolution: outdated
Status: newclosed

comment:5 by bluegr, 7 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, 13 months ago

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