more complete threading, update to newest libctru and c3d-next (clearing a new rendertarget doesn't work the first time yet)

This commit is contained in:
zetaPRIME 2017-05-01 21:35:51 -04:00
parent 9645920759
commit 144510b4e7
9 changed files with 120 additions and 12 deletions

View File

@ -98,6 +98,8 @@ void Application::_end() {
} }
void Application::_mainLoop() { void Application::_mainLoop() {
frameTimer.FrameStart();
if (!forms.empty()) { if (!forms.empty()) {
if (_sFormState) { if (_sFormState) {
_sFormState = false; _sFormState = false;
@ -154,4 +156,14 @@ void Application::_mainLoop() {
topScreen->Draw(); topScreen->Draw();
PostDraw(); PostDraw();
RenderCore::EndFrame(); 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<starlight::threading::Thread> thread) {
threads.push_back(thread);
thread->Start();
} }

View File

@ -3,11 +3,16 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <list>
#include "starlight/datatypes/Vector2.h" #include "starlight/datatypes/Vector2.h"
#include "starlight/datatypes/VRect.h" #include "starlight/datatypes/VRect.h"
#include "starlight/datatypes/Color.h" #include "starlight/datatypes/Color.h"
#include "starlight/util/FrameTimer.h"
#include "starlight/threading/Thread.h"
#include "starlight/ui/TouchScreenCanvas.h" #include "starlight/ui/TouchScreenCanvas.h"
#include "starlight/ui/TopScreenCanvas.h" #include "starlight/ui/TopScreenCanvas.h"
@ -41,6 +46,9 @@ namespace starlight {
void _mainLoop(); void _mainLoop();
void _end(); void _end();
std::list<std::shared_ptr<threading::Thread>> threads;
util::FrameTimer frameTimer;
public: public:
const std::string appId; const std::string appId;
@ -59,13 +67,14 @@ namespace starlight {
void Run(); void Run();
void EnqueueThread(std::shared_ptr<threading::Thread> thread);
inline void SignalFormState() { _sFormState = true; }
virtual void Init() { } virtual void Init() { }
virtual void Update() { } virtual void Update() { }
virtual void PostUpdate() { } virtual void PostUpdate() { }
virtual void Draw() { } virtual void Draw() { }
virtual void PostDraw() { } virtual void PostDraw() { }
virtual void End() { } virtual void End() { }
inline void SignalFormState() { _sFormState = true; }
}; };
} }

View File

@ -248,9 +248,22 @@ CRenderTarget::CRenderTarget(int width, int height, bool forceExact) {
auto w = forceExact ? width : NextPow2(width), auto w = forceExact ? width : NextPow2(width),
h = forceExact ? height : NextPow2(height); h = forceExact ? height : NextPow2(height);
txSize = Vector2(w, h); 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_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_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); //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<C3D_ClearBits>(0), 0, 0);
} }
CRenderTarget::~CRenderTarget() { CRenderTarget::~CRenderTarget() {
@ -258,17 +271,26 @@ CRenderTarget::~CRenderTarget() {
} }
void CRenderTarget::Clear(Color color) { void CRenderTarget::Clear(Color color) {
unsigned int c = color; //unsigned int c = color;
c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness //c = ((c>>24)&0x000000FF) | ((c>>8)&0x0000FF00) | ((c<<8)&0x00FF0000) | ((c<<24)&0xFF000000); // reverse endianness
C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0); //C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0);
//C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0);
clearColor = color;
} }
void CRenderTarget::BindTarget() { 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<C3D_ClearBits>(0), c, 0);
//C3D_RenderTargetSetClear(tgt, C3D_CLEAR_ALL, c, 0);
C3D_FrameBufClear(&(tgt->frameBuf), C3D_CLEAR_COLOR, c, 0);
}
C3D_FrameDrawOn(tgt); C3D_FrameDrawOn(tgt);
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, sLocProjection, &projection);
} }
void CRenderTarget::Bind(Color color) { void CRenderTarget::Bind(Color color) {
C3D_RenderTargetSetClear(tgt, 0, 0, 0); // don't clear again until marked to //C3D_RenderTargetSetClear(tgt, static_cast<C3D_ClearBits>(0), 0, 0); // don't clear again until marked to
RenderCore::BindTexture(&(tgt->renderBuf.colorBuf), color); RenderCore::BindTexture(&tex, color);
} }

