N64 programming (libdragon)

Discussion of development of software for any "obsolete" computer or video game system. See the WSdev wiki and ObscureDev wiki for more information on certain platforms.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: N64 programming (libdragon)

Post by calima »

N64 interest is picking up ;) Sadly it will be a while still before I have enough time.

Things I was going to bench:
- various compression algos
- opus at normal bitrates (64kbps mono and 96kbps stereo), how much of a frame does it take
- openal-soft to see how 3d audio sounds on it, and how much does the mixing take (it's not usable in embedded commercial projects, though that may change)

Maybe you want to try some of these? Opus is the current leading codec, better quality than Vorbis.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: N64 programming (libdragon)

Post by calima »

Oh, I was also going to try a few video codecs at several bitrates and resolutions, to have a baseline for what could be done with FMVs given modern tech. Mpeg1, mpeg2 and the simple xvid profiles, at 640x480 and 320x240, a few bitrates. Mpeg1 is patent-free, last I checked so was mpeg2, mpeg4 would take some years but if the simple profiles are workable, you could just create a custom codec based on the ideas.

Things like the older, indexed-color RAD codec would certainly work. I have read the RE2 article, where they achieved 15fps at reduced resolution and 16-bit colors IIRC, but they were under severe space constraints, and only used the GPU for colorspace conversion. Theora would be too heavy, based on quick tests on x86.
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: N64 programming (libdragon)

Post by lidnariq »

Once I started looking into what's involved in N64 dev I became tempted to port Rockbox...

Rockbox was ported to at least one MIPS-based portable music player, and they have some audio codec benchmarking data:
https://www.rockbox.org/wiki/CodecPerfo ... rison#MIPS
BMBx64
Posts: 25
Joined: Thu May 25, 2017 7:27 am

Re: N64 programming (libdragon)

Post by BMBx64 »

calima wrote:N64 interest is picking up ;) Sadly it will be a while still before I have enough time.

Things I was going to bench:
- various compression algos
- opus at normal bitrates (64kbps mono and 96kbps stereo), how much of a frame does it take
- openal-soft to see how 3d audio sounds on it, and how much does the mixing take (it's not usable in embedded commercial projects, though that may change)

Maybe you want to try some of these? Opus is the current leading codec, better quality than Vorbis.
More people interested on N64 scene could be great :D , main problem with the audio is the lack of threads on libdragon and the lack of RSP support (for fast mixing audio instead of the CPU), i guess these things could be implemented with time.

I made an example of the flipping feature, replicating a bit the effect of Iridion 3D (GBA) which indeed uses a small portion of the screen, then the tiles are mirrored.
Image

The GBA uses a small area then scrolls, so i had to set 256x240 with black borders.
Image

The sprites are sets of 172x8 loaded only once on TMEM to be mirrored, it seems it takes a bit to load, they are 480 files and about 1,30MB for the full animation (16bit textures yet), i may find a method to speed up this.

The example looks like this
Image

DOWNLOAD
https://mega.nz/#!NowTCZiR!zjdeRzSzBwgw ... fheN_Z8p1Q

I did a second build of SOTN OST, in case the problem is solved (here both versions works fine)
https://mega.nz/#!k9hGEDqS!CR53Lh-wb07- ... nxmr7k5kgE
ccovell
Posts: 1045
Joined: Sun Mar 19, 2006 9:44 pm
Location: Japan
Contact:

Re: N64 programming (libdragon)

Post by ccovell »

Very lovely, the work that you're doing.
User avatar
nicklausw
Posts: 376
Joined: Sat Jan 03, 2015 5:58 pm
Location: ...
Contact:

Re: N64 programming (libdragon)

Post by nicklausw »

That looks absolutely amazing.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: N64 programming (libdragon)

Post by Drew Sebastino »

It's nice to see 2D stuff on the N64 for once. How feasible would a fully functional 16x16 tile tilemap would be, with different graphics and flipping options per tile? I'd have thought you could do 16 layers or something like that if you wanted to until you posted the large explosion demo.
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: N64 programming (libdragon)

Post by lidnariq »

BMBx64 wrote:they are 480 files and about 1,30MB for the full animation (16bit textures yet), i may find a method to speed up this.
The default timing on the parallel interface "only" affords ≈6MB per second. You can change it to be more aggressive, up to whatever limits your dev hardware supports.
BMBx64
Posts: 25
Joined: Thu May 25, 2017 7:27 am

Re: N64 programming (libdragon)

Post by BMBx64 »

Thanks :)

