This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Background rendering

Background rendering
by on (#175474)
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 )
Re: Background rendering
by on (#175478)
"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.
Re: Background rendering
by on (#175479)
Quote:
check that the coarse X is incremented correctly.


So how it is incremented correctly ?
Re: Background rendering
by on (#175483)
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.
Re: Background rendering
by on (#175487)
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 ?
Re: Background rendering
by on (#175488)
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.
Re: Background rendering
by on (#175489)
Quote:
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


I have a problem with this example

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
by on (#175492)
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
Re: Background rendering
by on (#175493)
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 ?
Re: Background rendering
by on (#175495)
Correct.

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)

But while rendering is on, the VRAM address's carry paths are reconfigured to behave as four independent counters:

  • 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)

The names v and t come from "The skinny on NES scrolling", on which the wiki article about PPU scrolling registers was based. When I have needed longer names for them, lately I've been using "VRAM address" for v and "top left" for t.
Re: Background rendering
by on (#175596)
I may understand regsiter V but what is the importance of register T ?
Re: Background rendering
by on (#175598)
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.
Re: Background rendering
by on (#175601)
rainwarrior 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.


sorry I didn't get it

what will I lose without it ?

shouldn't the registers when rolled over return to the top left ?
Re: Background rendering
by on (#175604)
Muhammad_R4 wrote:
shouldn't the registers when rolled over return to the top left ?

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.
Re: Background rendering
by on (#175610)
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 ?
Re: Background rendering
by on (#175611)
Writes to $2005 and $2006 change t in a manner described in the aforementioned wiki article.
Re: Background rendering
by on (#175616)
T is usually changed during vblank, when the scroll is set. It might be changed during the frame as well, if the game is doing raster effects.
Re: Background rendering
by on (#175851)
thank you all , I have noticed it when I read it again

I have another question now

as stated in nesdev wiki , background buffers are shift registers , and the lower 8 bits are fed to 8x1 mux (for each register of the four registers) and fine_x used as selections for those muxs

my question is how the shift register shifts while the fine_x counts ?! this for sure won't give the right output
Re: Background rendering
by on (#175852)
Fine x doesn't count. Instead, it controls which bits are picked up as they shift past the mux.
Re: Background rendering
by on (#175855)
tepples wrote:
Fine x doesn't count.


How ? I didn't understand
Re: Background rendering
by on (#175856)
Fine x does not change during rendering. The only way it can change is if the program changes it by writing to the horizontal scroll value ($2005.first). If I write 105 ($69) as the horizontal scroll value, fine x becomes 1, as the fine scroll is taken from the low 3 bits of the scroll value, and $69 & $07 (that is, the low 3 bits of $69) is equal to 1. It remains 1 throughout the frame until I set a different horizontal scroll value.


What's the first word in this post that you didn't understand?
Re: Background rendering
by on (#175857)
till your comment

I was thinking of it as a counter XXXX Xxxx the lower 3 bits are the fine and the upper 5 are the coarse

the are used in rendering such that XXXXX -> the tile number , xxx -> a pixel inside the tile no. XXXXX

while rendering , I believed that the is incrementing rendering from left to right


now you destroyed all this :D

so I am very confused now.
Re: Background rendering
by on (#175862)
The upper 5 bits set the starting address in the nametable. The lower 3 bits set the amount by which pixels are delayed (higher = less delay).

Let's say the first four 8x1 pixel slivers on a particular scanline are as follows:

Code:
01002003 03300330 00112233 30020010


Then, for each X from 0 to 23, I break down how this scroll value is decomposed into a starting position and a delay amount:
Code:
x =   0: 00000 000. Coarse X =  0, fine X = 0. Start at tile  0, delay by 8 - 0 = 8
x =   1: 00000 001. Coarse X =  0, fine X = 1. Start at tile  0, delay by 8 - 1 = 7
x =   2: 00000 010. Coarse X =  0, fine X = 2. Start at tile  0, delay by 8 - 2 = 6
x =   3: 00000 011. Coarse X =  0, fine X = 3. Start at tile  0, delay by 8 - 3 = 5
x =   4: 00000 100. Coarse X =  0, fine X = 4. Start at tile  0, delay by 8 - 4 = 4
x =   5: 00000 101. Coarse X =  0, fine X = 5. Start at tile  0, delay by 8 - 5 = 3
x =   6: 00000 110. Coarse X =  0, fine X = 6. Start at tile  0, delay by 8 - 6 = 2
x =   7: 00000 111. Coarse X =  0, fine X = 7. Start at tile  0, delay by 8 - 7 = 1
x =   8: 00000 000. Coarse X =  1, fine X = 0. Start at tile  1, delay by 8 - 0 = 8
x =   9: 00001 001. Coarse X =  1, fine X = 1. Start at tile  1, delay by 8 - 1 = 7
x =  10: 00001 010. Coarse X =  1, fine X = 2. Start at tile  1, delay by 8 - 2 = 6
x =  11: 00001 011. Coarse X =  1, fine X = 3. Start at tile  1, delay by 8 - 3 = 5
x =  12: 00001 100. Coarse X =  1, fine X = 4. Start at tile  1, delay by 8 - 4 = 4
x =  13: 00001 101. Coarse X =  1, fine X = 5. Start at tile  1, delay by 8 - 5 = 3
x =  14: 00001 110. Coarse X =  1, fine X = 6. Start at tile  1, delay by 8 - 6 = 2
x =  15: 00001 111. Coarse X =  1, fine X = 7. Start at tile  1, delay by 8 - 7 = 1
x =  16: 00010 000. Coarse X =  2, fine X = 0. Start at tile  2, delay by 8 - 0 = 8
x =  17: 00010 001. Coarse X =  2, fine X = 1. Start at tile  2, delay by 8 - 1 = 7
x =  18: 00010 010. Coarse X =  2, fine X = 2. Start at tile  2, delay by 8 - 2 = 6
x =  19: 00010 011. Coarse X =  2, fine X = 3. Start at tile  2, delay by 8 - 3 = 5
x =  20: 00010 100. Coarse X =  2, fine X = 4. Start at tile  2, delay by 8 - 4 = 4
x =  21: 00010 101. Coarse X =  2, fine X = 5. Start at tile  2, delay by 8 - 5 = 3
x =  22: 00010 110. Coarse X =  2, fine X = 6. Start at tile  2, delay by 8 - 6 = 2
x =  23: 00010 111. Coarse X =  2, fine X = 7. Start at tile  2, delay by 8 - 7 = 1

When starting coarse X increases by 1, pixels arrive 8 pixels earlier than they would other have. But most of this being earlier is canceled out by the increased delay from fine X = 7 to fine X = 0 (from 1 to 8 pixels, a difference of 7 pixels). I'll run a few tiles for both x = 7 and x = 8 to show how two adjacent scroll values across a tile boundary changes the fetch pattern and which pixel is used.

With a horizontal scroll value of 7 (coarse X 0, fine X 7), the preroll at dots 321-336 has loaded two slivers from coarse X = 0 and coarse X = 1, leaving coarse X at 2.
Code:
SIPO      PISO      CX  Fetch
01002003  03300330   2  Nametable for X=2
10020030  3300330x   2
00200303  300330xx   2  Attribute for X=2
02003033  00330xxx   2
20030330  0330xxxx   2  Pattern plane 0 for X=2
00303300  330xxxxx   2
03033003  30xxxxxx   2  Pattern plane 1 for X=2
30330033  0xxxxxxx   2  Prepare to load sliver into PISO
03300330  00112233   3  Nametable for X=3
33003300  0112233x   3
30033000  112233xx   3  Attribute for X=3
00330001  12233xxx   3
03300011  2233xxxx   3  Pattern plane 0 for X=3
33000112  233xxxxx   3
30001122  33xxxxxx   3  Pattern plane 1 for X=3
00011223  3xxxxxxx   3  Prepare to load sliver into PISO
       ^
Fine X=7

Result:
30330033 00011223


With a horizontal scroll value of 8 (coarse X 1, fine X 0), the preroll at dots 321-336 has loaded two slivers from coarse X = 1 and coarse X = 2, leaving coarse X at 3.
Code:
SIPO      PISO      CX  Fetch
03300330  00112233   3  Nametable for X=3
33003300  0112233x   3
30033000  112233xx   3  Attribute for X=3
00330001  12233xxx   3
03300011  2233xxxx   3  Pattern plane 0 for X=3
33000112  233xxxxx   3
30001122  33xxxxxx   3  Pattern plane 1 for X=3
00011223  3xxxxxxx   3  Prepare to load sliver into PISO
00112233  30020010   4  Nametable for X=4
01122333  0020010x   4
11223330  020010xx   4  Attribute for X=4
12233300  20010xxx   4
22333002  0010xxxx   4  Pattern plane 0 for X=4
23330020  010xxxxx   4
33300200  10xxxxxx   4  Pattern plane 1 for X=4
33002001  0xxxxxxx   4  Prepare to load sliver into PISO
^
Fine X=0
Result:
03300330 00112233


Result from X = 7 (fine X = 7, starting coarse X = 0): 30330033 00011223
Result from X = 8 (fine X = 0, starting coarse X = 1): 03300330 00112233
These are offset by one pixel from each other.

Which is the first line of this diagram that still confuses you?
Re: Background rendering
by on (#175863)
I some how understand some parts of what you said like usage of CX in nametable addressing

I will be really happy if I knew how the fine x changes allover this timing diagram

http://wiki.nesdev.com/w/images/d/d1/Ntsc_timing.png

I think this may solve my problem .
Re: Background rendering
by on (#175867)
Again, the fine X does not change during the scanline.

I want to explain this with a parade analogy. Do they have parades where you live?
Re: Background rendering
by on (#175870)
I really appreciate your help and really thank you

you can explain it in any way you want but in details
Re: Background rendering
by on (#175871)
Say you have a band marching down the street row by row. If you sit in one place, you'll see each of the rows of people. Sit closer to the starting point, and they'll appear earlier. Sit farther from the starting point, and they'll appear later. Now say you have eight lawn chairs next to the street. You can change exactly when each row passes you by sitting in one of those chairs. You don't normally move from one chair to the next during the parade, except perhaps to use the restroom.

Now instead of a marching band, you have a pixel stream coming out of the PISO. If you make pixels appear earlier, they'll appear shifted to the left. (Because TV was invented in an English-speaking country, the screen is scanned from left to right, as in English.) Instead of lawn chairs, you have a mux. Fine X is which chair you're sitting in. And instead of a restroom, there's horizontal blanking.
Re: Background rendering
by on (#175875)
I understand that if the fine x doesn't change ( fixed chair ) I can see the stream pxl by pxl ( row by row )

but what annoys me is the fine x it self , if it will be fixed on 000 all the time ( selecting the least bits of the shift registers ) this may be good as I finally understood as you said it won't change , but if that , why the mux ? why not taking the bits 0 of the four registers forwarding them out of the back.render unit ?

this means that also fine x can change , so , why may I change it ( the chair ) ?
Re: Background rendering
by on (#175876)
Muhammad_R4 wrote:
but what annoys me is the fine x it self , if it will be fixed on 000 all the time ( selecting the least bits of the shift registers ) this may be good as I finally understood as you said it won't change , but if that , why the mux ? why not taking the bits 0 of the four registers forwarding them out of the back.render unit ?

You can scroll by changing only coarse X, but that allows scrolling only in 8-pixel increments. Several games for ZX Spectrum, ColecoVision, and MSX scrolled in 8-pixel increments due to hardware limits, but it's a lot jumpier.

Quote:
this means that also fine x can change , so , why may I change it ( the chair ) ?

You change which chair you're sitting in to advance or delay the whole band. You change fine X to scroll the whole screen in units smaller than 8 pixels.
Re: Background rendering
by on (#175877)
so fixing the mux selection on "000" will work for most games
Re: Background rendering
by on (#175878)
Fixing the mux selection will work with games that only ever scroll horizontally to a multiple of 8 pixels. It should suffice if you plan to make your NES emulator or hardware implementation compatible only with non-scrolling games or games that scroll only vertically. Thus it'll probably work with most of my NROM games, including Concentration Room, Thwaite, RHDE: Furniture Fight, robotfindskitten, and the menu of Action 53.

But it will cause games that scroll horizontally other than to a multiple of 8 pixels to scroll jumpily, and the background scrolling will fall out of synchronization with the movement of sprites. This visible artifact will annoy the player. It may also cause games that use the sprite 0 hit feature to crash, as the opaque part of the sprite may end up not overlapping the opaque part of the background, and thus bit 6 of $2002 never becomes true.
Re: Background rendering
by on (#175899)
so I can say that if I am now implementing background rendering unit without scrolling feature now - only fetches a frame and render it -
this will be good for this right ?
Re: Background rendering
by on (#175911)
My attempt at explaining the background pixel pipeline...

Let's say we are getting to the beginning of the scanline.
16 pixels were already computed. It's 4 bits per pixel here, so it can pick any color from the background palette.

ppppppppPPPPPPPP

Every time the PPU wants to draw a dot, it picks which dot it wants to draw using horizontal fine X. So if it's 0, it takes the left value, if it's 7, it takes the eighth pixel, etc.
Fine x could take ANY of the first 8 pixels here.

Then after that, they all are shifted one pixel to the left.
pppppppPPPPPPPP_

6 dots later, it has drawn 7 pixels...

pPPPPPPPP _______

then one dot later, it has drawn 8 pixels

PPPPPPPP________

After it has finished with the 8 pixels, the 8 new pixels have been calculated and are ready to be drawn, so the ________ can be filled in with new pixel data.
Re: Background rendering
by on (#175939)
Dwedit wrote:
My attempt at explaining the background pixel pipeline...

Let's say we are getting to the beginning of the scanline.
16 pixels were already computed. It's 4 bits per pixel here, so it can pick any color from the background palette.

ppppppppPPPPPPPP

Every time the PPU wants to draw a dot, it picks which dot it wants to draw using horizontal fine X. So if it's 0, it takes the left value, if it's 7, it takes the eighth pixel, etc.
Fine x could take ANY of the first 8 pixels here.

Then after that, they all are shifted one pixel to the left.
pppppppPPPPPPPP_

6 dots later, it has drawn 7 pixels...

pPPPPPPPP _______

then one dot later, it has drawn 8 pixels

PPPPPPPP________

After it has finished with the 8 pixels, the 8 new pixels have been calculated and are ready to be drawn, so the ________ can be filled in with new pixel data.



That's what exactly I am asking about

I can't join the concept of the fine_x which is a part of the first write to 0x2005 register ( i.e. : the horizontal address part of top left tile in the next frame to make scrolling and fine x determine a pixel exactly inside this tile )

I can't join the above with the fine_x used here in BG pipeline

In another words , I understands how it works but don't understand why it is implemented like this , why fine_x is used here

There must be something I can't see and this what I am searching for.

I hope you understand me all :)
Re: Background rendering
by on (#175958)
A total of 34 tiles are shifted through this 16-pixel window during 1 scanline. If you always sampled the same position of this buffer (say, pixel 0), you'd only be able to scroll in 8-pixel increments. In order to be able to scroll the screen smoothly, the PPU uses the fine X scroll to select 1 of 8 possible positions of the window to be sampled.

If I understand correctly, it works something like this:

Code:
          [********] (new tiles)
           |      |
           v      v
[********][********] (16-pixel window)
 |
 v
 01234567 (fine X scroll)

The window is shifted left each time a pixel is rendered, and every 8 pixels, 8 new pixels are read from the pattern tables and put at the top of the window. The fine X scroll determines which pixel of the window will be output to the screen. If the fine scroll is 0, the very first pixel of the first tile will be visible. If it's 1, the first pixel will never be used, because the second pixel will be picked, and so on. The fine X scroll just determines which pixel of the rotating buffer you're gonna use to render the picture.
Re: Background rendering
by on (#175960)
That's my problem , I can understand the relation between selecting a pixels from the BG buffers using fine_x ( which can be changed using first write to 0x2005 )

and its meaning as the pixel in the tile pointed to by the X_Coarse which forms the starting address of top left pixel on scrolling in the next frame.

I will give an example for what confuses me

If first write to 2005 is 001010 001 , this means that - as far as I understood - on the next frame , the top left tile from which scrolling start = the tenth tile , pxl no 001 ( neglecting Y now )

as you all said , this means that in BG pixel pipeline , the mux selection will be 001

my problem now is I can't understand why it works in this way , I want to understand the relation between this write and its meaning as the left top most tile ( fine_X = which pixel inside this tile ) and the selection of this BG pipeline mux.
Re: Background rendering
by on (#176056)
The SIPO produces eight background pictures on its outputs:
  • A picture
  • The same picture scrolled left by one pixel
  • The same picture scrolled left by two pixels
  • The same picture scrolled left by three pixels
  • The same picture scrolled left by four pixels
  • The same picture scrolled left by five pixels
  • The same picture scrolled left by six pixels
  • The same picture scrolled left by seven pixels

The fine X scroll controls which of these pictures is actually sent to the rest of the PPU.