View File

@ -31,6 +31,8 @@ namespace starlight {
friend class starlight::gfx::RenderCore; friend class starlight::gfx::RenderCore;
protected: protected:
C3D_RenderTarget* tgt; C3D_RenderTarget* tgt;
C3D_Tex tex;
Color clearColor = Color::transparent;
public: public:
C3D_Mtx projection; C3D_Mtx projection;

View File

@ -2,13 +2,16 @@
#include "3ds.h" #include "3ds.h"
#include "starlight/Application.h"
using starlight::threading::Thread; using starlight::threading::Thread;
using SysThread = ::Thread; using SysThread = ::Thread;
using SThread = starlight::threading::Thread;
namespace { namespace {
void _ThreadEnter(void* arg) { void _ThreadEnter(void* arg) {
// cast to thread and start up // cast to thread and start up
static_cast<starlight::threading::Thread*>(arg)->_FinishStart(); static_cast<SThread*>(arg)->_FinishStart();
} }
} }
@ -17,7 +20,13 @@ Thread::~Thread() {
if (event != 0) svcCloseHandle(event); 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() { void Thread::Start() {
state = ThreadState::Init;
svcCreateEvent(&event, RESET_ONESHOT); svcCreateEvent(&event, RESET_ONESHOT);
sthread = static_cast<void*>(threadCreate(_ThreadEnter, static_cast<void*>(this), 4*1024, 0x3F, -2, false)); sthread = static_cast<void*>(threadCreate(_ThreadEnter, static_cast<void*>(this), 4*1024, 0x3F, -2, false));
@ -25,6 +34,7 @@ void Thread::Start() {
void Thread::_FinishStart() { void Thread::_FinishStart() {
// lock out once already done // lock out once already done
if (state != ThreadState::Init) return; if (state != ThreadState::Init) return;
state = ThreadState::Running;
Yield(); Yield();
Body(); Body();
} }

View File

@ -1,15 +1,21 @@
#pragma once #pragma once
#include "starlight/_global.h" #include "starlight/_global.h"
#include <memory>
namespace starlight { namespace starlight {
class Application;
namespace threading { namespace threading {
enum class ThreadState : unsigned char { enum class ThreadState : unsigned char {
Unqueued, Init, Idle, Running Unqueued, Init, Idle, Running, Finished
}; };
class Thread { class Thread : public std::enable_shared_from_this<Thread> {
friend class starlight::Application;
protected: protected:
volatile ThreadState state;
volatile ThreadState state = ThreadState::Unqueued;
void* sthread; void* sthread;
long unsigned int event = 0; long unsigned int event = 0;

View File

@ -0,0 +1,19 @@
#include "FrameTimer.h"
#include "3ds.h"
using starlight::util::FrameTimer;
FrameTimer::FrameTimer() {
osTickCounterStart(reinterpret_cast<TickCounter*>(&tc));
}
void FrameTimer::FrameStart() {
osTickCounterUpdate(reinterpret_cast<TickCounter*>(&tc));
}
double FrameTimer::GetSubframe() {
TickCounter tmp = *(reinterpret_cast<TickCounter*>(&tc));
osTickCounterUpdate(&tmp);
return osTickCounterRead(&tmp) * (60.0/1000.0);
}

View File

@ -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();
};
}
}

View File

@ -2,6 +2,7 @@
roadmap to v0.5.1 { roadmap to v0.5.1 {
figure out how to fix the clear bug
- fix the hang on osk when pressing (L|R)+up+left - 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) figure out what (else) to put on the left side of the keyboard (opposite backspace and enter)
temporary drawable loading, local themeref, discard etc. temporary drawable loading, local themeref, discard etc.
@ -11,11 +12,18 @@ roadmap to v0.5.1 {
fix `, ' and " glyph spacing/offset fix `, ' and " glyph spacing/offset
adjust /\ some? adjust /\ some?
proper thread dispatch? { 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 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 - 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 ...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" { } 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) 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 { garbage collection for not-recently-used theme assets {