use pthread instead of std::thread for emscripten compatibility
This commit is contained in:
@@ -4,16 +4,14 @@
|
|||||||
#include <GL/glext.h>
|
#include <GL/glext.h>
|
||||||
|
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
|
#include <emscripten/bind.h>
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
#include <emscripten/threading.h>
|
#include <emscripten/threading.h>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
#include <emscripten/threading.h>
|
|
||||||
#include <emscripten/val.h>
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE flutter_filament_web_create_gl_context();
|
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE dart_filament_web_create_gl_context();
|
||||||
}
|
}
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
@@ -34,58 +32,76 @@ extern "C"
|
|||||||
|
|
||||||
using namespace flutter_filament;
|
using namespace flutter_filament;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
#include <time.h>
|
||||||
void doSomeStuff(void* ptr) {
|
|
||||||
std::cout << "DOING SOME STUFF ON MAIN THREDA" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RenderLoop
|
class RenderLoop
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit RenderLoop()
|
explicit RenderLoop()
|
||||||
{
|
{
|
||||||
_t = new std::thread([this]()
|
srand(time(NULL));
|
||||||
{
|
|
||||||
auto last = std::chrono::high_resolution_clock::now();
|
|
||||||
while (!_stop) {
|
|
||||||
|
|
||||||
if (_rendering) {
|
pthread_attr_t attr;
|
||||||
// auto frameStart = std::chrono::high_resolution_clock::now();
|
pthread_attr_init(&attr);
|
||||||
doRender();
|
#ifdef __EMSCRIPTEN__
|
||||||
// auto frameEnd = std::chrono::high_resolution_clock::now();
|
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
|
||||||
}
|
#endif
|
||||||
|
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
|
||||||
last = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
float elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last).count());
|
|
||||||
|
|
||||||
std::function<void()> task;
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(_access);
|
|
||||||
|
|
||||||
if(_tasks.empty()) {
|
|
||||||
_cond.wait_for(lock, std::chrono::duration<float, std::milli>(1));
|
|
||||||
}
|
|
||||||
while(!_tasks.empty()) {
|
|
||||||
task = std::move(_tasks.front());
|
|
||||||
_tasks.pop_front();
|
|
||||||
task();
|
|
||||||
}
|
|
||||||
|
|
||||||
now = std::chrono::high_resolution_clock::now();
|
|
||||||
elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last).count());
|
|
||||||
if(elapsed < _frameIntervalInMilliseconds - 4) {
|
|
||||||
auto sleepFor = std::chrono::microseconds(int(_frameIntervalInMilliseconds - elapsed - 4) * 1000);
|
|
||||||
std::this_thread::sleep_for(sleepFor);
|
|
||||||
}
|
|
||||||
} });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~RenderLoop()
|
~RenderLoop()
|
||||||
{
|
{
|
||||||
_stop = true;
|
_stop = true;
|
||||||
_t->join();
|
pthread_join(t, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mainLoop(void* arg) {
|
||||||
|
((RenderLoop*)arg)->iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *startHelper(void * parm) {
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_set_main_loop_arg(&RenderLoop::mainLoop, parm, 0, true);
|
||||||
|
#else
|
||||||
|
((RenderLoop*)parm)->start();
|
||||||
|
#endif
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
while (!_stop) {
|
||||||
|
iter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iter() {
|
||||||
|
|
||||||
|
auto frameStart = std::chrono::high_resolution_clock::now();
|
||||||
|
if (_rendering) {
|
||||||
|
doRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now - frameStart).count();
|
||||||
|
|
||||||
|
std::function<void()> task;
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_access);
|
||||||
|
while(true) {
|
||||||
|
now = std::chrono::high_resolution_clock::now();
|
||||||
|
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now - frameStart).count();
|
||||||
|
if(elapsed >= _frameIntervalInMicroseconds) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!_tasks.empty()) {
|
||||||
|
task = std::move(_tasks.front());
|
||||||
|
_tasks.pop_front();
|
||||||
|
task();
|
||||||
|
} else {
|
||||||
|
_cond.wait_for(lock, std::chrono::duration<float, std::milli>(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void createViewer(void *const context, void *const platform,
|
void createViewer(void *const context, void *const platform,
|
||||||
@@ -99,37 +115,39 @@ public:
|
|||||||
_renderCallbackOwner = owner;
|
_renderCallbackOwner = owner;
|
||||||
std::packaged_task<FilamentViewer *()> lambda([=]() mutable
|
std::packaged_task<FilamentViewer *()> lambda([=]() mutable
|
||||||
{
|
{
|
||||||
|
FilamentViewer* viewer = nullptr;
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
auto emContext = flutter_filament_web_create_gl_context();
|
_context = dart_filament_web_create_gl_context();
|
||||||
|
|
||||||
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)emContext);
|
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
|
||||||
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||||
std::cout << "Failed to make context current." << std::endl;
|
std::cout << "Failed to make context current." << std::endl;
|
||||||
return (FilamentViewer*)nullptr;
|
return viewer;
|
||||||
}
|
}
|
||||||
// glClearColor(0.0, 1.0, 0.0, 1.0);
|
glClearColor(0.0, 0.5, 0.5, 1.0);
|
||||||
// glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
// emscripten_webgl_commit_frame();
|
// emscripten_webgl_commit_frame();
|
||||||
|
|
||||||
_viewer = new FilamentViewer((void* const) emContext, loader, platform, uberArchivePath);
|
viewer = (FilamentViewer*) create_filament_viewer((void* const) _context, loader, platform, uberArchivePath);
|
||||||
MAIN_THREAD_EM_ASM({
|
MAIN_THREAD_EM_ASM({
|
||||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
moduleArg.dartFilamentResolveCallback($0, $1);
|
||||||
}, callback, _viewer);
|
}, callback, viewer);
|
||||||
#else
|
#else
|
||||||
_viewer = new FilamentViewer(context, loader, platform, uberArchivePath);
|
viewer = (FilamentViewer*)create_filament_viewer(context, loader, platform, uberArchivePath);
|
||||||
callback(_viewer);
|
callback(viewer);
|
||||||
#endif
|
#endif
|
||||||
return _viewer; });
|
_viewer = viewer;
|
||||||
|
return viewer; });
|
||||||
auto fut = add_task(lambda);
|
auto fut = add_task(lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyViewer()
|
void destroyViewer(FilamentViewer* viewer)
|
||||||
{
|
{
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
{
|
{
|
||||||
_rendering = false;
|
_rendering = false;
|
||||||
destroy_filament_viewer(_viewer);
|
destroy_filament_viewer(viewer);
|
||||||
_viewer = nullptr; });
|
});
|
||||||
auto fut = add_task(lambda);
|
auto fut = add_task(lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,23 +170,27 @@ public:
|
|||||||
|
|
||||||
void doRender()
|
void doRender()
|
||||||
{
|
{
|
||||||
// auto now = std::chrono::high_resolution_clock::now();
|
#ifdef __EMSCRIPTEN__
|
||||||
// auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
|
if(emscripten_is_webgl_context_lost(_context) == EM_TRUE) {
|
||||||
|
Log("Context lost");
|
||||||
|
auto sleepFor = std::chrono::seconds(1);
|
||||||
|
std::this_thread::sleep_for(sleepFor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
render(_viewer, 0, nullptr, nullptr, nullptr);
|
render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||||
_lastRenderTime = std::chrono::high_resolution_clock::now();
|
|
||||||
if (_renderCallback)
|
if (_renderCallback)
|
||||||
{
|
{
|
||||||
_renderCallback(_renderCallbackOwner);
|
_renderCallback(_renderCallbackOwner);
|
||||||
}
|
}
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
emscripten_webgl_commit_frame();
|
// emscripten_webgl_commit_frame();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
||||||
{
|
{
|
||||||
_frameIntervalInMilliseconds = frameIntervalInMilliseconds;
|
_frameIntervalInMicroseconds = static_cast<int>(1000.0f * frameIntervalInMilliseconds);
|
||||||
Log("Set _frameIntervalInMilliseconds to %f", _frameIntervalInMilliseconds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Rt>
|
template <class Rt>
|
||||||
@@ -183,18 +205,20 @@ public:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
bool _stop = false;
|
bool _stop = false;
|
||||||
bool _rendering = false;
|
bool _rendering = false;
|
||||||
float _frameIntervalInMilliseconds = 1000.0 / 60.0;
|
int _frameIntervalInMicroseconds = 1000000.0 / 60.0;
|
||||||
std::mutex _access;
|
std::mutex _access;
|
||||||
FilamentViewer *_viewer = nullptr;
|
|
||||||
void (*_renderCallback)(void *const) = nullptr;
|
void (*_renderCallback)(void *const) = nullptr;
|
||||||
void *_renderCallbackOwner = nullptr;
|
void *_renderCallbackOwner = nullptr;
|
||||||
std::thread *_t = nullptr;
|
pthread_t t;
|
||||||
std::condition_variable _cond;
|
std::condition_variable _cond;
|
||||||
std::deque<std::function<void()>> _tasks;
|
std::deque<std::function<void()>> _tasks;
|
||||||
std::chrono::steady_clock::time_point _lastRenderTime = std::chrono::high_resolution_clock::now();
|
FilamentViewer* _viewer = nullptr;
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
|
||||||
|
int _frameNum = 0;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@@ -220,7 +244,7 @@ extern "C"
|
|||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer)
|
||||||
{
|
{
|
||||||
_rl->destroyViewer();
|
_rl->destroyViewer((FilamentViewer*)viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer,
|
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer,
|
||||||
@@ -848,4 +872,5 @@ extern "C"
|
|||||||
});
|
});
|
||||||
auto fut = _rl->add_task(lambda);
|
auto fut = _rl->add_task(lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user