Im progressing very slowly, but i have added another feature.

CONTROL POINTS
This function brings a virtual center to X/Y coordinates plus support for multiple join sprites, mirrored sprites are aligned, the scaled textures will attempt to align equally but right now there is a small problem with precision.

Textures on libdragon are 0,0 aligned, left pic, on the center the animation using custom coords for X/Y axis, the right pic shows the number of rectangles, sometimes they can fit TMEM (32x64) or split in parts.
Image

So i did 2 functions, with or without scale, since the last one does more stuff and its slower, these are internal so the real x/y coords from the user won't be affected.

Code: Select all

void rdp_cp_sprite( int x, int y, int flags, int cp_x, int cp_y, int line );
void rdp_cp_sprite_scaled( int x, int y, double x_scale, double y_scale, int flags, int cp_x, int cp_y, int line );
When line is set to 1 the sprite follows the last one without the need to figure the coords.

Program example:
Image

CONTROLS
A - Mirror horizontally
B - Mirror vertically
Z - Delays animation 1 second
L - Stops animation for a while
C up/dowm - Scale Y
Dpad - Joysticks - Moves the reference pointer

DOWNLOAD
https://mega.nz/#!s0ATnZga!IdDcgNhDe8j1 ... FXlAFuXN_A
---

Other things i would love to add, at least i want the RDP to draw them:
- Alpha blending for textures
- Alpha blending for colors (for fade on/fade off screen or other effects)
- Rotating Sprites
- Fix RDP Sprite Scale X
- Raster effects X/Y (Mega Drive style)
- Additive Blending (do the color mixing with the CPU then draw with RDP if this isnt supported), i already did a pc test, but i have to port the code.
Image

---
Espozo wrote:It's nice to see 2D stuff on the N64 for once. How feasible would a fully functional 16x16 tile tilemap would be, with different graphics and flipping options per tile? I'd have thought you could do 16 layers or something like that if you wanted to until you posted the large explosion demo.
The problem is that the results has been inconsistent, i could have a test running at 60fps while showing 1004 sprites of 16x32, then just change a variable to "static" and now the results are 928 sprites instead of 1004 even if that variable have no use ¿?, i have to look at the compiler options and do more research, or if anyone have clues about this i can look into it.

I think 4bit textures could be faster than 16bit ones, on my tests N64 likes to fill TMEM with more data and do less calls, i think is good idea use 16x16 on the main layer and 32x32 or even 64x32 on background ones.

Nintendo for example used 64x64 on the backgrounds (Yoshis Story):
Image
lidnariq wrote:The default timing on the parallel interface "only" affords ≈6MB per second. You can change it to be more aggressive, up to whatever limits your dev hardware supports.
Do you know the memory address to change that or a bit more of info?
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: N64 programming (libdragon)

Post by lidnariq »

BMBx64 wrote:The problem is that the results has been inconsistent, i could have a test running at 60fps while showing 1004 sprites of 16x32, then just change a variable to "static" and now the results are 928 sprites instead of 1004 even if that variable have no use ¿?, i have to look at the compiler options and do more research, or if anyone have clues about this i can look into it.
The CPU speed on the N64 is going to be heavily influenced by whether things fit into its L1 cache or not. (and the L1 cache is only 24 KiB). You'll probably get better results from compiling with GCC's -Os than any other kind of optimizations.
Do you know the memory address to change [parallel interface timing] that or a bit more of info?
Public documentation? There's not much useful. There are four registers for each of two different memory regions on the cart. Libdragon barely mentions this at all; only in passing in the linker script.

This page: http://n64.icequake.net/mirror/www.crazynation.org/N64/ has a bit of low level information about, particularly:
The first word read is in the cart header address 0 [0x80371240] which sets the bus speed for subsequent cart access.
If you set it to 0x8037FF40 then the access timings for loading the boot code at 0x40 in the header would look like the first access at 0, where the read low signal was 4.0us. Can be useful for debugging since all bus activity is slowed down but still functional.
The IPL inside the PIF instructs the CPU to copy those four bytes to the registers at ... uh, ultimately, 0x04600014, 0x04600018, 0x0460001C, and 0x04600020. I guess libdragon's default MMU setup offsets the addresses to 0xA4600014 &c.

