Something that seems impossible to do in C

SGDK only sub forum

Moderator: Stef

Post Reply
tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Something that seems impossible to do in C

Post by tryphon » Wed Mar 23, 2016 9:27 pm

I'm studying how to optimize "dynamic" sprites (sprites whose patterns are dynamically loaded in VRAM at each frame).

Shadow Dancer uses a list of VDP commands, stored in ROM. For example, for Musashi at address 0x1ADA6, you'll find :

Code: Select all

0003 // number of chunks of commands
9330 9400 9580 96C9 977F 74000083 // chunk 1
9380 9400 95B0 96C9 977F 74600083 // chunk 2
9300 9401 9530 96CA 977F 75600083 // chunk 3
The 93xx 94yy give the number of patterns and the 95aa 96bb 97cc give the address in ROM (or RAM in this case, because Musashi patterns are Nemesis compressed, but it's not the case of the ennemies) where the patterns are stored. The last long word activates the DMA and give the VRAM pos. For Musashi, the VRAM loation is always the same but for ennemies the command long word is adjusted at runtime according to the ennemy slot.

These commands are then sent to the VDP control port during VINT. I find it clever and fast.

I want to do the same with my SGDK-written engine but I encountered an unexpected problem.

When I want to generate the command table, I first declare my patterns array :

Code: Select all

const u32 patterns[] = {
    0x00024666,
    // ... some 100ths of lines
};
Then I declare my command table (for the sake of simplicity, there will be only one entry of length 1) :

Code: Select all

const u16 temp[] = {
    0x9370, 
    0x9400, 
    0x9500 + ((patterns >> 1) & 0xFF), 
    0x9600 + ((patterns >> 9) & 0xFF), 
    0x9700 + ((patterns) >> 17) & 0xFF)
};
I get an error at compilation time :

Code: Select all

error: invalid operands to binary >>
error: initializer element is not constant
or, if I cast patterns as a u32 :

Code: Select all

warning: initializer element is not computable at load time
error: initializer element is not computable at load time
I asked a question on stackoverflow and it turrned out that a >> and a & are forbidden when declaring constants (even if it involves only constants and thus is actually computable at link time).

Two suggestions were made :

1) declaring the array with the right size but null data, then using a script after the compilation time that reads the symbol table and modify the binary file to put the right values in the table

2) playing with the linker scripting language

Solution 2) may be cleaner, but I know nothing about the linker scripting language. I don't see many difficulties in using 1), but I'd like to automatize the process. How can I specify in the makefile that a certain python script should be used on the binary output file after it and the symbol.txt have been created ?

Or do you see a better option ?

cero
Very interested
Posts: 339
Joined: Mon Nov 30, 2015 1:55 pm

Re: Something that seems impossible to do in C

Post by cero » Thu Mar 24, 2016 8:28 am

Initialize your command array in RAM at the start of main. It's small, there's no difference really to having it in RAM vs ROM.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Something that seems impossible to do in C

Post by Stef » Thu Mar 24, 2016 8:49 am

That's exactly what is doing the new DMA unit from SGDK :
https://github.com/Stephane-D/SGDK/blob ... /src/dma.c

It basically queues your DMA commands in RAM then send them at V-Int time to maximize DMA bandwidth.

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Re: Something that seems impossible to do in C

Post by tryphon » Thu Mar 24, 2016 10:29 am

Since I must do that for every type of dynamic objects in the level, I was afraid to run out of RAM (I evaluate it to around 10 - 20 kB per level).
Stef wrote:That's exactly what is doing the new DMA unit from SGDK :
https://github.com/Stephane-D/SGDK/blob ... /src/dma.c

It basically queues your DMA commands in RAM then send them at V-Int time to maximize DMA bandwidth.
Not exactly in fact : they are precomputed before they are even needed, while your module, if I understand correctly, compute the control port data at runtime but delay they execution until V-Int.

What I was doing before was much worse, since I queued only pos in ROM and VRAM, and called VDP_loadTile during V-Int with DMA flag set.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Something that seems impossible to do in C

Post by Stef » Thu Mar 24, 2016 1:32 pm

I was referring the fact you could put it in RAM but indeed that is not exactly the same.
Still the point for me is to maximize the VRAM bandwidth, CPU time in active period is not an issue so you can easily compute the transfer blocks for each frame as the DMA queue system is actually doing :)

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Re: Something that seems impossible to do in C

Post by tryphon » Thu Mar 24, 2016 10:11 pm

I'm under the impression that collision checking can take a large amount of CPU time when you have a lot of objects (hence my other thread). But I get your point and it's clever.

Post Reply