8x16 and whatever else unreg wants to know
Moderator: Moderators
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
After turning rendering off, the screen is wiped. Why? Did they design the PPU to do that? Maybe it makes sense though, bc, I guess, the screen requires the PPU to draw it every frame; and turning off the PPU's drawing restricts future screens from showing. If that's so, it would have been ultra cool to have installed a feature that made the PPU just draw the last screen written until rendering is reenabled. Maybe that would be to complex.
Too bad that $2001 can only be written to during vblank. It seems to me: if that wasn't the case the screen wouldn't clear bc rendering would be reenabled before the end of the frame.
Is the only way to avoid blank-screens appearing inbetween screens drawn by the PPU, is to draw each screen inside vblank so that rendering isn't disabled? I'm asking this here bc the nesdev wiki claims that screens can't be drawn outside of vblank.
Note to myself: have I asked this before?
Too bad that $2001 can only be written to during vblank. It seems to me: if that wasn't the case the screen wouldn't clear bc rendering would be reenabled before the end of the frame.
Is the only way to avoid blank-screens appearing inbetween screens drawn by the PPU, is to draw each screen inside vblank so that rendering isn't disabled? I'm asking this here bc the nesdev wiki claims that screens can't be drawn outside of vblank.
Note to myself: have I asked this before?
Re: 8x16 and whatever else unreg wants to know
The picture literally only exists at the exact moment that each pixel is sent to the CRT. The rest is just the optical illusion known as persistence of vision.unregistered wrote:After turning rendering off, the screen is wiped. Why? Did they design the PPU to do that? Maybe it makes sense though, bc, I guess, the screen requires the PPU to draw it every frame; and turning off the PPU's drawing restricts future screens from showing.
$2001 can be written at any time. But for the image to appear, you have to wait for the CRT to draw it. Turning on rendering using $2001 doesn't cause the entire set of pixels to be sent all at once; instead it starts sending pixels gradually, one new pixel every .000000182 seconds.Too bad that $2001 can only be written to during vblank. It seems to me: if that wasn't the case the screen wouldn't clear bc rendering would be reenabled before the end of the frame.
You cannot write new data during rendering, no.I'm asking this here bc the nesdev wiki claims that screens can't be drawn outside of vblank.
Re: 8x16 and whatever else unreg wants to know
There are two issues at play here:lidnariq wrote:The picture literally only exists at the exact moment that each pixel is sent to the CRT. The rest is just the optical illusion known as persistence of vision.unregistered wrote:After turning rendering off, the screen is wiped. Why? Did they design the PPU to do that? Maybe it makes sense though, bc, I guess, the screen requires the PPU to draw it every frame; and turning off the PPU's drawing restricts future screens from showing.
$2001 can be written at any time. But for the image to appear, you have to wait for the CRT to draw it. Turning on rendering using $2001 doesn't cause the entire set of pixels to be sent all at once; instead it starts sending pixels gradually, one new pixel every .000000182 seconds.Too bad that $2001 can only be written to during vblank. It seems to me: if that wasn't the case the screen wouldn't clear bc rendering would be reenabled before the end of the frame.
You cannot write new data during rendering, no.I'm asking this here bc the nesdev wiki claims that screens can't be drawn outside of vblank.
1. The NES is designed to drive a device that draws a picture by modulating a moving electron beam; the NES sends out a signal that controls how bright the spot under the beam should be at any given moment. Turning off rendering will cause the beam to just keep outputting a solid color until rendering is turned back on, but that will only affect the parts of the picture drawn by the beam while rendering was off. If rendering is left off, then it will affect the whole picture as the beam passes over it. Rendering is only enabled when the render control bits are set and the beam's scanning process isn't between the bottom of one frame and the start of the next--a time known as the "vertical blanking interval", or "vblank".
2. On machines designed for connect to NTSC-based televisions, the memory cells used to hold sprite positions and attributes (Object Attribute Memory, or OAM) may arbitrarily flip state if rendering is disabled for much longer than vblank. So leaving rendering disabled for too long may effectively "wipe" the OAM.
The first issue is common to many vintage systems. The latter is so far as I can tell unique to the NES.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
lidnariq wrote:$2001 can be written at any time. But for the image to appear, you have to wait for the CRT to draw it. Turning on rendering using $2001 doesn't cause the entire set of pixels to be sent all at once; instead it starts sending pixels gradually, one new pixel every .000000182 seconds.Too bad that $2001 can only be written to during vblank. It seems to me: if that wasn't the case the screen wouldn't clear bc rendering would be reenabled before the end of the frame.
So, since there seem to be 61,440 pixels in an entire (not just the visible part of NTSC) NES screen (32x8+30x8==61440) andsupercat wrote:There are two issues at play here:
1. The NES is designed to drive a device that draws a picture by modulating a moving electron beam; the NES sends out a signal that controls how bright the spot under the beam should be at any given moment. Turning off rendering will cause the beam to just keep outputting a solid color until rendering is turned back on, but that will only affect the parts of the picture drawn by the beam while rendering was off. If rendering is left off, then it will affect the whole picture as the beam passes over it. Rendering is only enabled when the render control bits are set and the beam's scanning process isn't between the bottom of one frame and the start of the next--a time known as the "vertical blanking interval", or "vblank".
2. On machines designed for connect to NTSC-based televisions, the memory cells used to hold sprite positions and attributes (Object Attribute Memory, or OAM) may arbitrarily flip state if rendering is disabled for much longer than vblank. So leaving rendering disabled for too long may effectively "wipe" the OAM.
The first issue is common to many vintage systems. The latter is so far as I can tell unique to the NES.
Recently, it did not say something like, "screens can't be drawn outside of vblank, unless rendering is disabled." Leaving that bold part off makes it seem like, to me at least, that screens must be drawn during vblank.lidnariq wrote:You cannot write new data during rendering, no.I'm asking this here bc the nesdev wiki claims that screens can't be drawn outside of vblank.
Thank you lidnariq and supercat!
edit.
final edit.
Last edited by unregistered on Mon May 20, 2019 6:49 pm, edited 1 time in total.
Re: 8x16 and whatever else unreg wants to know
The CRT and PPU are both busy between each horizontal line of pixels, so the math is not 256x240 but instead 341x240=81840; 81840x.000000182 = .0149. So, in practice, you only have the 20-ish scanlines between when NMI is asserted and when rendering starts on its own again later, or approximately .0013 seconds.unregistered wrote:So, since there seem to be 61,440 pixels in an entire (not just the visible part of NTSC) NES screen (32x8+30x8==61440) and drawing a screen must take 61440 x .000000182 == 0.01118208 seconds, it must be possible to disable rendering,
The only way you're getting that is by either rationing the amount you upload per vblank, or using advanced tricks to turn on rendering late or turn it off early.it would be really cool to see it work without blinking.
If you can point where on the wiki it says that, I'd love to fix it.unregistered wrote:Recently, it did not say something like, "screens can't be drawn outside of vblank, unless rendering is disabled." Leaving that bold part off makes it seem like, to me at least, that screens must be drawn during vblank.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
Hmm... sorry, maybe I read this too fast:lidnariq wrote:If you can point where on the wiki it says that, I'd love to fix it.unregistered wrote:Recently, it did not say something like, "screens can't be drawn outside of vblank, unless rendering is disabled." Leaving that bold part off makes it seem like, to me at least, that screens must be drawn during vblank.
In my head I read, "It is usually best practice to write this (info to the PPU) only during vblank, to prevent partial-frame artifacts." I guess I read "this" and thought you were talking about writing info to the PPU bc that's what the wiki was talking about... rendering. Sorry lidnariq, reading is sometimes problematic for me. I will respond, if I have a response, to the rest of your post tomorrow.A value of $00 or %00000000 disables all rendering. It is usually best practice to write this register only during vblank, to prevent partial-frame visual artifacts.
oh that quote is from https://wiki.nesdev.com/w/index.php/PPU ... rs#PPUMASK
Re: 8x16 and whatever else unreg wants to know
One may disable rendering at any time during a frame, with the effect that if one doesn't re-enable it, everything from there on down will be blanked. Enabling the PPU during a frame, however, is tricky. The counters are that are used to update the display address while rendering a display are also used to increment the address after each CPU write; consequently, they don't increment while rendering is disabled. As a consequence, if one enables rendering in the middle of the frame, the PPU will show things in the wrong places unless the CPU first loads the counters with correct values, which would in turn require that the CPU know what those correct values should be. Because the correct values of the counters depend upon the position of the beam, which in turn depends on the amount of time elapsed since the end of vertical blank, the only way the CPU can know what values to load into the counters is by knowing how much time has elapsed since vertical blank. There are ways this can be done, but it is generally difficult.unregistered wrote:Hmm... sorry, maybe I read this too fast:In my head I read, "It is usually best practice to write this (info to the PPU) only during vblank, to prevent partial-frame artifacts." I guess I read "this" and thought you were talking about writing info to the PPU bc that's what the wiki was talking about... rendering. Sorry lidnariq, reading is sometimes problematic for me. I will respond, if I have a response, to the rest of your post tomorrow.A value of $00 or %00000000 disables all rendering. It is usually best practice to write this register only during vblank, to prevent partial-frame visual artifacts.
Re: 8x16 and whatever else unreg wants to know
Unfortunately, there's some obscure bug with the OAM DRAM controller that causes it to malfunction the next time rendering is enabled, if it's not turned off at the right time. Either we've never figured out exactly what's going wrong, or I've forgotten where it was stated, but on the wiki we've only documented the window in which it's safe to do so. (between x≥192 for lines with no sprites, x≥240 for lines with at least one sprite, and ... the wiki doesn't say what the upper bound is? this thread implies it's 255. Note that although the discussion in that thread makes it sound like the bug due to starting rendering with OAMADDR nonzero, but it persists across writing to OAMADDR and OAMDMA)supercat wrote:One may disable rendering at any time during a frame,
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
Wow, thank you so much lidnariq for correcting my math! After reading supercat's and your most recent reply to this thread it seems like the best way to do this would be to disable rendering when x>=192 (while each screen is drawn horizontaly... right?) draw my screen and reenable rendering before vblank. However, when x >=192 doesn't leave much time for screen drawing... so my screen drawing code would have to be sped up (by me), I think... I have to go... to know exactly how much time elapsed since vblank it would require me counting cycles used between end of vblank and the end of me drawing the screen... many of the branches are permanent during this screen drawing so that might not be too bad... then I load that cycle number and write it to somewhere; and then turn on rendering before vbank starts. Seems difficult but, maybe possible? Drawing screens during vblank seems simpler, but then I have to think about redoing my vblank code. Ok, bye, thank you lidnariq and supercat so much!lidnariq wrote:The CRT and PPU are both busy between each horizontal line of pixels, so the math is not 256x240 but instead 341x240=81840; 81840x.000000182 = .0149. So, in practice, you only have the 20-ish scanlines between when NMI is asserted and when rendering starts on its own again later, or approximately .0013 seconds.unregistered wrote:So, since there seem to be 61,440 pixels in an entire (not just the visible part of NTSC) NES screen (32x8+30x8==61440) and drawing a screen must take 61440 x .000000182 == 0.01118208 seconds, it must be possible to disable rendering,
The only way you're getting that is by either rationing the amount you upload per vblank, or using advanced tricks to turn on rendering late or turn it off early.it would be really cool to see it work without blinking.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
Mesen is so helpful! It seems like, from reading Sour's notes in Mesen's Conditional: at the bottom of the Breakpoint window, each scanline takes 341 cycles. So, since vblank starts at scanline 241, then 241-192=49 ... 49*341=16,709 cycles available to draw the screen outside of vblank... and my screen drawing currently takes 16,832 cycles, which leaves only 123 excess cycles... and we'll have to turn rendering on again so if the screen drawing can be reduced by ~150 cycles then that would be enough? This is so much fun!
Re: 8x16 and whatever else unreg wants to know
Keep in mind that there are PPU cycles and CPU cycles... In NTSC, the PPU is 3 times faster than the CPU (i.e. during one CPU cycle, the PPU draws 3 pixels). Make sure you're not mixing the cycle types in your calculations.
Re: 8x16 and whatever else unreg wants to know
Reference: https://wiki.nesdev.com/w/index.php/Cyc ... cle_counts -- total number of CPU cycles available in NMI, on NTSC, is 2273. An entire frame -- when the PPU begins drawing one -- takes about 29780 CPU cycles to complete. So the latter is how much time essentially you have for your "main loop", and the former is how much time you have available in NMI.tokumaru wrote:Keep in mind that there are PPU cycles and CPU cycles... In NTSC, the PPU is 3 times faster than the CPU (i.e. during one CPU cycle, the PPU draws 3 pixels). Make sure you're not mixing the cycle types in your calculations.
To further expand on what tokumaru said, with regards to Mesen specifically: in Debugger, there are two fields -- "CPU Status: Cycles" and "PPU Status: Cycle". Note that one is plural, the other singular.
"CPU Status: Cycles" is a 32-bit signed counter, indicating how many CPU cycles have passed since the game was reset. In more recent AppVeyor builds, its been upgraded to a 64-bit signed counter (which is not backwards-compatible with previous save states, just as a comment in passing).
"PPU Status: Cycle" effectively ranges from 0 to 340, incrementing gradually when/as the PPU draws. It's reset to 0 every frame. Details of what the PPU does during each PPU cycle is available.
Last edited by koitsu on Wed May 22, 2019 5:24 pm, edited 3 times in total.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
Wow tokumaru... ok, so that means we only have around 5,569 cpu cycles to draw an entire screen? And my screen drawing function was just reduced to 16,536 cycles... which, would have been sufficient with my messed up math. Ahh, ok, I guess it's not possible for me to draw blinkingless screens outside of vblank. Maybe I'll try again tomorrow.
Thank you koitsu for the info and links... will look at them tomorrow.
Thank you koitsu for the info and links... will look at them tomorrow.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Re: 8x16 and whatever else unreg wants to know
tokumaru, thank you so much for teaching me 1 CPU cycle==3 PPU cycles.
Re: 8x16 and whatever else unreg wants to know
No. Screens are drawn from top to bottom. The range of 192<=x<256 is when, within any given scanline, you have to turn off rendering, IF you do, in order for sprites to not be broken the next time rendering turns on.unregistered wrote:disable rendering when x>=192 (while each screen is drawn horizontally... right?)
There's no restriction on which scanline number (Y) you turn off rendering, but it will produce a solid-colored bar at the bottom of the screen.
The entire amount of time the CPU has per redraw, regardless of whether the PPU is drawing, is 341*262/3 ~~ 29780. Your code needs to be a lot faster for "only letting the PPU draw part of the time" to be an adequate solution.unregistered wrote:and my screen drawing currently takes 16,832 cycles,
I'd strongly recommend figuring out how to divide uploads across multiple refreshes. You're going to need it anyway.