The right way to implement PPU

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
d15ea5e
Posts: 1
Joined: Tue Oct 08, 2013 8:25 am

The right way to implement PPU

Post by d15ea5e » Tue Oct 08, 2013 9:26 am

Hello everyone,
I've started writing my first emulator a few months ago (18 months actually according to hg log, but stopped 7 months ago). I want to continue making this thing for educational purposes. As for now it's working quite ok - 6502 emulation is almost 100% complete (per-cycle emulation), few simple non-MMC mappers are implemented, simple APU with pulse1 and pulse2 is added and PPU is good enough for games like Contra.
As for now main loop of emulator looks like this (simplified, not raw copy paste):

Code: Select all

while(1)
{
 //HandleEvents()
 //Input()
 while (!cpu->ppu.framerendered)
 {
  for(int i=0; i<3; i++) cpu->ppu.Step();
  cpu->Step();
 }
 DrawFrame();
 // Sleep long enough to keep 60fps
}
In CPU->Step one cycle is emulated, same in ppu.Step. Frame is rendered on last scanline if I remember correctly. Everything works ok unless game changes PPU values like ScrollX or ScrollY during visible scanline - my emulator cares only about values that in registers during frame rendering (so registers values on last scanline are only used). For example game like Micro Machines looks terribly wrong in menu and NEStress menu is jumping around.

My question is: how to implement changing values of PPU registers during visible scanlines correctly? One of my ideas is just to plot pixel during every PPU cycle, but this is extremely inefficient. Second thought is to render screen scanline by scanline, not whole frame at once. My last concept is to store register values when CPU is writing to them in some kind of vector in form of [scanline, pixel, value] per register. Then use those values during frame rendering.

Which approach is best one? Is there better way to implement this?

User avatar
James
Posts: 429
Joined: Sat Jan 22, 2005 8:51 am
Location: Chicago, IL
Contact:

Re: The right way to implement PPU

Post by James » Tue Oct 08, 2013 10:05 am

d15ea5e wrote:One of my ideas is just to plot pixel during every PPU cycle, but this is extremely inefficient.
Do it this way*. At first, at least. It may be inefficient compared to other methods, but it's the least complicated method. Once you have a solid understanding of how everything works, the quirks, etc., go back and optimize where you need to (even if that means throwing it all out and starting from scratch). Depending on your target platform, you may find that the inefficient way is good enough.

* don't plot a pixel to the display every cycle, though. Write to a buffer, then blit that to the screen at the end of the frame.
get nemulator
http://nemulator.com

User avatar
Quietust
Posts: 1684
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: The right way to implement PPU

Post by Quietust » Tue Oct 15, 2013 8:13 am

d15ea5e wrote:One of my ideas is just to plot pixel during every PPU cycle, but this is extremely inefficient.
This is actually how my emulator (Nintendulator) does it, though with James's clarification that it writes it to a buffer which then gets blitted once per frame. While it is rather inefficient, desktops and laptops from the past 8 years or so can run it just fine (though slower netbooks and tablets have been reported to struggle a bit).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

WedNESday
Posts: 1236
Joined: Thu Sep 15, 2005 9:23 am
Location: Berlin, Germany
Contact:

Re: The right way to implement PPU

Post by WedNESday » Tue Oct 15, 2013 9:23 am

d15ea5e wrote:One of my ideas is just to plot pixel during every PPU cycle, but this is extremely inefficient.
Erm, that's how all modern NES emulators do their PPUs...

mkwong98
Posts: 236
Joined: Mon May 30, 2011 9:01 pm

Re: The right way to implement PPU

Post by mkwong98 » Wed Oct 16, 2013 6:20 am

It depends on your goal and what graphics engine your emulator uses.

My emulator does additional processing with the graphics and so can't use the final pixel directly from the PPU. It runs on OpenGL and uses 33 background quads and 8 sprite quads to represent one scanline. Each scanline it updates the quads and generates textures. It renders the screen 3 times per frame - one for back sprite layer, one for background layer and one for front sprite layer.

Another way is to render the screen only when you meet a relevent register change or end of frame. Just render the screen using the old values upto the current pixel.

Post Reply