It is currently Sat Jul 21, 2018 4:43 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Sat Mar 31, 2018 11:55 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20280
Location: NE Indiana, USA (NTSC)
On the NES, I've gathered that it's considered best practice not to hardcode a particular game object's starting position in the display list. For example, don't always draw the main character using sprites 1-8, enemy 1 using sprites 9-14, enemy 2 using sprites 15-20, etc. Instead, NES games are supposed to reassign slots every frame, especially if there's a possibility that more than eight will be displayed on the same scanline. This also allows the game to make enemies intentionally Z-fight if they overlap.

But in the Game Boy community (gbdev.gg8.se and the related Discord server), it's common to hardcode OAM indices for actors or at least not shuffle them from frame to frame, and I'm trying to understand why they do that. The Game Boy sprite system differs from that of the NES as follows:

  • There is enough secondary OAM to draw 10 8-pixel-wide sprites per 160-pixel scanline. Thus sprites can cover nearly half of the screen's width rather than one-fourth like on the NES.
  • The PPU determines which sprites to draw by finding the 10 lowest-numbered sprites in OAM whose Y range overlaps each scanline, just as the NES PPU does. But then according to Pan Docs, the monochrome Game Boy sorts these frontmost 10 sprites by their X coordinate before displaying them. Sprites to the left are drawn in front, with position in OAM only breaking ties.
  • The memory controller responsible for OAM isn't a rushed, buggy mess. This means OAM can be randomly accessed at $FE00-$FE9F during blanking periods.
  • Horizontal blanking on the Game Boy is much longer than on the NES. OAM on the Game Boy can be accessed not only during vertical blanking but also during most of horizontal blanking.

On the Game Boy, with more relative overdraw and less control of sprite-to-sprite priority, would it be less of a bad practice to statically allocate OAM space? Does random access to OAM even during horizontal blanking have anything to do with it by reducing the need to always use OAM DMA?


Relationship to other topic: This one also includes the random access instead of DMA as an additional factor.


Top
 Profile  
 
PostPosted: Sat Mar 31, 2018 12:46 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6421
Location: Canada
I don't know why this was a whole new topic, but my previous response applies more or less equally here with a minor edit:
rainwarrior wrote:
I would say it's quite common for new NES developers to hardcode OAM indices too. It's just that they probably pretty quickly get beat back by the problems that creates. On a system with wider tolerance you wouldn't necessarily create a problem at all.

Overlap is often a big problem in a platform game with a flat plane of play, since gravity brings everything to the same level. But... 4 sprites on one platform is usually a pretty busy situation in NES games already... 8 5 sprites (on a smaller screen) ? How crowded is this?


I think pretty much everyone's reply in that thread is still relevant here.


Top
 Profile  
 
PostPosted: Sun Apr 01, 2018 7:21 pm 
Offline

Joined: Sun Mar 27, 2011 10:49 am
Posts: 254
Location: Seattle
tepples wrote:
On the Game Boy, with more relative overdraw and less control of sprite-to-sprite priority, would it be less of a bad practice to statically allocate OAM space? Does random access to OAM even during horizontal blanking have anything to do with it by reducing the need to always use OAM DMA?


Yes, it's probably less of a "bad practice", mostly because of the first point in your list: visual glitches are less likely to happen, so why bother?

I don't understand what you're talking about w.r.t. hblank and DMA, but I doubt it's a factor. My understanding is that most games do use the shadow OAM/OAM DMA method (IIRC the official docs prescribe it). hblank on the GB is still incredibly short and not useful for much besides raster effects.

My engine doesn't shuffle OAM slots right now, but it's something I'd like for it to do eventually. I don't know off the top of my head what any commercial games do.


Top
 Profile  
 
PostPosted: Sun Apr 01, 2018 7:35 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6421
Location: Canada
adam_smasher wrote:
I don't know off the top of my head what any commercial games do.


Teenage Mutant Ninja Turtles: Fall of the Foot Clan is one commercial game that appears to have OAM cycling:
https://youtu.be/V9g3abNwXO8?t=5m25s

I'm sure there are many others. There are also plenty of NES games that don't need to. I think we're just so used to NES games having "flicker" that it's an obvious feature. Less so on GB. Even less so on SNES.

The plant boss from Gradius III always made me suspect it might not cycle OAM. (In many other places overlap order appears to be fixed, as well.)
https://youtu.be/pjQ1_8hbp9I?t=21m40s


Top
 Profile  
 
PostPosted: Mon Apr 02, 2018 8:12 am 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2714
Dynamic OAM doesn't necessarily mean no flicker. My old Gunstar Heros demo used a dynamic OAM but no alternating flicker.


Top
 Profile  
 
PostPosted: Mon Apr 02, 2018 8:44 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20280
Location: NE Indiana, USA (NTSC)
adam_smasher wrote:
hblank on the GB is still incredibly short and not useful for much besides raster effects.

That's what I thought, until I found a reason to push 14 1bpp tiles over the course of 14 hblank lines. It's a variable width font (VWF) engine, and unlike on the NES, the 8.5 lines of vblank that remain after OAM DMA aren't long enough without stack abuse. Here's what I ended up doing, with no exceptions in BGB.

  1. Wait for LY not 153 or 0, to avoid a vblank followed immediately by OAM scan with no intervening hblank.
  2. Wait for LY not LYC - 2 or LYC - 1, to avoid the stat interrupt handler throwing off the timing of the following steps.
  3. Wait for STAT.D0 = 1, meaning vblank or draw.
  4. Wait for STAT.D1 = 0, meaning vblank or hblank; this loop has a 6-cycle granularity.
  5. You have about 44 cycles (for OAM) or 62 cycles (for VRAM) to write bytes. This should be enough to push one OAM entry, one 1bpp tile (alternating write and skip), half a 2bpp tile, or one group of four tiles in the tilemap.

Thus someone might be tempted to write a sprite update routine that pushes out changes immediately in hblank.


Top
 Profile  
 
PostPosted: Thu Apr 05, 2018 2:56 pm 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 220
I was going to write a reply about a routine I've written, but the post quickly became so long that I posted it in its own thread instead: 16 byte per line hblank copy routine

_________________
Gameboy Genius (Blog) - Gameboy development forum (+wiki and file area)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group