forked from Mirror/libstarlight
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:
parent
9645920759
commit
144510b4e7
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
19
libstarlight/source/starlight/util/FrameTimer.cpp
Normal file
19
libstarlight/source/starlight/util/FrameTimer.cpp
Normal 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);
|
||||||
|
}
|
20
libstarlight/source/starlight/util/FrameTimer.h
Normal file
20
libstarlight/source/starlight/util/FrameTimer.h
Normal 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();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user