Dynamically updating tiles in mode 7 BG tileset

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
User avatar
Señor Ventura
Posts: 233
Joined: Sat Aug 20, 2016 3:58 am

Dynamically updating tiles in mode 7 BG tileset

Post by Señor Ventura »

Greetings.


I'm trying to figure out ways of having more than 256 simultaneous tiles in mode7, but there are some issues about i would like to ask...

Since mode7 only can "see" 256 tile at a same time, Do the solution of using HDMA to update tileset registers could work?. How many Bytes per scanline needs a BG in mode 7 to read the transformation table in WRAM?.

If i'm not wrong, every tile in mode 7 has 2 Bytes inside the tileset registers, right?... so you need to interruptand then transfer 512 Bytes in order to have another 256 different tiles (if your already have these previously uploaded in VRAM).


If HDMA is slow, and it is also unusable, the only option is DMA + F-blanking, or instead of this, an external chip to do the work better than the DMA... right?.


In a context of scaling a background with no inclined perspectives, like an scenario of art of fighting 2...

Image



...I see two solutions here:



1º "EXTERNAL DMA" SOLUTION:

Image


2º SNES DMA ONLY:

Image
Myself086
Posts: 158
Joined: Sat Nov 10, 2018 2:49 pm

Re: Dinamically updating mode 7 BG tileset

Post by Myself086 »

Mode 7 has 128x128 tiles on its background layer.
Each tile is 1 byte in mode 7 instead of 2 bytes for other modes.
Each tile only has access to 256 characters.
Each character is 8x8 in size and 8bpp. So 64 bytes per character.

DMA and HDMA take 8 master cycle per byte.
VRAM is accessed by the PPU at a rate of 4 master cycles per byte per VRAM (there are 2) and I doubt it can be much faster with your external device.

If your external device works, you won't be able to transfer 16384 bytes during the vblank period.
If you want split screen, you'll need about 94 black lines between the 2 screens or about 47 black lines with your device.
User avatar
Señor Ventura
Posts: 233
Joined: Sat Aug 20, 2016 3:58 am

Re: Dinamically updating mode 7 BG tileset

Post by Señor Ventura »

Myself086 wrote: Tue Jan 04, 2022 9:33 amIf your external device works, you won't be able to transfer 16384 bytes during the vblank period.
If you want split screen, you'll need about 94 black lines between the 2 screens or about 47 black lines with your device.
It doesn't need to transfer 16384 Bytes of tiles because these are already stored in VRAM.

It only need to update the tileset of the group of 256 tiles (256 Bytes, then).


edit: The second example is inaccurate, cause it doesn't shows how big needs to be F-Blanking, but here is the idea.

In every scanline you have 16 pixels of F-Blanking(10 Bytes), plus the time that the beam regreats to the beginning (28 Bytes?), plus HDMA? (Does HDMA need the full 4 Bytes per scanline to read the transformation table from WRAM?).

38 Bytes per scanline means accumulate during 7 scanlines, but using the black borders, NOT F-Blanking the scanlines.

All of this without HDMA, and without external hardware...
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Dynamically updating tiles in mode 7 BG tileset

Post by Oziphantom »

you can not update VRAM out of a blanking period, at all, nothing can do it, the only way to get new data into VRAM is during blanking. You have 8 DMA channels so you can use HDMA to move 8 bytes per line into VRAM as long as it is sequential, so if you are changing the tile map, you could do

Code: Select all

DMA  0      1      2       3       4      5      6       7
LINE AddrLo AddrHi tileNum tileNum AddrLo AddrHi tileNum tileNum
to update 2 up to 4 tiles in the tile map per line where the tiles on DMA 2 and 3 and 6 and 7 must follow each other

or if you want to change a tile definition you can update 8 bytes per line where each tile takes 64 bytes so you need 8 lines to DMA a tile.

you could force blank but that will probably stuff up sprites as well, but if you don't need those then you could force blank and update more bytes per line with an IRQ based DMA call.
User avatar
Señor Ventura
Posts: 233
Joined: Sat Aug 20, 2016 3:58 am

Re: Dynamically updating tiles in mode 7 BG tileset

Post by Señor Ventura »

