Background rendering
Moderator: Moderators
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Background rendering
Hello
I have now a question about background rendering
I know that the background rendering starts 2 tiles ahead before the real output of the tile
according to the this http://wiki.nesdev.com/w/images/d/d1/Ntsc_timing.png
we fetch the first two tiles of scanline (S) in clks from 321 -> 336 of scanline (S-1)
according to this project , the address of the name table byte is as follows ( assuming we are dealing with name table at 0x2C00 )
& = concatenation
"1011" & y_scroll[7:3] & x_scroll[7:3]
where x_scroll and y_scroll are counters for horizontal and vertical pixels
the problem I see with this is that the first 2 tiles are not fetched right
as example , if we are on scanline y=0x02 thefore the address if name table byte( at clk = 321) will be equal
0x2C08(the ninth tile) not 0x2C00( the first tile )
I have now a question about background rendering
I know that the background rendering starts 2 tiles ahead before the real output of the tile
according to the this http://wiki.nesdev.com/w/images/d/d1/Ntsc_timing.png
we fetch the first two tiles of scanline (S) in clks from 321 -> 336 of scanline (S-1)
according to this project , the address of the name table byte is as follows ( assuming we are dealing with name table at 0x2C00 )
& = concatenation
"1011" & y_scroll[7:3] & x_scroll[7:3]
where x_scroll and y_scroll are counters for horizontal and vertical pixels
the problem I see with this is that the first 2 tiles are not fetched right
as example , if we are on scanline y=0x02 thefore the address if name table byte( at clk = 321) will be equal
0x2C08(the ninth tile) not 0x2C00( the first tile )
Re: Background rendering
"1011" isn't necessarily right, the first 10 is fine since it indicates that it wants the nametables rather than the pattern tables, but the "11" afterwards is actually two nametable selection bits, which are part of V. It could be 00, 01, 10, 11, etc.
Aside from that, check that the coarse X is incremented correctly.
Aside from that, check that the coarse X is incremented correctly.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
So how it is incremented correctly ?check that the coarse X is incremented correctly.
Re: Background rendering
Some quick stuff:
VRAM address format: yyyNNYYYYYXXXXX (yyy = fine y, NN = nametable, YYYYY = coarse Y, XXXXX = coarse x)
For nametable tile fetches, we use this:
010NNYYYYYXXXXX
010 = Nametable memory rather than pattern tables, NN = nametable selection, YYYYY = coarse Y, XXXXX = coarse X
If we are scrolled to 0,0 on upper-left name table, we use NN = 0, YYYYY = 0, XXXXX = 0, we get this address:
010000000000000
Then for the next tile horizontally, treat NXXXXX as a single 6-bit value (using the lower bit of NN), increment that.
Attribute byte fetch:
010NN1111YYYXXX, using upper 3 bits of XXXXX and YYYYY. The second-lowest bit of YYYYY and XXXXX are used to select which 2-bits to use from the attribute byte value.
The same attribute fetch is made twice.
VRAM address format: yyyNNYYYYYXXXXX (yyy = fine y, NN = nametable, YYYYY = coarse Y, XXXXX = coarse x)
For nametable tile fetches, we use this:
010NNYYYYYXXXXX
010 = Nametable memory rather than pattern tables, NN = nametable selection, YYYYY = coarse Y, XXXXX = coarse X
If we are scrolled to 0,0 on upper-left name table, we use NN = 0, YYYYY = 0, XXXXX = 0, we get this address:
010000000000000
Then for the next tile horizontally, treat NXXXXX as a single 6-bit value (using the lower bit of NN), increment that.
Attribute byte fetch:
010NN1111YYYXXX, using upper 3 bits of XXXXX and YYYYY. The second-lowest bit of YYYYY and XXXXX are used to select which 2-bits to use from the attribute byte value.
The same attribute fetch is made twice.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
it seems I have a problem with counters arrangement
till now , I think that counters are chained as follows
MSB-------------------LSB
YYYYY yyy XXXXX xxx
YYYYY -> 5 bits indicating tile no. (vertically)
yyy -> fine ver
xxx -> fine hor
XXXXX-> 5 bits indicating tile no. (horizontally)
that's also how I think rendering goes , line by line
is this wrong ?
till now , I think that counters are chained as follows
MSB-------------------LSB
YYYYY yyy XXXXX xxx
YYYYY -> 5 bits indicating tile no. (vertically)
yyy -> fine ver
xxx -> fine hor
XXXXX-> 5 bits indicating tile no. (horizontally)
that's also how I think rendering goes , line by line
is this wrong ?
Re: Background rendering
A game will write to $2006 twice, and get this:
first write: _0yyNNYY
2nd write: YYYXXXXX
(due to a quirk about how register $2006 works, the top bit of fine y can't be written that way, but it can still be changed with a combination of $2005/$2006 writes)
If you use the ordering from what $2006 writes look like, you get this:
_yyyNNYYYYYXXXXX
When rendering is disabled, that 15-bit value is used as the PPU address for reads and writes.
The actual arrangement of the bits inside could be anything. I haven't looked at the silicon and don't intend to. But numbers like YYYYYyyy and XXXXXxxx aren't used anywhere during rendering.
Since yyyNNYYYYYXXXXX corresponds to the 15-bit value used as the PPU address, people often assume that the counter inside looks like that.
And fine x (xxx) is nowhere to be seen in the VRAM address value, it's treated as being separate. First write to $2005 will set those bits.
first write: _0yyNNYY
2nd write: YYYXXXXX
(due to a quirk about how register $2006 works, the top bit of fine y can't be written that way, but it can still be changed with a combination of $2005/$2006 writes)
If you use the ordering from what $2006 writes look like, you get this:
_yyyNNYYYYYXXXXX
When rendering is disabled, that 15-bit value is used as the PPU address for reads and writes.
The actual arrangement of the bits inside could be anything. I haven't looked at the silicon and don't intend to. But numbers like YYYYYyyy and XXXXXxxx aren't used anywhere during rendering.
Since yyyNNYYYYYXXXXX corresponds to the 15-bit value used as the PPU address, people often assume that the counter inside looks like that.
And fine x (xxx) is nowhere to be seen in the VRAM address value, it's treated as being separate. First write to $2005 will set those bits.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
I have a problem with this exampleIf we are scrolled to 0,0 on upper-left name table, we use NN = 0, YYYYY = 0, XXXXX = 0, we get this address:
010000000000000
although this is the address of the first tile in the name table , it should be fetched at clks 321 , 322
at those clks , if we tried to extract the fine x , coarse x and formed the address from it using the format , we will find that
321 = 0b 101000000------> xcoarse = 01000 ( assuming ycoarse = 00000
if we formed the address : 010 0000 0000 1000 = 0x2008 which points to the ninth tile not the first which I want to fetch
I have a way to bypass this ( subtracting 8 during fetch in scanline S-1 clks 321 -> 336 and adding 2 when fetching the rest in scanline S ) but I think this is not what really happens
tell me if you didn't get me problem to explain it more
Re: Background rendering
While there might be some internal counters somewhere for the scanline number and which dot it's rendering, those are separate from the VRAM address used when fetching stuff.
We have two counters, people call them "Loopy T" and "Loopy V", named after a user called Loopy who figured out how they worked.
V corresponds to the address that the PPU uses to fetch tiles, and T is used to make V snap back to the left at the end of a scanline, or snap back to the top at the beginning of the screen.
They are organized in the usual yyyNNYYYYYXXXXX pattern.
At dots 280-304 of the prerender line, vertical parts of T are copied into V. This is yyy, high bit of NN, and YYYYY. This snaps it back to the top of the screen.
At dot 256 of each scanline, vertical part of V is incremented.
Vertical increment:
Treat Y scroll bits of V as an 8-bit value made up of YYYYYyyy. Increment it. If the value changed from 239 to 240, set YYYYYyyy = 0, then toggle the high bit of NN. This makes it advance to the next name table after incrementing from 239 to 240, and resets vertical scroll to 0.
There is also 'negative scrolling' here, if the value of Y was 240 or higher before it was incremented, it does not change any bits of NN, and does not reset to 0. The value of Y can increase from 255 to 0, and it won't flip the high bit of NN. This doesn't usually happen, unless the game intentionally wrote an out-of-range value 240 or higher to Y-scroll. Y-scroll values out of range make it draw attribute tables as tiles, and produce artifacts at the top of the screen.
At dot 257 of each scanline (including prerender line), horizontal parts of T are copied into V. This is XXXXX and low bit of NN. This makes it snap back to the left so it can draw the next scanline.
At dot 321, it starts fetching the first tile of the next scanline.
Horizontal increment:
This happens 34 times per scanline.
7 dots after the first fetch, horizontal parts of V are incremented, like incrementing a 6-bit number made up of NXXXXX. There is nothing weird here, unlike Y scrolling.
this is a good diagram: http://wiki.nesdev.com/w/images/d/d1/Ntsc_timing.png
We have two counters, people call them "Loopy T" and "Loopy V", named after a user called Loopy who figured out how they worked.
V corresponds to the address that the PPU uses to fetch tiles, and T is used to make V snap back to the left at the end of a scanline, or snap back to the top at the beginning of the screen.
They are organized in the usual yyyNNYYYYYXXXXX pattern.
At dots 280-304 of the prerender line, vertical parts of T are copied into V. This is yyy, high bit of NN, and YYYYY. This snaps it back to the top of the screen.
At dot 256 of each scanline, vertical part of V is incremented.
Vertical increment:
Treat Y scroll bits of V as an 8-bit value made up of YYYYYyyy. Increment it. If the value changed from 239 to 240, set YYYYYyyy = 0, then toggle the high bit of NN. This makes it advance to the next name table after incrementing from 239 to 240, and resets vertical scroll to 0.
There is also 'negative scrolling' here, if the value of Y was 240 or higher before it was incremented, it does not change any bits of NN, and does not reset to 0. The value of Y can increase from 255 to 0, and it won't flip the high bit of NN. This doesn't usually happen, unless the game intentionally wrote an out-of-range value 240 or higher to Y-scroll. Y-scroll values out of range make it draw attribute tables as tiles, and produce artifacts at the top of the screen.
At dot 257 of each scanline (including prerender line), horizontal parts of T are copied into V. This is XXXXX and low bit of NN. This makes it snap back to the left so it can draw the next scanline.
At dot 321, it starts fetching the first tile of the next scanline.
Horizontal increment:
This happens 34 times per scanline.
7 dots after the first fetch, horizontal parts of V are incremented, like incrementing a 6-bit number made up of NXXXXX. There is nothing weird here, unlike Y scrolling.
this is a good diagram: http://wiki.nesdev.com/w/images/d/d1/Ntsc_timing.png
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
sorry but I didn't get it but I think you want to refer that the vertical counters are different from scanline counters?
and pixel counters (from 0 to 340) differs from the horizontal counter ?
and pixel counters (from 0 to 340) differs from the horizontal counter ?
Re: Background rendering
Correct.
While rendering is off, there are three counters:
While rendering is off, there are three counters:
- VRAM address, bits 14-0
- Horizontal pixel position, from 0 to 340
- Vertical pixel position, from 0 to 261 (or 311 on PAL)
- Horizontal portion of VRAM address, consisting of bits 10 and 4-0 of the VRAM address
- Vertical portion of VRAM address, consisting of bits 11, 9-5, and 14-12 of the VRAM address
- Horizontal pixel position, from 0 to 340
- Vertical pixel position, from 0 to 261 (or 311 on PAL)
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
I may understand regsiter V but what is the importance of register T ?
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Background rendering
T is the "scroll" setting.
T is used to automatically reload V at the top of the screen to start drawing the new frame with the desired scroll.
It also partially reloads V at the end of every line, just the horizontal bits, again to keep the desired scroll position.
T is used to automatically reload V at the top of the screen to start drawing the new frame with the desired scroll.
It also partially reloads V at the end of every line, just the horizontal bits, again to keep the desired scroll position.
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
sorry I didn't get itrainwarrior wrote:T is the "scroll" setting.
T is used to automatically reload V at the top of the screen to start drawing the new frame with the desired scroll.
It also partially reloads V at the end of every line, just the horizontal bits, again to keep the desired scroll position.
what will I lose without it ?
shouldn't the registers when rolled over return to the top left ?
Re: Background rendering
The horizontal and vertical parts are reset separately. Every scanline, the horizontal part is reset (copied from T to V) back to the left, but the vertical part simply increments to the next scanline.Muhammad_R4 wrote:shouldn't the registers when rolled over return to the top left ?
-
- Posts: 66
- Joined: Sat Jun 25, 2016 5:33 am
Re: Background rendering
then how T is edited during the entire frame ?
I only read that V is reloaded from T , but the data in T how it is calculated ?
I only read that V is reloaded from T , but the data in T how it is calculated ?