Discussion about software development for the old-school Gameboys, ranging from the "Gray brick" to Gameboy Color
(Launched in 2008)
You are not logged in.
Am I understanding all this this correctly.
My thoughts
The gb is drawing the screen - during this time i cant access the gfx data
but i can do updating logic.
Then you sit and wait patiently for the vblank to fire.
Then the vblank is triggered, a time where no screen is drawing and the gfx can be updated during this short window.
then you go back to logic and repeat.
Is that the general idea? Because i assumed then it would be
logic
wait for vblank
update graphics
repeat
But In my code, the screen seems choppy if I do it this way.
Instead to remove that choppy I do
logic
rendering
wait_vbl_done();
Or is my mistake in thinking wait_vbl_done(); is for the start of vblank and not the end?
https://gbdk-2020.github.io/gbdk-2020/d … b545a55619
says HALTs the CPU and waits for the vertical blank interrupt (VBL) to finish.
Does that finish mean the start of vblank or its end.
Or do i misunderstand the whole thing,
Offline
Neither, kind of. wait_vbl_done() will wait until the VBlank interrupt finishes. When LY becomes 0x90, a VBlank interrupt is requested. The VBlank handler runs whatever routines are registered for the interrupt. Then it writes 1 to a variable to signal that it is done. wait_vbl_done() will return when it sees that this variable is 1.
Exactly when this happens depends on how long the interrupt took to execute. By default, the only routine registered is OAM DMA to update sprites. This is quick enough that there's still time in VBlank to do stuff before the VBlank period runs out. A common way to handle things would be to register your own routine that runs through the VBlank interrupt. See for example the IRQ example included in GBDK-2020.
What you're describing seems like you either have a problem with your game logic, or your code is simply too slow to finish within a frame.
Consider the following:
Logic
** VBlank intrrupt happens because logic took too long
Logic continues running
call wait_vbl_done()
** VBlank interrupt happens
return from wait_vbl_done()
Update graphics
As you can see, now it will take two frames before the logic and graphics for one game frame is complete, and you have a lag frame. In this case you somehow need to optimize your code.
Look at the CPU meter in BGB. Does it quickly flicker a lot between 100% and something less than 100%? This indicates that what I described above is happening.
Seeing some code might help spot the problem as well.
Offline
My code would bring sadness to you, but if you are in a hurry to cry my rendering is https://pastebin.com/yMsDFzrf
Its definitely the drawing not logic, because if i comment it out the cpu barely moves.
I'm not sure I can handle gameboy, just so little time to use.
It is the cpu thing fill up i checked on bgb. gbc : https://www.dropbox.com/s/xloef4ieb14pt … t.gbc?dl=1
I tried to also gather the tiles into a circular queue to separate figuring out what tiles to update and actually doing it, but it didn't seem to help.
I'm not sure how I'm supposed to write this code properly.
I removed using non powers of two so all those macros are
#define TILE_SIZE 8u // pixels per tile w or h
#define META_TILE_SIZE 16u // pixels per meta tile w or h
#define META_TILE_COUNT 2u // how many tiles in a metatile
#define META_TILE_SCREEN_WIDTH 10u // 10 metatiles per screen width
#define META_TILE_SCREEN_HEIGHT 9u // 9 metatiles per screen height
#define CHUNK_TILES 32u // tiles per chunk ( width and height )
#define CHUNK_META_TILES 16u // metatiles per chunk ( width and height )
#define CHUNK_META_TILE_REM( val ) ( val & 15u ) // val % 16 ( val % CHUNK_META_TILES )
#define PIXEL_TO_TILE( val ) ( val >> 3u ) // val / 8 ( val / TILE_SIZE )
#define PIXEL_TO_META_TILE( val ) ( val >> 4u ) // val / 16 ( val / META_TILE_SIZE )
#define TILE_TO_META_TILE( val ) ( val >> 1u ) // val / 2 ( val / META_TILE_COUNT )
#define PIXEL_TO_CHUNK( val ) ( PIXEL_TO_TILE( val ) >> 5u ) // ( val / 8 ) / 32 ( ( val / TILE_SIZE ) / CHUNK_X_TILES )
#define META_TILE_TO_CHUNK( val ) ( val >> 4u ) // val / 16 ( val / CHUNK_META_TILES )
#define CHUNK_TO_META_TILE( val ) ( val << 4u ) // val * 16 ( val * CHUNK_META_TILES )
#define META_TILE_TO_TILE( val ) ( val << 1u ) // val * 2 ( val * META_TILE_COUNT )
#define TILE_TO_PIXELS( val ) ( val << 3u ) // val * 8 ( val * TILE_SIZE )
and where i couldn't make it a power of 2 i made a LUT.
eg.
g_current_chunk->tile_y_offset[ tile_y ]
g_current_map->chunk_y_offset[ META_TILE_TO_CHUNK( meta_tile_y ) ]
so they just look up the value instead of a multiplication (which did help)
Edit:
Just tried enabling the double cpu mode and it runs smoothly, peeking at 75%.
Do ppl normally use the double cpu mode? How much is increasing power consumption ? :p
This is the updated version. You can see it jumps while moving screen, but not much else happens while the screen moves.
https://www.dropbox.com/s/js5kiq2g4u0c6 … e.gbc?dl=1
Last edited by Azenris (2022-04-11 12:38:04)
Offline