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() {
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<starlight::threading::Thread> thread) {
threads.push_back(thread);
thread->Start();
}

View File

@ -3,11 +3,16 @@
#include <string>
#include <memory>
#include <list>
#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<std::shared_ptr<threading::Thread>> threads;
util::FrameTimer frameTimer;
public:
const std::string appId;
@ -59,13 +67,14 @@ namespace starlight {
void Run();
void EnqueueThread(std::shared_ptr<threading::Thread> 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; }
};
}

View File

@ -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<C3D_ClearBits>(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<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_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<C3D_ClearBits>(0), 0, 0); // don't clear again until marked to
RenderCore::BindTexture(&tex, color);
}

View File

@ -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;

View File

@ -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<starlight::threading::Thread*>(arg)->_FinishStart();
static_cast<SThread*>(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<void*>(threadCreate(_ThreadEnter, static_cast<void*>(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();
}

View File

@ -1,15 +1,21 @@
#pragma once
#include "starlight/_global.h"
#include <memory>
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<Thread> {
friend class starlight::Application;
protected:
volatile ThreadState state;
volatile ThreadState state = ThreadState::Unqueued;
void* sthread;
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 {
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 {