-
-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Softlock when nothing is drawn #35
Comments
If you don't draw anything to a target, why do you bind it? |
Well I'm unsure how to check if the end user will be drawing anything immediately. They could be writing their draw function into the script to set up for later. Add other events like keypressing and it doesn't work because of the softlock. If there's a way to fix this issue that I'm unaware of (if it's on my end), please let me know. |
Why don't you let the end users bind the targets themselves? |
The reason is because it's meant to be a game framework (i.e. Love Potion), but I'm rewriting it to use Citro rather than sf2dlib. The end users shouldn't need to know how to bind a rendertarget on the Lua side, that's just ugly and makes no sense. /shrug |
It does make sense. Allowing the end user to control rendertargets allows for fun stuff to happen, such as caching a piece of drawing to a texture and using that multiple times when drawing to a screen. IIRC even sf2d did the same thing. |
Right, I know. The issue, however, is that this is basically Love2D for 3DS. I'm following how it's done through the official code and tweaking where needed (such as font loading and filesystem access). The code looks like this on the Lua script: function love.load()
print("Press 'start' to quit")
--print("Loading font!")
timer = 1
end
function love.update(dt)
timer = timer - dt
if timer < 0 then
print("FPS: " .. love.timer.getFPS())
timer = 1
end
end
function love.draw()
love.graphics.print("Adrian.. FACE REVEAL WEN?!?!?!", 120, 120)
end
function love.keypressed(key)
if key == "start" then
love.quit()
end
end The way it works is all I care about is knowing I can draw whenever. It doesn't need to be immediate. If I throw the program on the 3DS or Citra it should run without needing to draw something or having people familiar (or new) with this framework require knowledge about behind-the-scenes stuff. |
You could try lazily starting the frame. Invoke |
Where would I FrameSync()? I thought Citro does that already. I'm also not sure if I can really 'detect' if the user tries to invoke a drawing command. I'll take a poke at it I guess. This is my rendering code in C++ void Graphics::Render(gfxScreen_t screen)
{
resetPool();
renderScreen = screen;
C3D_FrameBegin(C3D_FRAME_SYNCDRAW); //SYNC_DRAW
switch(screen)
{
case GFX_TOP:
this->StartTarget(topTarget);
break;
case GFX_BOTTOM:
this->StartTarget(bottomTarget);
break;
}
}
void Graphics::StartTarget(CRenderTarget * target)
{
if (target->GetTarget() == nullptr)
return;
target->Clear(graphicsGetBackgroundColor());
C3D_FrameDrawOn(target->GetTarget());
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, projection_desc, target->GetProjection());
}
void Graphics::SwapBuffers()
{
C3D_FrameEnd(0);
} All of these methods do get called appropriately. |
citro3d does that automatically, but only if you actually use C3D_FrameBegin/C3D_FrameEnd. Otherwise you're going to have to sync manually. Where do you invoke |
I invoke it during the aptMainLoop: while (aptMainLoop())
{
if (LOVE_QUIT)
break;
if (!LUA_ERROR)
{
....
if(luaL_dostring(L, "if love.update then love.update(love.timer.getDelta()) end"))
console->ThrowError(L);
....
love::Graphics::Instance()->Render(GFX_TOP);
if (luaL_dostring(L, "if love.draw then love.draw() end"))
console->ThrowError(L);
/*love::Graphics::Instance()->Render(GFX_BOTTOM);
if (luaL_dostring(L, "if love.draw then love.draw() end"))
console->ThrowError(L);
*/
love::Graphics::Instance()->SwapBuffers();
love::Timer::Instance()->Tick();
}
} Sorry for the spacing :P |
Ok so you basically need to lazily call |
I think I have the right way to do it, but my issue is most likely detecting if the frame really started. The render for GFX_TOP happens before love.draw executes. This allows for Citro to render images, primitive shapes, etc. Then it ends the frame. I don't have a way to definitely check if the user put in some rendering code. |
No. I meant deferring the Render() call until love.draw actually calls drawing commands. You ought to have those drawing commands implemented in C, right? That's where you need to detect if Render() needs to be called. (Btw, if it's not clear enough: Using the renderqueue frame commands without actually rendering anything is considered API misuse.) |
Yeah the draw commands are in C. If I have to flag a Boolean in each one it's kind of hacky, tbh. I'll keep trying I guess. I was hoping there'd be a better fix. |
I just had this same problem with my homebrew game, and I think I have something that works. Before noticing this issue was here, I was looking through the commit log to see if I could find the cause. Along the way, I stumbled upon this commit.
So, just to keep my code clean, I removed all uses of C3D_RenderTargetSetClear, and instead did it directly as part of my render function:
To my surprise, the crashes stopped happening. |
Might as well add that calling |
So just basically clear the FrameBuffer rather than SetClear? |
I'm being bitten by this right now too, FYI. Not all code is as simple and straightforward as you assume and telling someone "well just refactor it to make it more straightforward" is not exactly a solution. |
I agree with @endrift since there shouldn't be a reason it softlocks using this function if nothing is there. Regardless, just using FrameBufClear works and doesn't cause a soft lock before drawing, but the color format to clear is different than expected. |
Just experienced this issue for myself. Render a frame, draw nothing, GPU crash (no crash handler, just hang). The context was me trying to clear the framebuffer to prevent issues with APT_DoApplicationJump (In which it gets weird and renders your last frame but... without the last thing you drew while jumping). Simply drawing a black rectangle does what I need (clearing the framebuffer would work too), but just keep in mind that more people are going to run in to this. |
i stuck on this thing few hours don't know why my hb suddenly stuck. |
Specifically, if I have Citro render the top screen render target, but I don't draw anything, it will go through two cycles before soft locking. Removing this rendertarget stuff in aptMainLoop fixes this (which broke my FPS timer :P)
Emulation on Citra
Apparently the solution is to fool the render targets by applying a completely transparent texture at all times--something I'd rather not do. I've tested both builds on my 3DS and they behave as shown on Citra.
The text was updated successfully, but these errors were encountered: