NEON scalers


M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
Hi,

I implemented various scalers with following properties:
- written in pure assembler
- uses ARMv7 and NEON instructions
- uses instruction scheduling for Cortex-A8 processors
- no checking for corectness of parameters
- no clipping
- MIT license

Implemented scalers: normal1x, normal2x, normal3x, normal4x, scale2x, scale3x, scale4x, eagle2x

The library and source code is available in the archive.
The source code is available on GitHub.

Edit (2012-11-19):
Known use:
GPFCE - NES emulator (uses: scale2x, eagle2x)
gpSP - GBA emulator (uses: scale2x, scale3x, eagle2x)
PCSX ReARMed - PlayStation emulator (uses: scale2x, eagle2x)
 
Last edited:

EvilDragon

Administrator
Staff member
Joined
Mar 4, 2003
Messages
29,597
Age
43
Location
Ingolstadt
Wooooaa!


Scale4x and the likes with NEON and assembler?


Awesome work, thanks a lot :D
 

Garrett

Advanced Member
Joined
Aug 24, 2011
Messages
1,255
Location
Workington, Cumbria, UK
Is this as exciting as it sounds? (thanks M-HT)


can these now be incorporated in all the emulators/games that currently don't scale to the Pandora's full screen?


If so.. happy days!!
 

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
can these now be incorporated in all the emulators/games that currently don't scale to the Pandora's full screen?
This library is meant as faster versions of the scalers. Any program can use it, but these scalers only scale to integer factors (2x, 3x, 4x) so the result probably won't fill Pandora's full screen.
 

milkshake

Advanced Member
Joined
May 18, 2009
Messages
3,735
Age
36
Location
Rotherham, UK
surly it could be converted to use floats? instead of Integers? im assuming that will slow it down somewhat? but I though that what neon was good at ? floating point calculations?
 

pmprog

DNF (Did Not Finish)
Joined
Apr 25, 2011
Messages
4,099
Should be very useful for The Collector Plus. Thanks :)
 

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
surly it could be converted to use floats? instead of Integers? im assuming that will slow it down somewhat? but I though that what neon was good at ? floating point calculations?
These scalers only compare pixels for equality, they don't perform any calculations (ie. interpolation) upon them, so there's no difference between floats and integers - only thing that matters is the number of bits per pixel.


Neon is also good for processing multiple data with single instruction.


With 8 bits per pixels 16 pixels are processed at once.


With 16 bits per pixels 8 pixels are processed at once - two times slower than 8 bits per pixel.


With floats (32 bits per pixel) 4 pixels would be processed at once - two times slower than 16 bits per pixel.
 

EvilDragon

Administrator
Staff member
Joined
Mar 4, 2003
Messages
29,597
Age
43
Location
Ingolstadt
Well, but using Scale2x or Eagle2x and then using the hardware scaler to make it fit the Pandora screen might look pretty awesome with some emulators :)
 

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
Obvious question is why the emulators aren't they doing it already. :)


If it's because it slows down the emulation, then I hope that my implementation is fast enough.
 

Exophase

Nothing good will ever come of Exophase.
Joined
Sep 21, 2006
Messages
10,308
Age
37
Location
Cleveland OH
These scalers only compare pixels for equality, they don't perform any calculations (ie. interpolation) upon them, so there's no difference between floats and integers - only thing that matters is the number of bits per pixel.
Neon is also good for processing multiple data with single instruction.


With 8 bits per pixels 16 pixels are processed at once.


With 16 bits per pixels 8 pixels are processed at once - two times slower than 8 bits per pixel.


With floats (32 bits per pixel) 4 pixels would be processed at once - two times slower than 16 bits per pixel.
Even worse, 32x4 FP32 compare issues in two cycles, while 32x4 integer compare issues in one. Although you can sometimes compare floats using integer compare.
 

mcobit

Advanced Member
Joined
Jul 28, 2008
Messages
6,910
Is this meant as a drop in replacement for other scale2x/3x filters?


I'd like to integrate those faster implementations into panmame, if I can. Would you help me a bit, if I run into troubles there?


Edit: And of course thank you for taking the time to write those, definately no easy job.
 
Last edited by a moderator:

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
Is this meant as a drop in replacement for other scale2x/3x filters?
There are (probably) different input parameters and the input conditions must be met, but yes.


If you need different input parameters, parameter checking, cliping, etc. you can write wrappers for my functions, but that shouldn't be a problem.

I'd like to integrate those faster implementations into panmame, if I can. Would you help me a bit, if I run into troubles there?
Yes.
 