Oziphantom wrote: Wed Jan 05, 2022 2:23 am you can not update VRAM out of a blanking period, at all, nothing can do it, the only way to get new data into VRAM is during blanking. You have 8 DMA channels so you can use HDMA to move 8 bytes per line into VRAM as long as it is sequential, so if you are changing the tile map, you could do

Code: Select all

DMA  0      1      2       3       4      5      6       7
LINE AddrLo AddrHi tileNum tileNum AddrLo AddrHi tileNum tileNum
to update 2 up to 4 tiles in the tile map per line where the tiles on DMA 2 and 3 and 6 and 7 must follow each other

or if you want to change a tile definition you can update 8 bytes per line where each tile takes 64 bytes so you need 8 lines to DMA a tile.

you could force blank but that will probably stuff up sprites as well, but if you don't need those then you could force blank and update more bytes per line with an IRQ based DMA call.
The actual AoF2 of snes do F-blanking during the first 8 pixels, and the last 8 pixels of every scanline. It has two black borders horizontally and vertically, so, this game only draws 240 pixels instead 256 (even you have bigger F-Blanking in the HUD).

And you can do it uninterruptedly if you start the interruption from the pixel 248 of an scanline, till the pixel 8 of the next one. If an complete F-blanked scanline gives 165.5 Bytes, Do 16 pixels of an scanline give 10 Bytes?, and then you get what HDMA sums...

One doubt i have is how many Bytes of HDMA per scanline need the mode 7 to read the transformation table in WRAM. If it needs the whole 4 Bytes per scanline, then it won't help in this task.


A plausible result with this system could be that every 9 horizontal columns of tiles, you can update up to 128 new tiles, achieving until 512 for BG in mode 7 (only in perspectives like the "AoF" one). With F-zero and mario kart it won't work.
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: Dynamically updating tiles in mode 7 BG tileset

Post by psycopathicteen »

Oziphantom wrote: Wed Jan 05, 2022 2:23 am you can not update VRAM out of a blanking period, at all, nothing can do it, the only way to get new data into VRAM is during blanking. You have 8 DMA channels so you can use HDMA to move 8 bytes per line into VRAM as long as it is sequential, so if you are changing the tile map, you could do

Code: Select all

DMA  0      1      2       3       4      5      6       7
LINE AddrLo AddrHi tileNum tileNum AddrLo AddrHi tileNum tileNum
to update 2 up to 4 tiles in the tile map per line where the tiles on DMA 2 and 3 and 6 and 7 must follow each other

or if you want to change a tile definition you can update 8 bytes per line where each tile takes 64 bytes so you need 8 lines to DMA a tile.

you could force blank but that will probably stuff up sprites as well, but if you don't need those then you could force blank and update more bytes per line with an IRQ based DMA call.
Wouldn't you need to force blank during hblank and disable sprites in order to use HDMA for VRAM writes?

Plus, you're allowed to HDMA up to 32 bytes per lines because HDMA allows up to 4 bytes per channel.
93143
Posts: 1717
Joined: Fri Jul 04, 2014 9:31 pm

Re: Dynamically updating tiles in mode 7 BG tileset

Post by 93143 »

Señor Ventura wrote: Thu Jan 06, 2022 6:57 amThe actual AoF2 of snes do F-blanking during the first 8 pixels, and the last 8 pixels of every scanline.
You sure about that? Just because that part is black doesn't mean it's forced blank - in fact, it's incredibly unlikely, because forced blank during HBlank would disable or glitch out sprites (OBJ graphics are loaded from VRAM during HBlank), to say nothing of the effective impossibility of lining up writes to INIDISP within a pixel every scanline while running a game (an IRQ firing during actual code, rather than just WAI, will experience a quasi-random delay of up to 8 cycles depending on the instruction currently being executed, due to the CPU having to finish the instruction before handling the interrupt - note that even a fast CPU cycle is 1.5 pixels long, and a slow cycle is two pixels).

It's more likely just windowing.

psycopathicteen wrote: Wed Jan 12, 2022 8:56 pmWouldn't you need to force blank during hblank and disable sprites in order to use HDMA for VRAM writes?

