AntonioND / nitro-engine

3D engine for the Nintendo DS
150 stars 10 forks source link

[Bug] Dual 3D mode renders models on the opposite screen #21

Closed SospectGuy58 closed 11 months ago

SospectGuy58 commented 1 year ago

In dual 3D mode, models drawn by the function that runs on the main screen are rendered on the sub screen and vice-versa; this doesn't seem to happen with sprites/GUI elements, only models

For example, the landscape model here is supposed to be rendered on the main screen (currently set to the top screen), but instead renders on the other one image image image

Here this sprite is rendered correctly on the main screen image

AntonioND commented 1 year ago

Are you using this group of functions? https://github.com/AntonioND/nitro-engine/blob/db33780b45da84dcdb7aeb7e763dcff995469f04/include/NEGeneral.h#L90-L102 If you use the libnds functions directly, NE_ProcessDual() will switch it back.

SospectGuy58 commented 1 year ago

I haven't used any of these functions, so the main screen should be the one on top by default; even the console correctly prints there, the model just switches screens for no apparent reason. One thing I have noticed just now while testing is that the model does render on the top screen for one frame, then immediately moves to the bottom; again, the screens aren't touched at all at runtime

AntonioND commented 1 year ago

How are you calling swiWaitForVblank() and NE_ProcessDual()? Can you show me your main loop, and how you enter it?

SospectGuy58 commented 1 year ago

It is essentially identical to the one in the samples: https://github.com/SospectGuy58/HelloGuestDS/blob/e0f061bdbc8a74614090e37ddc465bc132dbe0d0/source/main.c#L19-L57

AntonioND commented 1 year ago

I've taken a look at this, and the problem is when the game goes under 60 FPS there is no stable way to keep dual 3D going in a stable way. This is a big issue, I'll try to fix it this weekend. The idea is that, somehow, if the game is too slow for a bit, the engine should be able to at least recover the right screen locations. Preferably, the state of the last frame should be preserved until a new frame is ready..

AntonioND commented 1 year ago

Well, there is a change I could make to ensure that dual 3D is stable even if the framerate drops. However, it will break the debug console and the special effects (sine and noise https://github.com/AntonioND/nitro-engine/tree/db33780b45da84dcdb7aeb7e763dcff995469f04/examples/effects/screen_effects). I don't care a lot about the special effects, but the text console is important. All my dual 3D examples rely on using the text console to print instructions, for example. Even this demo you've linked to uses it because it's just convenient to have it.

There is another technique that can be used, but it will have a significant CPU cost as it essentially involves doing a DMA copy of the bitmap of the screen, which is quite a bit.

For now, a workaround could be to call NE_ProcessDual() from a VBL handler function, I guess, and to ensure that there is always a function to be called to draw polygons (even if the number of polygons you draw is 0).

This isn't the final result, I'm still thinking about how to do this properly.

SospectGuy58 commented 1 year ago

Thank you for taking the time to look into it - I just tested the temporary solution, and yeah it does drag down performance by a significant amount. I'll stay tuned for any future updates on this!

AntonioND commented 11 months ago

Okay, so I've been working on this for the last few weeks (slowly, yeah, but getting this to work was quite frustrating). I've created a new 3D mode in Nitro Engine thanks to the instructions of @Gericom: https://github.com/AntonioND/nitro-engine/commit/7915ee80d3820402c9e2e86931165fe6510ccdc0

This should ensure that the output is stable even when the framerate drops, I've added an example to test this: https://github.com/AntonioND/nitro-engine/tree/e1662b7357b56f9bf04456bc27c014ca2f1d40f7/examples/other/safe_dual_3d_low_framerate

However, with your HelloWorldDS demo I still get the screen swap. I'll leave this issue open for a bit, there must be something I'm missing.

EDIT: Also, note that some of the functions are still going to change! I'm trying to figure out how to give enough flexibility with dual 3D.

AntonioND commented 11 months ago

@SospectGuy58 I think I may have fixed the issue. Do you mind trying with the current master? I've added this commit https://github.com/AntonioND/nitro-engine/commit/166cf2998628379f75c46e793e7bd4804324e87c which should help.

In order to keep the screens in the right place, you need NE_MainScreenSetOnBottom(); in your example.

Can you try with this attached file? Replace your main.c by it (and rename it to main.c, GitHub doesn't let me upload files with .c extension). main.txt

SospectGuy58 commented 11 months ago

Yup, issue's fixed image image

AntonioND commented 11 months ago

Great! One last thing. If you don't use the screen effects functions, you should eventually switch to NE_InitDual3D_FB() instead of NE_InitDual3D_DMA(). The DMA mode is required for the demo text console, but you lose the top row of each screen (I don't know if you've noticed that they are now black!). The special effects don't work with the FB functions, but I'm not sure if you care about that, so just keep it in mind! Also, the DMA version requires a DMA copy of the framebuffer per frame, so it takes up a bit of CPU time.

I'm closing this issue now, thanks for checking that it works!

AntonioND commented 11 months ago

Well, to be fair, FB mode has more latency than DMA mode, new frames are delayed by two frames to be shown. In DMA mode it happens right away.