notaz

Certified Guru
Joined
Aug 23, 2005
Messages
4,913
Location
Lithuania
Website
notaz.gp2x.de
Integrated these into gpfce today, a few comments:


some older versions of GCC want comma before :alignment, or else:



Code:
drivers/arm/neon_scale2x.S:253: Error: ']' expected -- `vld1.16 {q9},[ip:128]!'


.include doesn't work well if source files are not in working directory:



Code:
arm-none-linux-gnueabi-gcc -mcpu=cortex-a8 -mfpu=neon   -c -o drivers/arm/neon_scale2x.o drivers/arm/neon_scale2x.S

/tmp/cc27EDXa.s: Assembler messages:

/tmp/cc27EDXa.s:29: Error: can't open neon_scale2x.Sinc for reading: No such file or directory
while #include does.


Finally, that 32bit palette with 16bit values is rather inconvenient to use, I assume you wanted to avoid address generation complexity and larger load latency?
 

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
Integrated these into gpfce today, a few comments:
You're the first one to use them (that I know of). It's good to know that I didn't waste my time creating them :) .

some older versions of GCC want comma before :alignment, or else:



Code:
drivers/arm/neon_scale2x.S:253: Error: ']' expected -- `vld1.16 {q9},[ip:128]!'
The GCC I'm using (4.6.1) doesn't accept comma before :alignment and newer versions are probably the same.



.include doesn't work well if source files are not in working directory:



Code:
arm-none-linux-gnueabi-gcc -mcpu=cortex-a8 -mfpu=neon -c -o drivers/arm/neon_scale2x.o drivers/arm/neon_scale2x.S

/tmp/cc27EDXa.s: Assembler messages:

/tmp/cc27EDXa.s:29: Error: can't open neon_scale2x.Sinc for reading: No such file or directory
while #include does.
I didn't realize that. When deciding between #include and .include, I decided to use .include, because that allows the file to be compiled without C preprocessor.



Finally, that 32bit palette with 16bit values is rather inconvenient to use, I assume you wanted to avoid address generation complexity and larger load latency?
I wanted to use only one instruction for loading value from palette:



Code:
ldr value, [palette, pixel, lsl #2]
With 16bit palette, more instructions are needed.



You can write a wrapper if you like, such as this:



Code:
void neon_scale2x_8_16_wrapper(const uint8_t *src, uint16_t *dst, const uint16_t *palette, unsigned int width, unsigned int srcstride, unsigned int dststride, unsigned int height)

{

uint32_t palette2[256];

int i;

for (i = 0; i < 256; i++) palette2[i] = palette[i];


neon_scale2x_8_16(src, dst, palette2, width, srcstride, dststride, height);

}
If you're calling the scaler once per blit, the overhead is negligible.
 

notaz

Certified Guru
Joined
Aug 23, 2005
Messages
4,913
Location
Lithuania
Website
notaz.gp2x.de
The GCC I'm using (4.6.1) doesn't accept comma before :alignment and newer versions are probably the same.
Are you sure? I took latest linaro release and it works here:



Code:
$ arm-linux-gnueabihf-gcc -v

...

gcc version 4.7.2 20120731 (prerelease) (crosstool-NG linaro-1.13.1-2012.08-20120827 - Linaro GCC 2012.08)

$ echo 'vld1.16 {q9},[ip, :128]!' > test.s

$ arm-linux-gnueabihf-gcc -c test.s -o test.o

$ arm-linux-gnueabihf-objdump test.o

00000000 <.text>:

   0:    f46c2a6d     vld1.16    {d18-d19}, [ip :128]!
 

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
You're right.


I was putting the register with alignment in a macro call - that didn't work because the macro was taking it as two parameters instead of one.
 

notaz

Certified Guru
Joined
Aug 23, 2005
Messages
4,913
Location
Lithuania
Website
notaz.gp2x.de
I've also noticed you don't use preload (pld instruction) at all, this gave a good improvement to my SDL blitters because Cortex-A8 doesn't have streaming detection (A9 does). Preloading around 2 cachelines ahead of time did a good job there. I tried to illustrate this on your code but strangely it had no positive effect even on test buffers way larger than L2 cache size. Strange.
 
Last edited by a moderator:

M-HT

Very Active Member
Joined
Nov 30, 2007
Messages
626
Location
Bratislava
Website
github.com
I did some tests with using pld instruction in some scalers, but it was slower than the version without using them, so I didn't use the instruction in any scaler. Either I didn't use the instruction properly or it has no effect in my implementation.
 
Top