Running scalers on DSP


I wanted to try a different approach so I first took hq2x (running on cpu) and optimized it (using some ideas from dsp version and using arm/neon assembly).
The unoptimized version takes 38.6 ms to scale 320x240 16-bit image. The optimized version takes 16.5 ms. The optimized source is in the attachment, in case someone is interested.
Then I rewrote the dsp version to work from bottom to top (instead of from top to bottom like the arm version).
Afterward I let the dsp and arm version run in parallel, stopping when they met somewhere in the middle.
The resulting time was about 8.5 ms to scale the image. Adding the time to invalidate caches and copy the result from dsp version to form a full scaled image, the result was about 10.5 ms.

At 60fps that's still not really useful on original Pandora (leaving about 5ms per frame for the rest of the program), but you could make an easily used library which hides (almost) all dsp work from the programmer.
It also shows that the task running on dsp doesn't have to be a separate task running asynchronously from the main cpu - in some cases you can split your data in two parts and process them in parallel (on dsp and the main cpu).

View attachment 12374
 
I wanted to try a different approach so I first took hq2x (running on cpu) and optimized it (using some ideas from dsp version and using arm/neon assembly).
The unoptimized version takes 38.6 ms to scale 320x240 16-bit image. The optimized version takes 16.5 ms. The optimized source is in the attachment, in case someone is interested.
Then I rewrote the dsp version to work from bottom to top (instead of from top to bottom like the arm version).
Afterward I let the dsp and arm version run in parallel, stopping when they met somewhere in the middle.
The resulting time was about 8.5 ms to scale the image. Adding the time to invalidate caches and copy the result from dsp version to form a full scaled image, the result was about 10.5 ms.

At 60fps that's still not really useful on original Pandora (leaving about 5ms per frame for the rest of the program), but you could make an easily used library which hides (almost) all dsp work from the programmer.
It also shows that the task running on dsp doesn't have to be a separate task running asynchronously from the main cpu - in some cases you can split your data in two parts and process them in parallel (on dsp and the main cpu).

View attachment 12374

Looks nice. I'll try to implements the scaler in Xargon as a POC.
 
I forgot to mention it, but some restrictions/requirements for the arm version of hq2x are:
- width must be at least 8 and it must be divisible by 4
- height must be at least 2
- the palette is an array of 256 16-bit values and it must be aligned to 16-bits (2 bytes)
The dsp version has stricter requirements, so the combined version does too.


Care to change the main function here to match the same prototype you're using in your neon optimised scalers ? (and add it to the bundle ?)
I can change it to use the same prototype, I can change it to use the same palette format (array of 256 32-bit values, upper 16 bits are zero), I can relax the restriction that width must be divisible by 4, but adding it to the bundle - no.
The neon optimised scalers use MIT license.
The hq2x uses LGPL 2.1 or later (or GPL 2 or later).

I can make a separate release, although I should also optimize hq3x and hq4x to have it all together. It could be usable on Pyra, if not on Pandora.
 
Oh sorry, I havent checked the licences :(
The only reason why i'm requesting the same prototype is that i'm using function pointers to switch between filter in spi.snes.
I'm fine with the currents restrictions but the palette. I'll need to investigate this before using.

Next time i'll use your work before suggesting improvements especially when they doesnt make sense.

BTW: after having a quick look at your work here, I'm having an idea how "fun" it will be to optimize hq3x... no rush (I've no use for this in mind)
 
Whoops. In my hq2x implementation (dsp and arm) I'm using rgb565 format, although the native (SDL) format is bgr565. I should change it (make it configurable).
 
So I made the color format configurable. It can be selected in file hqx-format.h (one format is used both for input and output).
I also noticed that the conversion to yuv was different from the original hqx algorithm, so I changed that.

Following releases are in the attachments:
hqx-arm.zip:
Contains hq2x, hq3x, hq4x using only cpu, optimized for arm (Cortex-A8). The function prototypes are the same as my neon scalers.
It can also be compiled on non-arm platform and it's faster than the original hqx, but at least function yuv_diff (in hqx-common.c) should be optimized in assembler to get more speed.
Some results for 16-bit source (320x240) to 16-bit destination (on original Pandora):
hq2x - 16.4 ms
hq3x - 18.1 ms
hq4x - 25.2 ms

hqx-dsp.zip:
Contains hq2x, hq3x using dsp. Apart from above changes, I reduced the amount of used scratch memory a bit and made some minor changes. It also contains versions that work from bottom to top.
Some results (320x240):
hq2x 16 to 16 - 15.6 ms
hq2x 8 to 16 - 14.8 ms
hq3x 16 to 16 - 22.2 ms
hq3x 8 to 16 - 21.6 ms