Plus, you're allowed to HDMA up to 32 bytes per lines because HDMA allows up to 4 bytes per channel.
Yes. But unless you have ridiculously precise IRQ timing and/or a window border to give you some leeway, you need HDMA to turn the screen off and on, as well as setting the VRAM address if necessary (it persists, so you can technically just dump contiguous data into VRAM as long as nothing else is poking VMADD during the frame). So the practical maximum using HDMA is 24 bytes per scanline, or less if you want HDMA for anything else. I got 29 with regular DMA in an IRQ, but it's way more expensive to use an IRQ, especially if you have to branch down jitter from real game code to line up the writes.

You do have to be careful of the fact that on some models, if the destination address of the last HDMA channel of the frame is $00, it crashes the DMA unit (viewtopic.php?t=21971). It appears to be safe to use transfer mode %001 with BBADx set to $FF and the same value sent to both p and p+1...

...say. I wonder if you could overload the IRQ to get rid of most of the jitter in one shot. Have it reset itself and refire at the desired point during a WAI, giving you maybe one pixel of jitter to branch down... Even that would be pretty expensive...


On the topic of the thread,
Señor Ventura wrote: Tue Jan 04, 2022 6:07 amSince mode7 only can "see" 256 tile at a same time
Mode 7 can only "see" 256 tiles, period. The tileset starts at $0000 in VRAM, and you can't change that. The only way to have more tiles is to overwrite some of them after they've been used, but before the new ones are needed. At the maximum capacity of the HDMA scheme, you can replace 84 tiles in 224 scanlines, and this assumes perfect onscreen alignment so you aren't overwriting data you need, or trying to display data you haven't written yet. I don't think increasing the tile pool by 30% (or less, in practical situations) is generally going to be worth losing the ability to use any sprites at all... and good luck trying this with a rotating display; the tiles you want to replace could be anywhere...
every tile in mode 7 has 2 Bytes inside the tileset registers, right?
There is no such thing as a "tileset register" as you seem to be describing it. I have no idea where you got that notion. The only things in the SNES that are 512 bytes in size are CGRAM and the low OAM table. Were you thinking of OAM?

Other BG modes (not 7) have registers on the B bus that control where in VRAM the PPU looks for the tilemap (describes onscreen tile arrangement with 2 bytes per entry, ranges from 2 to 8 KB) and tileset (1024 tiles in a single contiguous chunk), and these registers are few in number (6 bytes total for all four BG layers, used for every BG mode from Mode 0 to Mode 6). But those registers do not affect Mode 7. Both the tileset (256 tiles) and the tilemap (1 byte per entry, 16 KB for a square map 128 tiles on a side) start at the bottom of VRAM, end of story. (The Mode 7 tileset and tilemap are byte-interleaved, so they span the same set of word addresses.)

This is allegedly the reason Super Mario Kart exists. It was originally a 2-player F-Zero sequel, but since there is only one tilemap in Mode 7 and you can't move it, they couldn't do scroll updates properly in 2-player mode, and a track small enough to fit in the tilemap without scroll updates felt too small for F-Zero's sense of speed to work. So they turned it into a go-kart game... I suspect that if the SNES had ended up with 128 KB of VRAM (there's evidence in some of the register definitions that this was originally the plan), two Mode 7 maps with independent tilesets might have been possible, but the console is what it is.


Also note that Mode 7 doesn't require you to write the transform parameters every scanline. You only do that if you want the parameters to change every scanline, like with perspective or some types of fancy warping. A simple zoom (and/or rotation, squash/stretch, any full-screen affine transformation) requires only a single set of writes during VBlank to update the transform parameters for the upcoming frame. And even that is only strictly necessary if you want the transform to be different than it was last frame...
User avatar
Nikku4211
Posts: 569
Joined: Sun Dec 15, 2019 1:28 pm
Location: Florida
Contact:

Re: Dynamically updating tiles in mode 7 BG tileset

Post by Nikku4211 »

Señor Ventura wrote: Tue Jan 04, 2022 6:07 am In a context of scaling a background with no inclined perspectives, like an scenario of art of fighting 2...

Image



...I see two solutions here:



1º "EXTERNAL DMA" SOLUTION:

Image


2º SNES DMA ONLY:

Image
Aw man, why'd you set the pictures to expire?
I have an ASD, so empathy is not natural for me. If I hurt you, I apologise.
Post Reply