I'm reverting back to my older DMA code

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
I'm reverting back to my older DMA code
by on (#151384)
I found out the optimizations I made to the DMA code, back when I had my older animation engine, no longer has any benefit with my current animation engine.

Code:
dma_sprites_loop:
lda.w {dma_rows},x
beq end_dma_sprites_loop
clc

-;
lda.w {dma_address},x
sta $02
adc.w {dma_increment},x
sta.w {dma_address},x

lda.w {dma_bank},x
sta $04

lda.w {dma_legnth},x
beq end_dma_sprites_loop
sta $05
lda.w {dma_destination},x
sta $2116
adc #$0100
sta.w {dma_destination},x
sty $420b


dec.w {dma_rows},x
bne -

inx #2
bra dma_sprites_loop

end_dma_sprites_loop:

stz {dma_updates}
stz {total_dma_legnth}


The stuff about "dma rows" and "dma increment" can be removed. The reason they existed in the first place was because my old animation engine used rectangular animation boxes and the spent a lot of CPU time filling up the dma table, and having extra dma table parameters saved overall CPU time at a cost of vblank time. Now that I'm only using 32x32 and 16x16 boxes, I can just improvise the dma table building routine, so now the benefit is gone.

The reason why I didn't pay any attention to it until now is because I'm adding ninjas to my game, and the ninja jumping animation is 80x80 pixels big, so I'm having DMA overload issues. If I put the DMA threshold to 3kB, the ninja's animation freezes when jumping, but when it's set to 3.5kB I get flickering black bars. I use to be able to get 5kB per frame.
Re: I'm reverting back to my older DMA code
by on (#151385)
Have you tried predicting what each actor's next frame is going to be, based on its current frame, and then uploading that to a double buffer over the course of two frames? It works for me in my current project. Or is VRAM not big enough to double-buffer all sprites?
Re: I'm reverting back to my older DMA code
by on (#151389)
I don't know if it's big enough, and it looks like it will be complicated to implement. My animation engine is already complicated to begin with. I might do it in the future, but it doesn't look like I need it right now.
Re: I'm reverting back to my older DMA code
by on (#151399)
Quote:
I use to be able to get 5kB per frame.

Wait, does Vblank code affect DMA transfer size that bad? Well, shoot. I've held of this stuff forever at this point, and I haven't even touched any SNES thing since the beginning of the summer...
Re: I'm reverting back to my older DMA code
by on (#151401)
I'm guessing this old 16x16 and 32x32 DMA code I made isn't very good... :(

Quote:
Table Setup:
Word 1: Spot In Vram
Word 2: Transfer/Sprite Size
Word 3: Bank Number
Word 4: Tile Address
Code:
start_tile_uploader:
  rep #$30   ; A=16, X/Y=16
  ldx #$0000
  lda #$1801         ; Set DMA mode (word, normal increment) and destination register (VRAM write register)
  sta $4300
  lda #$0080
  sta $2115


tile_uploader_begining:
  lda TileRequestTable+2,x   ;Transfer/Sprite Size
  sta $4305
  sta $4315
  cmp #$0080
  beq tile_uploader_32x32


;16x16 Top Half
  lda TileRequestTable,x   ;Spot in vram
  sta $2116

  lda TileRequestTable+4,x   ;Bank number
  sta $4303
  sta $4313

  lda TileRequestTable+6,x   ;Tile address
  sta $4302
  clc
  adc #$0040
  sta $4312

  lda #%0000000100000000   ; Initiate DMA transfer (channel 0)
  sta $420A


;16x16 Bottom Half
  lda TileRequestTable,x   ;Spot in vram
  clc
  adc #$0100
  sta $2116

  lda #%0000001000000000   ; Initiate DMA transfer (channel 1)
  sta $420A

  txa
  clc
  adc #$0008
  tax
  cpx TileUploaderRequestCounter
  bne tile_uploader_begining
  jsr




tile_uploader_32x32:
  sta $4325
  sta $4335

  lda TileRequestTable+2,x   ;Transfer/sprite size
  cmp #$0080
  sta $4305
  sta $4315
  beq tile_uploader_32x32

  lda TileRequestTable,x   ;Spot in vram
  sta $2116

  lda TileRequestTable+4,x   ;Bank number
  sta $4303
  sta $4313
  sta $4323
  sta $4333

  lda TileRequestTable+6,x   ;Tile address
  sta $4302
  clc
  adc #$0040
  sta $4312
  clc
  adc #$0040
  sta $4322
  clc
  adc #$0040
  sta $4332

  lda #%0000000100000000   ; Initiate DMA transfer (channel 0)
  sta $420A


;Second Row
  lda TileRequestTable,x   ;Spot in vram
  clc
  adc #$0100
  sta $2116

  lda #%0000001000000000   ; Initiate DMA transfer (channel 1)
  sta $420A


;Third Row
  lda TileRequestTable,x   ;Spot in vram
  clc
  adc #$0200
  sta $2116

  lda #%0000010000000000   ; Initiate DMA transfer (channel 2)
  sta $420A


;Fourth Row
  lda TileRequestTable,x   ;Spot in vram
  clc
  adc #$0300
  sta $2116

  lda #%0000100000000000   ; Initiate DMA transfer (channel 3)
  sta $420A

  txa
  clc
  adc #$0008
  cmp TileUploaderRequestCounter
  beq done:
  tax
  brl tile_uploader_begining

done:
  rts
Re: I'm reverting back to my older DMA code
by on (#151407)
Espozo wrote:
Quote:
I use to be able to get 5kB per frame.

Wait, does Vblank code affect DMA transfer size that bad? Well, shoot. I've held of this stuff forever at this point, and I haven't even touched any SNES thing since the beginning of the summer...

I would argue that DMA code overhead has more to do with it.

These days on the Mega Drive I do pretty much what Traveller Tales did (at least in Sonic 3D): during the game logic build a queue with all the DMAs to be executed for that frame (as in the commands themselves to be sent to the video hardware), then as soon as vblank starts the entire queue is copied to the VDP. This reduces overhead to the minimum and ensures the most critical part (the DMAs) get all the priority in vblank. I would imagine something similar could (should) be done on the SNES.
Re: I'm reverting back to my older DMA code
by on (#151409)
@Espozo

That looks like it's fast enough.

That gives me an idea. I can have 3 different transfer modes:
$00 = 1 row (used for non sprite DMA transfers)
$01 = 2 rows
$02 = 4 rows
Re: I'm reverting back to my older DMA code
by on (#161509)
Sik wrote:
Espozo wrote:
Quote:
I use to be able to get 5kB per frame.

Wait, does Vblank code affect DMA transfer size that bad? Well, shoot. I've held of this stuff forever at this point, and I haven't even touched any SNES thing since the beginning of the summer...

I would argue that DMA code overhead has more to do with it.

These days on the Mega Drive I do pretty much what Traveller Tales did (at least in Sonic 3D): during the game logic build a queue with all the DMAs to be executed for that frame (as in the commands themselves to be sent to the video hardware), then as soon as vblank starts the entire queue is copied to the VDP. This reduces overhead to the minimum and ensures the most critical part (the DMAs) get all the priority in vblank. I would imagine something similar could (should) be done on the SNES.


Is this the same thing as making a list of source addresses, destination addresses, and DMA legnths, or is it something a little bit different?
Re: I'm reverting back to my older DMA code
by on (#161525)
psycopathicteen wrote:
Is this the same thing as making a list of source addresses, destination addresses, and DMA legnths, or is it something a little bit different?

That's basically what it is, yeah.
Re: I'm reverting back to my older DMA code
by on (#161534)
Yeah, that is how almost games handle DMA so they maximize the bandwidth usage during vblank.
The new dma.c unit from SGDK allow direct DMA operation or queue :
https://github.com/Stephane-D/SGDK/blob ... /src/dma.c

when you use DMA_queueDma(..) you basically queue a DMA operation in a specific structure adapted for direct hardware port write.
Then at VInt you just call DMA_flushQueue() which send very quickly all DMA instructions to VDP.
Re: I'm reverting back to my older DMA code
by on (#161543)
Apparently turning the screen back on before setting up HDMA, was enough to fix any black bar tearing on the top of the screen. Must've missed the end of vblank by a hair, since the HDMA code is pretty short.