hqx-dsp+arm.zip:
Contains hq2x, hq3x using cpu and dsp. The function prototypes are the same as my neon scalers, but must be first initialized using function dsp_hqx_initialize. Initialization can fail, so check the return value (0 = success, other value = error value). The width must be divisible by 8. Also contains compiled dsp part (file hqx_dsp_area3.out), so only arm part needs to be compiled. The file must be in current directory when calling dsp_hqx_initialize.
Some results (320x240):
hq2x 16 to 16 - 10.2 ms
hq2x 8 to 16 - 10.0 ms
hq3x 16 to 16 - 13.9 ms
hq3x 8 to 16 - 13.8 ms

View attachment hqx-arm.zip

View attachment hqx-dsp.zip

View attachment hqx-dsp+arm.zip
 
Last edited by a moderator:
Impressive! I might have to give a try @ incorporating this into GINGE to see if it gives a nice result.

Part of me kinda misses the GP2X hardware scalers just for transparency sake... would love to see a scaler that could be used to resize BOR mods made for PSP to the Pandora resolution, but now that I think about it, might be better off seeing how it's implemented in ppsspp and maybe working from there as it's not an integer scaling.
 
Part of me kinda misses the GP2X hardware scalers just for transparency sake... would love to see a scaler that could be used to resize BOR mods made for PSP to the Pandora resolution, but now that I think about it, might be better off seeing how it's implemented in ppsspp and maybe working from there as it's not an integer scaling.

What's wrong with OMAP3's scalers compared to GP2X one? They can also downscale.
 
 
Doesn't GP2X's only offer filtered scaling with YUV color space inputs? It was because of this that gpSP and Temper used simple software fixed-ratio interpolation.
 
Notaz: I might just not be t3h ub3r n3rd enough to fully understand the Pandora hardware still, just remember that Paeryn's SDL (I think...) could init to whatever resolution I threw at it, then even zoom in/out on stuff on demand if/when I wanted :)  Omap3's scalers may be perfectly capable of this, but I'm not sure how to do this myself...

Exophase: you're probably right there, fairly certain that it was just a coarse scaler...
 
Last edited by a moderator:
Notaz: I might just not be t3h ub3r n3rd enough to fully understand the Pandora hardware still, just remember that Paeryn's SDL (I think...) could init to whatever resolution I threw at it, then even zoom in/out on stuff on demand if/when I wanted :)  Omap3's scalers may be perfectly capable of this, but I'm not sure how to do this myself...

http://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=sdl_omap.git;a=blob;f=README.OMAP;hb=HEAD
...

EDIT: this is the second link of a stick in the pandora general section. You could have found it yourself. BTW, this sdl driver is now available by default on pandora, you dont even need to ship it in your PND, it'll just work
 
Last edited by a moderator:
Notaz: I might just not be t3h ub3r n3rd enough to fully understand the Pandora hardware still, just remember that Paeryn's SDL (I think...) could init to whatever resolution I threw at it, then even zoom in/out on stuff on demand if/when I wanted :)  Omap3's scalers may be perfectly capable of this, but I'm not sure how to do this myself...

Exophase: you're probably right there, fairly certain that it was just a coarse scaler...

The GP2X did have a fine scaler but only for a YUV layer and I don't think I ever got around to supporting it, the RGB scaler was a basic coarse one. By the looks of if to change the scaling on notaz's you change the env_var SDL_OMAP_BORDER_CUT and/or SDL_OMAP_LAYER_SIZE and re-call SDL_SetVideoMode(). My method worked nicely since I didn't have to go through the display driver (I just set the hardware registers directly) and was based on code I wrote outside of SDL. Though notaz's use of env_vars is a better way to add the functionality rather than my hack of adding extra functions.
 
I always thought it'd have been neat to see some emulators on GP2X use the YUV scaler. For platforms that used paletted graphics exclusively it would have been pretty cheap to keep things in YUV space by only doing the conversion when the palette is modified (and most of them didn't have a wide bredth of possible colors anyway so a LUT would suffice)

I was thinking about doing it for Temper but then Wiz rolled out and IIRC it didn't have that scaler anymore, so I lost the motivation.
 
I've an idea that the Pollux could scale it's YUV layer (but not the RGB), the best info I can find now is that it supported either nearest-neighbour or bilinear. Knowing GPH the Wiz probably didn't have the functionality in the drivers and I can't seem to find any info on it's registers so I don't know if anybody figured out how to do it.
 
Back
Top