HDMA Sprite demo not working...

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
HDMA Sprite demo not working...
by on (#137051)
Sorry, for posting some thing like this, but I am starting to grow frustrated with trying to change different sprite attributes while the screen is being rendered with HDMA. I have created a code that clearly doesn't work as shown bellow that uses the "Walker" demo from the SNESstarterkit as a base.

Attachment:
Strange.png
Strange.png [ 1.15 KiB | Viewed 2888 times ]



Now here is the code behind it:

STZ $420C ; stop HDMA from last frame
LDY #$0404 ; information about the transfer and where to transfer (both bytes being 04 is just a coincidence)
STY $4310 ; CPU -> PPU, auto increment, 4 bytes
LDY #HDMASpriteTable
STY $4312 ; source offset
LDA #$00
STA $4314
LDA #$02
STA $420C ;start HDMA transfer

Now somewhere else in the code...

HDMASpriteTable:
.DB $90,$70,$A0,$00,$30
.DB 0

Now if anyone knows what's wrong, don't hesitate to tell me.
Re: HDMA Sprite demo not working...
by on (#137052)
Quote:
Sorry, for posting some thing like this, but I am starting to grow frustrated with trying to change different sprite attributes while the screen is being rendered with HDMA.

This is simply not possible to do I guess.
Re: HDMA Sprite demo not working...
by on (#137053)
So there is nothing wrong with what I wrote, It's just that the SNES doesn't accept you doing it? I guess that's why I've never seen it done before.
Re: HDMA Sprite demo not working...
by on (#137055)
http://problemkaputt.de/fullsnes.htm#sn ... ryaccesses

Quote:
So, aside from the 256 known/used dot-cycles, there may (or may not) be up to 84 unused dot-cycles... possibly allowing to change OAM during Hblank(?).

http://problemkaputt.de/fullsnes.htm#sn ... attributes

Quote:
During rendering, the PPU is destroying the Address register (using it internally for whatever purposes), after rendering (at begin of Vblank, ie. at begin of line 225/240, but only if not in Forced Blank mode) it reinitializes the Address from the Reload value; the same reload occurs also when deactivating forced blank anytime during the first scanline of vblank (ie. during line 225/240).

viewtopic.php?f=12&t=6758#p65562

Quote:
Your write during Hblank will end up going to the high attribute table address of the last sprite the S-PPU fetched. Even if you hit a patch of empty scanlines, the address is still the last sprite fetched. Rewriting OAMADDR during Hblank will not help you.

It's not known to what extent you can modify OAM during HBlank, but it's very tricky at best; Uniracers is the only game that does it.

...

Also, doesn't that code write one byte each to OAMDATA, BGMODE, MOSAIC, and BG1SC without writing to OAMADDL/OAMADDH first? I don't think there is an HDMA mode that writes four bytes in a row to one register, and it seems you can only turn off auto-increment with general-purpose DMA...

EDIT: switched first two links to match the quotes.
Re: HDMA Sprite demo not working...
by on (#137058)
93143 wrote:
It's not known to what extent you can modify OAM during HBlank, but it's very tricky at best; Uniracers is the only game that does it.


But what you are saying is that you CAN at least modify sprites in some way using HDMA? And, If Uniracers DOES do it, why does it? It is not like it's a bullet-hell game or anything. Oh, and how did you even know that?

93143 wrote:
Also, doesn't that code write one byte each to OAMDATA, BGMODE, MOSAIC, and BG1SC without writing to OAMADDL/OAMADDH first? I don't think there is an HDMA mode that writes four bytes in a row to one register, and it seems you can only turn off auto-increment with general-purpose DMA...


I had been lead to believe that writing #%00000100 to $43x0 would mean I would be able to write 4 different bytes to OAM (1st being x location, 2nd being y location, 3rd being character data, and 4th being palette, flip, and priority data)instead of writing to 4 different 21xx registers. Also, I already wrote to $2101 so the SNES would know where to look for the tile data, otherwise, the sprite wouldn't have even appeared (unless I need to write to It again right before the transfer.) Finally, What do I even need to write to $2102? You can probably tell that I'm no programing genius.
Re: HDMA Sprite demo not working...
by on (#137063)
Espozo wrote:
93143 wrote:
It's not known to what extent you can modify OAM during HBlank, but it's very tricky at best; Uniracers is the only game that does it.

But what you are saying is that you CAN at least modify sprites in some way using HDMA? And, If Uniracers DOES do it, why does it?

Not even byuu knows that. All he knows is that he has to emulate writes to HiOAM as he described in the post I linked; otherwise Uniracers doesn't work.

As he says, sprite size and X-position high bit aren't a very useful thing to be able to write to...

Quote:
I had been lead to believe that writing #%00000100 to $43x0 would mean I would be able to write 4 different bytes to OAM (1st being x location, 2nd being y location, 3rd being character data, and 4th being palette, flip, and priority data)instead of writing to 4 different 21xx registers.

You can't write to OAM. You can only write to a register ($2104) that's designed to copy the value you write to it into OAM at the location you specify in $2102-03 - or not, if OAM is locked/otherwise occupied. VRAM and CGRAM work the same way.

Writing %0xxxx100 to $43x0 sets HDMA to write to the target B-bus address ($04 in this case), then the one above it, then the one above that, then finally one more above that. For a similar example, if you want to change CGRAM with HDMA, you'd set $43x0 to %0xxxx011 or %0xxxx111, with the target being $2121. That way, you write the target CGRAM address to $2121 (twice, but what other choice do we have?) and then the colour data to $2122.
Re: HDMA Sprite demo not working...
by on (#137064)
Espozo wrote:
And, If Uniracers DOES [modify sprites during the picture], why does it? It is not like it's a bullet-hell game or anything.

Just a guess, but split screen usually means you need to keep sprites from penetrating from one player's view to the other's.
Re: HDMA Sprite demo not working...
by on (#137068)
So I finally fixed my code to where I'm not writing to 4 different registers and surely enough, the game was back to normal as in the background was fixed, but nothing happened sprite-wise (in zsnes, no sprites would even appear on the screen, which really shows how "accurately" it emulates the SNES). After reading what byu said changing OAM using HDMA and how the values go wherever they want to, It seem overly complicated and not really worth it. Also, what is force blank? does the screen get shut off while its rendering and allow you to write some values over again? I heard byu say it's how Super Mario Kart is able to change all the sprites around. Lastly, can force blank happen more than once and how do you set it up?
Re: HDMA Sprite demo not working...
by on (#137074)
Espozo wrote:
It seem overly complicated and not really worth it.

I suppose that would depend on what you managed to get it to do. The bullet hell form of this trick would be epic, but I'm not sure it's possible, and even if it is it might be prohibitively finicky...

Quote:
Also, what is force blank? does the screen get shut off while its rendering and allow you to write some values over again? I heard byu say it's how Super Mario Kart is able to change all the sprites around. Lastly, can force blank happen more than once and how do you set it up?

http://problemkaputt.de/fullsnes.htm#snesppucontrol

Force blank (or forced blank) is just the state where bit 7 of $2100 is set, meaning the display is turned off. Rendering doesn't happen, and a black signal is sent to the TV. In this state, you can send data to VRAM, CGRAM and OAM freely, as if the screen were in vertical blanking (though it's been suggested there might be a delay before VRAM opens up, which I suppose might apply to OAM too). You can do this whenever you want, on an interrupt or whatever, just by writing to $2100. I imagine you could even set up HDMA to do it...

http://wiki.superfamicom.org/snes/show/Registers

Quote:
Note that force blank CAN be disabled mid-scanline. However, this can result in glitched graphics on that scanline, as the internal rendering buffers will not have been updated during force blank. Current theory is that BGs will be glitched for a few tiles (depending on how far in advance the PPU operates), and OBJ will be glitched for the entire scanline.

If I recall correctly, the above is why you can't use it during HBlank to force OAM open... or can you? Based on fullsnes, I suspect that if a lot of sprites are present, turning the display off during HBlank would cause the PPU to not do certain critical steps to prepare the sprites for the next scanline, but it looks like the theory is tentative in this area, and I can't recall if there's another reason not to do this.

It has been stated pretty bluntly that force blank during HBlank is incompatible with sprites: viewtopic.php?f=12&t=11920&start=15#p135154
I have a feeling I should know why this is, but I can't think of it right now.

I have noticed that even higan's accuracy core doesn't correctly emulate the effect of turning on the display too late during HBlank (the real system will glitch where higan won't). This is edge case territory, so if you wanted to find anything out you'd have to test on hardware. I might try it myself some time...
Re: HDMA Sprite demo not working...
by on (#137077)
Well, I tried to turn off the screen using HDMA and this is what I got... (I'm a work in progress)

Attachment:
strange2.png
strange2.png [ 1.4 KiB | Viewed 2813 times ]


At least something IS being done with $2100 as there are black bars running horizontally across the screen (that aren't BG's or Sprites).

Again... Here's what I wrote:

LDA #$80
STA $2100 ; Turn the screen back on

STZ $420C
LDA #$00
STA $4310 ; CPU -> PPU, auto increment, write 1 reg, $2100
LDA #$00
STA $4311
LDY #ForceBlankTable
STY $4312 ; source offset
LDA #$00
STA $4314 ; bank address = $7E (work RAM)
LDA #$02
STA $420C ;start HDMA transfer

Later...

ForceBlankTable:
.DB $60,$80 ; Turns off the screen after line $60
.DB 0

Regarding updating everything while the screen is off, how do you arrange everything? Would you put the part that gets updated in force blank between where you turn the screen off and where you turn the screen on? (If that makes any sense) Also, about graphics being messed up after force blanking mid screen, How is Super Mario Kart able to transfer sprite Data using force blank then? I don't see any abnormalities with the graphics.

Lastly, How would you be able to test the games on real hardware? I'm guessing there is some sort of way to burn custom ROMs on an SNES cartridge? I know that there are special carts that people have made that allow you to play games from an SD card like the SD2SNES, but personally, I don't think my mother would let me buy a $200 cart (you have no idea how hard it was for me to convince her to get R-Type III :roll: )
Re: HDMA Sprite demo not working...
by on (#137078)
One cheap way to get started is the INL-HiLoROM flash cart from infiniteneslives.com.
Re: HDMA Sprite demo not working...
by on (#137079)
Thanks for the information. Oh, tepples, while you're hear, can you explain why force blank during HBlank is incompatible with sprites like you said in that one topic I wrote? (sorry for filling up a full post with just this...)
Re: HDMA Sprite demo not working...
by on (#137080)
The NES PPU fetches sprite patterns during horizontal blanking. Based on what I know about the Super NES's background fetch pattern, as well as the difference between the 32 sprite and 34 sliver limits, it's overwhelmingly likely that the Super NES PPU does likewise. So you won't get any sprites on the line after the horizontal blanking period in which you forced blanking.
Re: HDMA Sprite demo not working...
by on (#137081)
tepples wrote:
So you won't get any sprites on the line after the horizontal blanking period in which you forced blanking.


Will you get sprites on consecutive lines though? Oh, When you were talking about 32 sprites per scan line and everything like that, it reminded me of a question I was eventually going to ask. I know that the SNES has 272 sprite pixels per scan line, but what counts as a sprite pixel? Does the whole width of the sprite count toward the sprite pixel per scan line, or just any tile with information on it? E.g. an 8x8 bullet tile in a 16x16 sprite. Also, do color 0 pixels count toward the sprite pixel per scan line limit in those tiles? Lastly, are pixels from a sprite that is partially off screen count toward the limit?
Re: HDMA Sprite demo not working...
by on (#137083)
Espozo wrote:
I know that the SNES has 272 sprite pixels per scan line

Which equals 34 8x1 pixel slivers. It takes two dots during hblank to fetch each sliver.

Quote:
but what counts as a sprite pixel? Does the whole width of the sprite count toward the sprite pixel per scan line

Yes. The PPU doesn't know that part of the width is unused until it has spent time fetching all slivers in the width.

Quote:
Also, do color 0 pixels count toward the sprite pixel per scan line limit in those tiles?

Yes. The PPU doesn't know that the pixels in a sliver are color 0 until it has spent time fetching the sliver.

Quote:
Lastly, are pixels from a sprite that is partially off screen count toward the limit?

Apparently so, as long as -w <= x <= 256. (Yes, that's <= and not the more efficient < because Nintendo was lazy.) If you want to hide a sprite, put it at (384, 224).
Re: HDMA Sprite demo not working...
by on (#137084)
Espozo wrote:
LDA #$80
STA $2100 ; Turn the screen back on

STZ $420C
LDA #$00
STA $4310 ; CPU -> PPU, auto increment, write 1 reg, $2100
LDA #$00
STA $4311
LDY #ForceBlankTable
STY $4312 ; source offset
LDA #$00
STA $4314 ; bank address = $7E (work RAM)
LDA #$02
STA $420C ;start HDMA transfer

Later...

ForceBlankTable:
.DB $60,$80 ; Turns off the screen after line $60
.DB 0

Two things: first, it looks like your "turn the screen back on" part actually turns it off. You have to write $0 (or something less than $8) to the high nibble, and something nonzero to the low nibble because that's what controls the screen brightness - if you want full brightness, as is probable, you should write $0F to $2100 to turn the screen on.

Second, why are you taking your HDMA table values out of WRAM? Is the table actually in WRAM?

Also, the first part of your code is in the NMI routine, right?

Quote:
Regarding updating everything while the screen is off, how do you arrange everything? Would you put the part that gets updated in force blank between where you turn the screen off and where you turn the screen on?

Generally you'd use an IRQ. HDMA isn't so useful for this in most cases, because it's not synchronized with the main code. You'd need to be writing raster-aligned cycle-timed code to fit ordinary processing or general-purpose DMA in between two specific scanlines, and that's a very advanced programming technique; I can't help you with such a thing...

But with an IRQ, you have a whole separate chunk of code that's guaranteed to run at a certain position on the screen, so you can turn off the display, do whatever needs to be done, and then turn it back on.

You can even have the IRQ fire at different times to do different things; the IRQ code itself can change the settings for when it's supposed to fire ($4200 and $4207-420A), and change a variable in RAM or something each time, so it can check that variable at the start and branch to the appropriate task. This can be useful even in a basic case like the Mario Kart split screen, if you can't guarantee that your IRQ code will take exactly the right amount of time - rather than cycle counting with NOPs or polling the H/V counters, just repurpose the IRQ to turn the screen back on (and then un-hijack it again so it works properly during the next frame, obviously).

Quote:
Also, about graphics being messed up after force blanking mid screen, How is Super Mario Kart able to transfer sprite Data using force blank then? I don't see any abnormalities with the graphics.

That's only for the same scanline. I assume Mario Kart re-enables rendering soon enough after the end of the last blank scanline that the next scanline works fine.

I suppose if this was causing trouble, you could re-enable the screen early at zero brightness (write $00 to $2100), and then bump it to full brightness ($0F) at the point where you actually wanted it turned on. Now that I think about it, sprites are scanned and cached during the scanline above the one where they're displayed, and I doubt that happens during forced blank, so this may be what SMK is actually doing...

...maybe I should back off and let an actual expert handle this...

Quote:
Lastly, are pixels from a sprite that are off screen count toward the limit?

No. If all parts of a sprite are off screen, it doesn't count towards the 32-sprite limit, and if a tile is off screen it doesn't count towards the 34-tile limit.

...except when the sprite is at $0100 exactly, in which case all of its tiles count towards the tile limit. Basically, never put a sprite at X=256, especially a big one; no good can come of it.
Re: HDMA Sprite demo not working...
by on (#137098)
93143 wrote:
...except when the sprite is at $0100 exactly, in which case all of its tiles count towards the tile limit. Basically, never put a sprite at X=256, especially a big one; no good can come of it.

So that is why the Nintendo documentation says to never allow a sprite at those coordinates no matter what (though sadly they never explain the reason). Huh, I wonder what they had screwed up in the process. I guess it can still help if you need to do sprite clipping though (nowhere near as easy as Sega's own screw-up though where a single sprite would clip every single one after... later they tried to claim that bug was a feature =P).
Re: HDMA Sprite demo not working...
by on (#137101)
93143 wrote:
it looks like your "turn the screen back on" part actually turns it off.


Oops, my bad...

93143 wrote:
Second, why are you taking your HDMA table values out of WRAM? Is the table actually in WRAM?


I'm actually taking it from bank 0 ($00 is bank 0 right?), it's just that I accidentally forgot to change some of the leftover writing I got from another code.

93143 wrote:
Also, the first part of your code is in the NMI routine, right?


The whole thing is.

93143 wrote:
I suppose if this was causing trouble, you could re-enable the screen early at zero brightness (write $00 to $2100), and then bump it to full brightness ($0F) at the point where you actually wanted it turned on.


After playing Super Mario Kart again, I actually noticed that there is a thin black line that runs between the two screens, which might actually be there to hide the messed up graphics.

93143 wrote:
Now that I think about it, sprites are scanned and cached during the scanline above the one where they're displayed, and I doubt that happens during forced blank, so this may be what SMK is actually doing....


??? Are you saying that Super Mario Kart uses forced blank, because I thought that had already been determined.

93143 wrote:
...maybe I should back off and let an actual expert handle this...


Some help is better than none! But seriously, where's byu when you need him? :roll: It would have been extremely helpful if he bothered to figure out Uniracers... Oh, didn't byu actually say that writing to OAM during h-blank will send your values to where the PPU was last working? would it be possible to somehow align it or something to where it goes to the right place based on the rest of your code or something? Or did he say that it is only possible to write to high OAM during h-blank? I'm kind off starting to eliminate using forced blank if it's going to output messed up graphics. (didn't someone say it actually messes up BG tiles?)

Sik wrote:
93143 wrote:
...except when the sprite is at $0100 exactly, in which case all of its tiles count towards the tile limit. Basically, never put a sprite at X=256, especially a big one; no good can come of it.

So that is why the Nintendo documentation says to never allow a sprite at those coordinates no matter what (though sadly they never explain the reason).


Nintendo's docs are a bit of a disaster...
Re: HDMA Sprite demo not working...
by on (#137114)
tepples wrote:
If you want to hide a sprite, put it at (384, 224).


When I place sprites off-screen, I don't change the x-coordinates, only the y-coordinates. You probably know why.
Re: HDMA Sprite demo not working...
by on (#137119)
Espozo wrote:
93143 wrote:
I suppose if this was causing trouble, you could re-enable the screen early at zero brightness (write $00 to $2100), and then bump it to full brightness ($0F) at the point where you actually wanted it turned on.

After playing Super Mario Kart again, I actually noticed that there is a thin black line that runs between the two screens, which might actually be there to hide the messed up graphics.

That line is what forced blank looks like. You wouldn't have time to rearrange much of OAM during HBlank even if you did turn off rendering during it; a full OAM update takes more than three scanlines of pure DMA. And Mario Kart might have other things to do between the two screens besides the OAM update. So it blanks the display for several scanlines to get it all done.

Quote:
93143 wrote:
Now that I think about it, sprites are scanned and cached during the scanline above the one where they're displayed, and I doubt that happens during forced blank, so this may be what SMK is actually doing....

??? Are you saying that Super Mario Kart uses forced blank, because I thought that had already been determined.

No, I'm saying that if force blank (which SMK uses) prevents sprite prefetch from happening, maybe there's an extra scanline or so of rendering at zero brightness (write #$00 to $2100) after the blanked area, to allow the sprites to work properly on the top scanline of player 2's screen. It's not like you could visually tell the difference between (a) 8 scanlines of forced blank and (b) 7 scanlines of forced blank plus one scanline rendered at zero brightness...

In other words, a thin line to hide the messed up (or absent) graphics, at the bottom of the thicker line that's actually forced blank in order to let the game write to OAM.

Maybe. I haven't investigated it, and I don't have enough experience to say whether or not it's necessary.

I'm pretty sure BG layers work fine a few tiles after force blank is turned off, so as long as you disable force blank early enough after HBlank starts, the next scanline's BG layers should work normally. At least, I've done it with a single 8bpp layer in mode 3. It's only sprites that need extensive preprocessing.

Quote:
Nintendo's docs are a bit of a disaster...

I would recommend this and this if you find Nintendo's manual hard to work with. They're much easier to search in, for one thing...
Re: HDMA Sprite demo not working...
by on (#137127)
93143 wrote:
That line is what forced blank looks like. You wouldn't have time to rearrange much of OAM during HBlank even if you did turn off rendering during it; a full OAM update takes more than three scanlines of pure DMA. And Mario Kart might have other things to do between the two screens besides the OAM update. So it blanks the display for several scanlines to get it all done.

Doesn't that mean you could actually force blank 1/4 of OAM on one line and there wouldn't be any graphical side effects, Or would the line still be messed up? Or will it still be messed up because it can't "pre fetch" or whatever? It might be worth it to have 4 lines of messed up sprites if it means you could push twice the amount of sprites on screen. (it would probably look better if there were four spread out lines)

93143 wrote:
I'm pretty sure BG layers work fine a few tiles after force blank is turned off, so as long as you disable force blank early enough after HBlank starts, the next scanline's BG layers should work normally. At least, I've done it with a single 8bpp layer in mode 3. It's only sprites that need extensive preprocessing."]

Do you mind showing me what you wrote? :oops: I'm not completely sure how to set it up.

93143 wrote:
I would recommend this and this if you find Nintendo's manual hard to work with. They're much easier to search in, for one thing...

Thank You! :D I knew about superfamicom.org, but the other website is also very helpful

Oh yeah, If we ever did pull off this stunt, how would you set it up? Say if you wanted 256 sprites, would you create another table in ram that replaces the values of the original sprite table as you go down the screen? And how would you transfer 1 sprite from the top off the screen to the bottom? Would you check to see if the sprites y value is greater than where the line is, store the values of that sprite on the other sprite table, and then turn off the sprite on the first sprite table? Doing this with all 128 sprites seems like it would take a lot of time though...

Just wondering, do you know how Bullet GBA does it? (if you even know what I'm talking about)
Re: HDMA Sprite demo not working...
by on (#137131)
On the GBA, OAM and VRAM are writable even during draw time, like on the TG16 and Genesis. It's how the GBA port of Super Puzzle Fighter II draws its playfields.
Re: HDMA Sprite demo not working...
by on (#137134)
Actually, to my knowledge, on the GBA OAM and OAM VRAM are read-only during scanline rendering* They can only be written to during HBlank, VBlank, or Forced Blank. For HBlank, there is the additional requirement that you flip a certain bit in one of the GBA's display registers (DISPCNT) to allow the H-Blank Interval Free feature. I believe all DMAs to OAM and OAM VRAM require H-Blank Interval Free too. H-Blank Interval Free has the consequence of reducing the number of cycles available for rendering sprites on a given scanline. The maximum number of sprites under H-Blank Interval Free actually depends on a number of other factors based on what types of sprites are used.

*EDIT: Actually, I don't even know if that "read-only" bit is true. Current documentation just mentions an "access" to OAM is only available during blanking periods, not necessarily a "read".

Now, I have not written any test ROMs to verify this behavior on my hardware, but nocash and Nintendo's official docs both imply that OAM and OAM VRAM can only be modified at specific blanks. Palette data and BG VRAM are fair game for reading and writing at any given moment, however, if you can bear with the few extra cycles it takes for memory access. Overall though, it's a lot more flexible than the GB or GBC ever were.

For reference:
http://problemkaputt.de/gbatek.htm#lcdiodisplaycontrol
http://problemkaputt.de/gbatek.htm#lcdobjoverview
Re: HDMA Sprite demo not working...
by on (#137136)
Shonumi wrote:
H-Blank Interval Free has the consequence of reducing the number of cycles available for rendering sprites on a given scanline.

Without: 5x overdraw
With: 4x overdraw
(Assumes no rot/scale sprites)

Compare to ~1x overdraw for Super NES, Genesis, and TG16
Re: HDMA Sprite demo not working...
by on (#137141)
Espozo wrote:
93143 wrote:
That line is what forced blank looks like. You wouldn't have time to rearrange much of OAM during HBlank even if you did turn off rendering during it; a full OAM update takes more than three scanlines of pure DMA. And Mario Kart might have other things to do between the two screens besides the OAM update. So it blanks the display for several scanlines to get it all done.

Doesn't that mean you could actually force blank 1/4 of OAM on one line and there wouldn't be any graphical side effects, Or would the line still be messed up? Or will it still be messed up because it can't "pre fetch" or whatever? It might be worth it to have 4 lines of messed up sprites if it means you could push twice the amount of sprites on screen. (it would probably look better if there were four spread out lines)

I don't think you're getting this. Force blank isn't something you do to OAM. It means turning the screen off. The fact that you can access OAM while the screen is off is a side effect. And since OAM is 544 bytes and DMA is only 1324 bits per scanline, you'd need to turn the screen off completely for more than three scanlines to update all of OAM in one shot. Those scanlines would be black, not because of the OAM refresh but because you turned off the screen.

While the screen is off, the PPU isn't keeping track of what it would otherwise be doing. This means that if you turn the screen on partway through the active display portion of a frame, it takes a while for the PPU to figure out what's going on. In the case of BG layers, it's a few tiles. In the case of sprites, it's a whole line. So the line under the black area would (we think) have no sprites, or glitched sprites. (Unless you set the screen to zero brightness for the duration of that line, in which case it too would be black.)

So in your example, you'd get one black scanline (during which you can do a partial OAM update), probably followed by one line with sprites absent or not working properly, and then the picture would work normally for subsequent scanlines.

Quote:
93143 wrote:
I'm pretty sure BG layers work fine a few tiles after force blank is turned off, so as long as you disable force blank early enough after HBlank starts, the next scanline's BG layers should work normally. At least, I've done it with a single 8bpp layer in mode 3. It's only sprites that need extensive preprocessing.

Do you mind showing me what you wrote? :oops: I'm not completely sure how to set it up.

I don't really mind, but be aware that there may be a vulnerability in it, so you shouldn't slavishly copy what I've done... I was using force blank to extend VBlank, and using the IRQ as a substitute for NMI (since you can't change when NMI triggers). Here's the relevant part of my code:

Code:
.ENUM $10
disp        db         ; screen brightness; can be given to $2100 to turn the screen on
end_vblank  db         ; IRQ toggle flag
.ENDE
Code:
   ldx #$00B0          ; dot number for interrupt
   stx $4207           ; set H-timer
   ldx #$00DC          ; scanline number for interrupt
   stx $4209           ; set V-timer
   stz end_vblank      ; initialize IRQ switch
Code:
   lda #$31            ; enable IRQ and controller autopoll
   sta $4200
Code:
Interrupt:
   phb
   pha
   phx
   phy
   phd
   php

   rep #$30            ; all 16-bit
   lda #$0000.w        ; reset direct page
   tcd
   sep #$20            ; mem/A = 8 bit
   lda #$00            ; ...but A should already be zero...
   pha
   plb                 ; reset data bank

   lda end_vblank
   beq begin_vblank
   ldx #$00B0          ; dot number for interrupt
   stx $4207           ; set H-timer
   ldx #$00DC          ; scanline number for interrupt
   stx $4209           ; set V-timer
   stz end_vblank      ; toggle IRQ
   lda disp            ; turn the screen back on (brightness stored in RAM)
   sta $2100
   jmp end_interrupt

begin_vblank:
   lda #$80            ; turn the screen off
   sta $2100
   ldx #$0090          ; dot number for interrupt
   stx $4207           ; set H-timer
   ldx #$0004          ; scanline number for interrupt
   stx $4209           ; set V-timer
   inc end_vblank      ; toggle IRQ

   ; VBLANK CODE GOES HERE

end_interrupt:
   lda $4211           ; clear interrupt flag

   plp
   pld
   ply
   plx
   pla
   plb

   rti


PLEASE NOTE that there is a sporadic timing-sensitive bug hiding somewhere in the program I took this from, and removing the lda #$00 from the direct page and data bank reset code near the top of the IRQ triggers the bug. (Actually, I can replace the lda #$00 with two nops and it will still work, which is very odd as with the lda #$00 there I can delete both lda #$0000.w and tcd and it will still work...) I am not a guru; use my code with caution.

Better yet, don't use my code at all. Look at it, figure out what it does, and then write your own.

Oh, and if any of the experts on here can tell what might be going wrong (the bug doesn't affect the IRQ; it results in a subroutine the IRQ is interrupting occasionally getting a calculation wrong), please speak up...

Quote:
Oh yeah, If we ever did pull off this stunt, how would you set it up?

I haven't really worked it out yet. The details probably depend on how well it works, if it does (which is looking increasingly unlikely, unless you're willing to accept graphical artifacts). But you sound like you might be on the right track.

As for me, I can't spend a whole lot of time on this right now, because I have a ton of work to do and I'm behind schedule...
Re: HDMA Sprite demo not working...
by on (#137217)
93143 wrote:
what might be going wrong (the bug doesn't affect the IRQ; it results in a subroutine the IRQ is interrupting occasionally getting a calculation wrong), please speak up...

One thing that comes to mind is that your irq is nuking the high byte of the accumulator. If an irq were to be raised when the accumulator is 8 bit and the hidden high byte contains data, it'll contain garbage once the interrupt returns, since you're only pushing the low byte in the irq prologue. The same goes for x/y too, although that's less common.
Here's how I would do it:
Code:
irqHandler:
 rep #$30 ; always preserve the full 16 bits of a/x/y registers
 pha
 phx
 phy
 phb
 phd
 ...
 rep #$30
 pld
 plb
 ply
 plx
 pla
 rti ; irq preserves the psr on 65816, hence we don't have to php/plp with this approach
Re: HDMA Sprite demo not working...
by on (#137242)
[*facepalm*]

That would explain it nicely. Especially since the only part of the entire interrupt routine that touches B is the direct page reset, which is what I had originally removed to fix the problem.

Rewriting the IRQ intro and outro as recommended results in a working code, with or without the extra lda #$00 or a string of between one and five nops. Looks good. Feels good.

Thanks!

...

Is there anything important about the order of the stack operations? I mean, other than having to pull in reverse order to the pushes?