restore multithreading on iOS and use DisplayLink to decouple rendering from the main loop
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
>
|
>
|
||||||
{
|
{
|
||||||
@public GameView* glview;
|
@public GameView* glview;
|
||||||
|
@public CADisplayLink *displayLink;
|
||||||
}
|
}
|
||||||
- (void)display_file:(std::string)filename;
|
- (void)display_file:(std::string)filename;
|
||||||
- (void)reset_touch;
|
- (void)reset_touch;
|
||||||
@@ -32,4 +33,6 @@
|
|||||||
- (void)unregisterForKeyboardNotifications;
|
- (void)unregisterForKeyboardNotifications;
|
||||||
- (void)crash;
|
- (void)crash;
|
||||||
- (void)share_file:(NSString*)file_path;
|
- (void)share_file:(NSString*)file_path;
|
||||||
|
- (void)tick;
|
||||||
|
- (void)render_loop;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
std::deque<std::packaged_task<void()>> tasklist;
|
std::deque<std::packaged_task<void()>> tasklist;
|
||||||
std::mutex task_mutex;
|
std::mutex task_mutex;
|
||||||
|
std::mutex render_mutex;
|
||||||
|
std::condition_variable render_cv;
|
||||||
|
|
||||||
@interface GameImagePicker : UIImagePickerController
|
@interface GameImagePicker : UIImagePickerController
|
||||||
{
|
{
|
||||||
@@ -432,6 +434,64 @@ std::set<UITouch*> ignored_touch;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)tick
|
||||||
|
{
|
||||||
|
//std::lock_guard<std::mutex> lock(render_mutex);
|
||||||
|
render_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)render_loop
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
static auto time = std::chrono::steady_clock::now();
|
||||||
|
static double elapsed = 0;
|
||||||
|
static double min_fps_timer = 0;
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
auto dt = std::chrono::duration<float>(now - time);
|
||||||
|
time = now;
|
||||||
|
elapsed += dt.count();
|
||||||
|
min_fps_timer += dt.count();
|
||||||
|
|
||||||
|
if (min_fps_timer > 0.5)
|
||||||
|
{
|
||||||
|
App::I.redraw = true;
|
||||||
|
min_fps_timer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<std::packaged_task<void()>> working_list;
|
||||||
|
if (!tasklist.empty())
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(task_mutex);
|
||||||
|
working_list = std::move(tasklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
App::I.tick(dt.count());
|
||||||
|
|
||||||
|
if (!(App::I.redraw || App::I.animate || !working_list.empty()))
|
||||||
|
{
|
||||||
|
//[self.context presentRenderbuffer:GL_FRAMEBUFFER];
|
||||||
|
//[self async_unlock];
|
||||||
|
std::unique_lock<std::mutex> lock(render_mutex);
|
||||||
|
render_cv.wait(lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self async_lock];
|
||||||
|
while (!working_list.empty())
|
||||||
|
{
|
||||||
|
working_list.front()();
|
||||||
|
working_list.pop_front();
|
||||||
|
}
|
||||||
|
App::I.clear();
|
||||||
|
App::I.update(elapsed);
|
||||||
|
[self.context presentRenderbuffer:GL_FRAMEBUFFER];
|
||||||
|
[self async_unlock];
|
||||||
|
[self->glview display];
|
||||||
|
elapsed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setupGL
|
- (void)setupGL
|
||||||
{
|
{
|
||||||
[self async_lock];
|
[self async_lock];
|
||||||
@@ -439,54 +499,12 @@ std::set<UITouch*> ignored_touch;
|
|||||||
[self async_unlock];
|
[self async_unlock];
|
||||||
|
|
||||||
std::thread([self]{
|
std::thread([self]{
|
||||||
while (true)
|
[self render_loop];
|
||||||
{
|
|
||||||
static auto time = std::chrono::steady_clock::now();
|
|
||||||
static double elapsed = 0;
|
|
||||||
static double min_fps_timer = 0;
|
|
||||||
auto now = std::chrono::steady_clock::now();
|
|
||||||
auto dt = std::chrono::duration<float>(now - time);
|
|
||||||
time = now;
|
|
||||||
elapsed += dt.count();
|
|
||||||
min_fps_timer += dt.count();
|
|
||||||
|
|
||||||
if (min_fps_timer > 0.1)
|
|
||||||
{
|
|
||||||
App::I.redraw = true;
|
|
||||||
min_fps_timer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::deque<std::packaged_task<void()>> working_list;
|
|
||||||
if (!tasklist.empty())
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(task_mutex);
|
|
||||||
working_list = std::move(tasklist);
|
|
||||||
}
|
|
||||||
|
|
||||||
App::I.tick(dt.count());
|
|
||||||
|
|
||||||
[self async_lock];
|
|
||||||
if (!(App::I.redraw || App::I.animate || !working_list.empty()))
|
|
||||||
{
|
|
||||||
//[self.context presentRenderbuffer:GL_FRAMEBUFFER];
|
|
||||||
[self async_unlock];
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!working_list.empty())
|
|
||||||
{
|
|
||||||
working_list.front()();
|
|
||||||
working_list.pop_front();
|
|
||||||
}
|
|
||||||
App::I.clear();
|
|
||||||
App::I.update(elapsed);
|
|
||||||
[self.context presentRenderbuffer:GL_FRAMEBUFFER];
|
|
||||||
[self async_unlock];
|
|
||||||
[self->glview display];
|
|
||||||
elapsed = 0;
|
|
||||||
}
|
|
||||||
}).detach();
|
}).detach();
|
||||||
|
|
||||||
|
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick)];
|
||||||
|
displayLink.frameInterval = 4;
|
||||||
|
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tearDownGL
|
- (void)tearDownGL
|
||||||
|
|||||||
@@ -1176,10 +1176,6 @@ void Canvas::clear_context()
|
|||||||
|
|
||||||
void Canvas::import_equirectangular(std::string file_path)
|
void Canvas::import_equirectangular(std::string file_path)
|
||||||
{
|
{
|
||||||
#if __IOS__
|
|
||||||
import_equirectangular_thread(file_path);
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
std::thread t(&Canvas::import_equirectangular_thread, this, file_path);
|
std::thread t(&Canvas::import_equirectangular_thread, this, file_path);
|
||||||
t.detach();
|
t.detach();
|
||||||
}
|
}
|
||||||
@@ -1253,12 +1249,6 @@ void Canvas::export_equirectangular(std::string file_path, std::function<void()>
|
|||||||
{
|
{
|
||||||
if (App::I.check_license())
|
if (App::I.check_license())
|
||||||
{
|
{
|
||||||
#if __IOS__
|
|
||||||
export_equirectangular_thread(file_path);
|
|
||||||
if (on_complete)
|
|
||||||
on_complete();
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
std::thread t([=] {
|
std::thread t([=] {
|
||||||
export_equirectangular_thread(file_path);
|
export_equirectangular_thread(file_path);
|
||||||
if (on_complete)
|
if (on_complete)
|
||||||
@@ -1563,12 +1553,6 @@ void Canvas::export_layers(std::string file_name, std::function<void()> on_compl
|
|||||||
{
|
{
|
||||||
if (App::I.check_license())
|
if (App::I.check_license())
|
||||||
{
|
{
|
||||||
#if __IOS__
|
|
||||||
export_layers_thread(file_name);
|
|
||||||
if (on_complete)
|
|
||||||
on_complete();
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
std::thread t([=] {
|
std::thread t([=] {
|
||||||
export_layers_thread(file_name);
|
export_layers_thread(file_name);
|
||||||
if (on_complete)
|
if (on_complete)
|
||||||
@@ -1824,12 +1808,6 @@ void Canvas::project_save(std::function<void(bool)> on_complete)
|
|||||||
{
|
{
|
||||||
if (App::I.check_license())
|
if (App::I.check_license())
|
||||||
{
|
{
|
||||||
#if __IOS__
|
|
||||||
bool ret = project_save_thread(App::I.doc_path);
|
|
||||||
if (on_complete)
|
|
||||||
on_complete(ret);
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
std::thread t([=] {
|
std::thread t([=] {
|
||||||
bool ret = project_save_thread(App::I.doc_path);
|
bool ret = project_save_thread(App::I.doc_path);
|
||||||
if (on_complete)
|
if (on_complete)
|
||||||
@@ -1844,12 +1822,6 @@ void Canvas::project_save(std::string file_path, std::function<void(bool)> on_co
|
|||||||
LOG("saving %s", file_path.c_str());
|
LOG("saving %s", file_path.c_str());
|
||||||
if (App::I.check_license())
|
if (App::I.check_license())
|
||||||
{
|
{
|
||||||
#if __IOS__
|
|
||||||
bool ret = project_save_thread(file_path);
|
|
||||||
if (on_complete)
|
|
||||||
on_complete(ret);
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
std::thread t([=] {
|
std::thread t([=] {
|
||||||
bool ret = project_save_thread(file_path);
|
bool ret = project_save_thread(file_path);
|
||||||
if (on_complete)
|
if (on_complete)
|
||||||
@@ -2046,12 +2018,6 @@ bool Canvas::project_save_thread(std::string file_path)
|
|||||||
|
|
||||||
void Canvas::project_open(std::string file_path, std::function<void(bool)> on_complete)
|
void Canvas::project_open(std::string file_path, std::function<void(bool)> on_complete)
|
||||||
{
|
{
|
||||||
#if __IOS__
|
|
||||||
bool ret = project_open_thread(file_path);
|
|
||||||
if (on_complete)
|
|
||||||
on_complete(ret);
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
std::thread t([=] {
|
std::thread t([=] {
|
||||||
bool result = project_open_thread(file_path);
|
bool result = project_open_thread(file_path);
|
||||||
if (on_complete)
|
if (on_complete)
|
||||||
|
|||||||
@@ -492,6 +492,7 @@ void NodeStrokePreview::draw_stroke()
|
|||||||
gl.save();
|
gl.save();
|
||||||
node->draw_stroke_immediate();
|
node->draw_stroke_immediate();
|
||||||
gl.restore();
|
gl.restore();
|
||||||
|
node->app_redraw();
|
||||||
node->async_end();
|
node->async_end();
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
std::this_thread::sleep_for(std::chrono::milliseconds(30));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user