From 144510b4e709009d41595863c70ecdcb47770266 Mon Sep 17 00:00:00 2001 From: zetaPRIME Date: Mon, 1 May 2017 21:35:51 -0400 Subject: [PATCH] more complete threading, update to newest libctru and c3d-next (clearing a new rendertarget doesn't work the first time yet) --- libstarlight/source/starlight/Application.cpp | 12 +++++++ libstarlight/source/starlight/Application.h | 13 ++++++-- .../source/starlight/gfx/RenderCore.cpp | 32 ++++++++++++++++--- .../source/starlight/gfx/RenderCore.h | 2 ++ .../source/starlight/threading/Thread.cpp | 12 ++++++- .../source/starlight/threading/Thread.h | 12 +++++-- .../source/starlight/util/FrameTimer.cpp | 19 +++++++++++ .../source/starlight/util/FrameTimer.h | 20 ++++++++++++ libstarlight/todo.txt | 10 +++++- 9 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 libstarlight/source/starlight/util/FrameTimer.cpp create mode 100644 libstarlight/source/starlight/util/FrameTimer.h diff --git a/libstarlight/source/starlight/Application.cpp b/libstarlight/source/starlight/Application.cpp index b595960..40efa7c 100644 --- a/libstarlight/source/starlight/Application.cpp +++ b/libstarlight/source/starlight/Application.cpp @@ -98,6 +98,8 @@ void Application::_end() { } void Application::_mainLoop() { + frameTimer.FrameStart(); + if (!forms.empty()) { if (_sFormState) { _sFormState = false; @@ -154,4 +156,14 @@ void Application::_mainLoop() { topScreen->Draw(); PostDraw(); RenderCore::EndFrame(); + + while (!threads.empty() && frameTimer.GetSubframe() < 0.9) { + threads.front()->Resume(); + threads.splice(threads.end(), threads, threads.begin()); // move to back of queue + } +} + +void Application::EnqueueThread(std::shared_ptr thread) { + threads.push_back(thread); + thread->Start(); } diff --git a/libstarlight/source/starlight/Application.h b/libstarlight/source/starlight/Application.h index 78ebc4d..0c27687 100644 --- a/libstarlight/source/starlight/Application.h +++ b/libstarlight/source/starlight/Application.h @@ -3,11 +3,16 @@ #include #include +#include #include "starlight/datatypes/Vector2.h" #include "starlight/datatypes/VRect.h" #include "starlight/datatypes/Color.h" +#include "starlight/util/FrameTimer.h" + +#include "starlight/threading/Thread.h" + #include "starlight/ui/TouchScreenCanvas.h" #include "starlight/ui/TopScreenCanvas.h" @@ -41,6 +46,9 @@ namespace starlight { void _mainLoop(); void _end(); + std::list> threads; + util::FrameTimer frameTimer; + public: const std::string appId; @@ -59,13 +67,14 @@ namespace starlight { void Run(); + void EnqueueThread(std::shared_ptr thread); + inline void SignalFormState() { _sFormState = true; } + virtual void Init() { } virtual void Update() { } virtual void PostUpdate() { } virtual void Draw() { } virtual void PostDraw() { } virtual void End() { } - - inline void SignalFormState() { _sFormState = true; } }; } diff --git a/libstarlight/source/starlight/gfx/RenderCore.cpp b/libstarlight/source/starlight/gfx/RenderCore.cpp index e386ca6..195f063 100644 --- a/libstarlight/source/starlight/gfx/RenderCore.cpp +++ b/libstarlight/source/starlight/gfx/RenderCore.cpp @@ -248,9 +248,22 @@ CRenderTarget::CRenderTarget(int width, int height, bool forceExact) { auto w = forceExact ? width : NextPow2(width), h = forceExact ? height : NextPow2(height); txSize = Vector2(w, h); + tgt = C3D_RenderTargetCreate(w, h, GPU_RB_RGBA8, -1/*GPU_RB_DEPTH24_STENCIL8*/); // I don't think we need a depth buffer >.> + //tgt = C3D_RenderTargetCreateFromTex(&tex, GPU_TEXFACE_2D, -1, -1); // create target from texture, actually + + C3D_TexInit(&tex, w, h, GPU_RGBA8); + //memset(tex.data, 0, w*h*4); // manually zero out; TODO: optimize this + C3D_TexDelete(&tex); tex.data = tgt->frameBuf.colorBuf; // replace stuff... + Mtx_Ortho(&projection, 0.0f, w, 0.0f, h, 0.0f, 1.0f, true); //Mtx_OrthoTilt(&projection, 0.0f, h, 0.0f, w, 0.0f, 1.0f, true); + + //C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_ALL, 0, 0); + //Clear(Color::transparent); + //RenderCore::BindTexture(&tex, Color::white); + //C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, 0, 0); + //C3D_RenderTargetSetClear(tgt, static_cast(0), 0, 0); } CRenderTarget::~CRenderTarget() { @@ -258,17 +271,26 @@ CRenderTarget::~CRenderTarget() { } void CRenderTarget::Clear(Color color) { - unsigned int c = color; - c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness - C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0); + //unsigned int c = color; + //c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness + //C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0); + //C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0); + clearColor = color; } void CRenderTarget::BindTarget() { + if (true || clearColor) { // clear if color valid + unsigned int c = clearColor; + c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness + //C3D_RenderTargetSetClear(tgt, static_cast(0), c, 0); + //C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0); + C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0); + } C3D_FrameDrawOn(tgt); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection); } void CRenderTarget::Bind(Color color) { - C3D_RenderTargetSetClear(tgt, 0, 0, 0); // don't clear again until marked to - RenderCore::BindTexture(&(tgt->renderBuf.colorBuf), color); + //C3D_RenderTargetSetClear(tgt, static_cast(0), 0, 0); // don't clear again until marked to + RenderCore::BindTexture(&tex, color); } diff --git a/libstarlight/source/starlight/gfx/RenderCore.h b/libstarlight/source/starlight/gfx/RenderCore.h index 57bf8f0..bbd00dd 100644 --- a/libstarlight/source/starlight/gfx/RenderCore.h +++ b/libstarlight/source/starlight/gfx/RenderCore.h @@ -31,6 +31,8 @@ namespace starlight { friend class starlight::gfx::RenderCore; protected: C3D_RenderTarget* tgt; + C3D_Tex tex; + Color clearColor = Color::transparent; public: C3D_Mtx projection; diff --git a/libstarlight/source/starlight/threading/Thread.cpp b/libstarlight/source/starlight/threading/Thread.cpp index e949c89..1791023 100644 --- a/libstarlight/source/starlight/threading/Thread.cpp +++ b/libstarlight/source/starlight/threading/Thread.cpp @@ -2,13 +2,16 @@ #include "3ds.h" +#include "starlight/Application.h" + using starlight::threading::Thread; using SysThread = ::Thread; +using SThread = starlight::threading::Thread; namespace { void _ThreadEnter(void* arg) { // cast to thread and start up - static_cast(arg)->_FinishStart(); + static_cast(arg)->_FinishStart(); } } @@ -17,7 +20,13 @@ Thread::~Thread() { if (event != 0) svcCloseHandle(event); } +void Thread::Enqueue() { + if (state != ThreadState::Unqueued) return; // don't double enqueue, you derp + Application::Current()->EnqueueThread(shared_from_this()); +} + void Thread::Start() { + state = ThreadState::Init; svcCreateEvent(&event, RESET_ONESHOT); sthread = static_cast(threadCreate(_ThreadEnter, static_cast(this), 4*1024, 0x3F, -2, false)); @@ -25,6 +34,7 @@ void Thread::Start() { void Thread::_FinishStart() { // lock out once already done if (state != ThreadState::Init) return; + state = ThreadState::Running; Yield(); Body(); } diff --git a/libstarlight/source/starlight/threading/Thread.h b/libstarlight/source/starlight/threading/Thread.h index 67d464e..c950767 100644 --- a/libstarlight/source/starlight/threading/Thread.h +++ b/libstarlight/source/starlight/threading/Thread.h @@ -1,15 +1,21 @@ #pragma once #include "starlight/_global.h" +#include + namespace starlight { + class Application; + namespace threading { enum class ThreadState : unsigned char { - Unqueued, Init, Idle, Running + Unqueued, Init, Idle, Running, Finished }; - class Thread { + class Thread : public std::enable_shared_from_this { + friend class starlight::Application; protected: - volatile ThreadState state; + + volatile ThreadState state = ThreadState::Unqueued; void* sthread; long unsigned int event = 0; diff --git a/libstarlight/source/starlight/util/FrameTimer.cpp b/libstarlight/source/starlight/util/FrameTimer.cpp new file mode 100644 index 0000000..63dc238 --- /dev/null +++ b/libstarlight/source/starlight/util/FrameTimer.cpp @@ -0,0 +1,19 @@ +#include "FrameTimer.h" + +#include "3ds.h" + +using starlight::util::FrameTimer; + +FrameTimer::FrameTimer() { + osTickCounterStart(reinterpret_cast(&tc)); +} + +void FrameTimer::FrameStart() { + osTickCounterUpdate(reinterpret_cast(&tc)); +} + +double FrameTimer::GetSubframe() { + TickCounter tmp = *(reinterpret_cast(&tc)); + osTickCounterUpdate(&tmp); + return osTickCounterRead(&tmp) * (60.0/1000.0); +} diff --git a/libstarlight/source/starlight/util/FrameTimer.h b/libstarlight/source/starlight/util/FrameTimer.h new file mode 100644 index 0000000..ef20212 --- /dev/null +++ b/libstarlight/source/starlight/util/FrameTimer.h @@ -0,0 +1,20 @@ +#pragma once +#include "starlight/_global.h" + +namespace starlight { + namespace util { + class FrameTimer { + private: + struct TickCount { + unsigned long long int elapsed; + unsigned long long int ref; + }; + TickCount tc; + public: + FrameTimer(); + + void FrameStart(); + double GetSubframe(); + }; + } +} diff --git a/libstarlight/todo.txt b/libstarlight/todo.txt index b0c9acd..b283e71 100644 --- a/libstarlight/todo.txt +++ b/libstarlight/todo.txt @@ -2,6 +2,7 @@ roadmap to v0.5.1 { + figure out how to fix the clear bug - fix the hang on osk when pressing (L|R)+up+left figure out what (else) to put on the left side of the keyboard (opposite backspace and enter) temporary drawable loading, local themeref, discard etc. @@ -11,11 +12,18 @@ roadmap to v0.5.1 { fix `, ' and " glyph spacing/offset adjust /\ some? proper thread dispatch? { - Application main loop keeps a libctru TickCounter and keeps track of frame time; + probably part of Application, actually + + Application main loop keeps a(n abstracted) libctru TickCounter and keeps track of frame time thread objects are held in a std::list, Application dispatches resume events and splice()s them to the end until frame time reaches some proportion of 1/60s + x.splice( x.end(), x, iter ); - thread gets a yield function that calls svcWaitSynchronization on its resume event ...and some mechanism for allowing it to opt out of the rest of the cycle + + Trackable sideclass for threads; float progress 0..1, etc. } +} then by v0.5.5 { + event propagation system of some sort; threadsafe to whatever extent is needed on 3DS } then consider these before 1.0 "gold" { make closing forms a bit less finicky (add them to a separate list and let the Application remove them from the list) garbage collection for not-recently-used theme assets {