These registers that configure the speed of the PI should be part of libdragon's PI_regs_s structure (the one that initiates DMA) but, for whatever reason, are omitted. Possibly because it is easy to choose timings that are too aggressive? Supposedly no games ever change the defaults.

All I know is that the ones that are actually counts are measured in terms of FSB clocks (i.e. 1/62.5MHz = 16ns), so that 0x12 = (18+1)·16=304 ns that /RD or /WR stays low.
mic_
Posts: 922
Joined: Thu Oct 05, 2006 6:29 am

Re: N64 programming (libdragon)

Post by mic_ »

Cool. You should think about doing a pull request to get your routines merged into libdragon (if you haven't already done so).
BMBx64
Posts: 25
Joined: Thu May 25, 2017 7:27 am

Re: N64 programming (libdragon)

Post by BMBx64 »

lidnariq thanks for the info.
mic_ wrote:Cool. You should think about doing a pull request to get your routines merged into libdragon (if you haven't already done so).
I could try, but most of his files are 5 years old on github though.

Also i found a more updated libdragon by Chilly Willy as well, it seems he added mouse support for the Doom port, he did also an example of ADPCM using the RSP.

If anyone is interested his libdragon can be found here (12-11-2014):
http://krikzz.com/forum/index.php?topic ... 6#msg24116
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: N64 programming (libdragon)

Post by lidnariq »

I've looked into this a little more. An augmented PI_regs_s structure, adding the registers that you "shouldn't"(??) touch:

Code: Select all

typedef struct PI_regs_s {
    /** @brief Uncached address in RAM where data should be found */
    volatile void * ram_address;
    /** @brief Address of data on peripheral */
    uint32_t pi_address;
    /** @brief How much data to read from RAM into the peripheral */
    uint32_t read_length;
    /** @brief How much data to write to RAM from the peripheral */
    uint32_t write_length;
    /** @brief Status of the PI, including DMA busy */
    uint32_t status;

    /* (Number of FSB cycles)-1 after ALE_L falls before /RD or /WR
       falls. Default value loaded from the ROM header: 0x40 -> 1040ns */
    uint32_t rom_time_after_address_latch;

    /* (Number of FSB cycles)-1 after /RD or /WR falls before it rises
       again. Default value loaded from the ROM header: 0x12 -> 304ns */
    uint32_t rom_time_during_read_or_write;

    /* When the address autoincrement behavior would cause a carry-out into
       this (address line)+1, PI must manually load address (e.g. 0=two
       reads; 15=65536 reads). Default value from the ROM header: 7 ->
       perfectly-aligned DMA transfers will permit 256 reads at a time
       before the hardware must load a new address. */
    uint32_t rom_autoincrement_address_bits;

    /* no idea what this does. Random guess: amount of time /RD or /WR is
       high between reads? Default value from ROM header: 3 ( -> 64ns??) */
    uint32_t rom_dunno;

    /* same as above four, but for the address region on the cart where
       parallel-accessed save memory is kept */
    uint32_t ram_time_after_address_latch;
    uint32_t ram_time_during_read_or_write;
    uint32_t ram_autoincrement_address_bits;
    uint32_t ram_dunno;
} PI_regs_t;
mic_
Posts: 922
Joined: Thu Oct 05, 2006 6:29 am

Re: N64 programming (libdragon)

Post by mic_ »

I could try, but most of his files are 5 years old on github though.
I think Shaun will respond if you do a pull request on github. I made one 9 months ago and IIRC he got back to me within a couple of days.
User avatar
mikejmoffitt
Posts: 1353
Joined: Sun May 27, 2012 8:43 pm

Re: N64 programming (libdragon)

Post by mikejmoffitt »

mic_ wrote:
I could try, but most of his files are 5 years old on github though.
I think Shaun will respond if you do a pull request on github. I made one 9 months ago and IIRC he got back to me within a couple of days.
I'm going to his house tomorrow, so I can whine at him to check the repository.
Post Reply