feat!: big refactor to support multiple swapchains
This commit is contained in:
@@ -739,7 +739,12 @@ namespace thermion_filament
|
||||
FilamentViewer::~FilamentViewer()
|
||||
{
|
||||
clearLights();
|
||||
destroySwapChain();
|
||||
for(auto swapChain : _swapChains) {
|
||||
_engine->destroy(swapChain);
|
||||
}
|
||||
|
||||
_swapChains.clear();
|
||||
|
||||
if (!_imageEntity.isNull())
|
||||
{
|
||||
_engine->destroy(_imageEntity);
|
||||
@@ -760,25 +765,29 @@ namespace thermion_filament
|
||||
|
||||
Renderer *FilamentViewer::getRenderer() { return _renderer; }
|
||||
|
||||
void FilamentViewer::createSwapChain(const void *window, uint32_t width, uint32_t height)
|
||||
SwapChain* FilamentViewer::createSwapChain(const void *window, uint32_t width, uint32_t height)
|
||||
{
|
||||
std::lock_guard lock(_renderMutex);
|
||||
SwapChain* swapChain;
|
||||
#if TARGET_OS_IPHONE
|
||||
_swapChain = _engine->createSwapChain((void *)window, filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT | filament::backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
|
||||
swapChain = _engine->createSwapChain((void *)window, filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT | filament::backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
|
||||
#else
|
||||
if (window)
|
||||
{
|
||||
_swapChain = _engine->createSwapChain((void *)window, filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT | filament::backend::SWAP_CHAIN_CONFIG_READABLE);
|
||||
swapChain = _engine->createSwapChain((void *)window, filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT | filament::backend::SWAP_CHAIN_CONFIG_READABLE);
|
||||
Log("Created window swapchain.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Created headless swapchain.");
|
||||
_swapChain = _engine->createSwapChain(width, height, filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT | filament::backend::SWAP_CHAIN_CONFIG_READABLE | filament::SwapChain::CONFIG_HAS_STENCIL_BUFFER);
|
||||
swapChain = _engine->createSwapChain(width, height, filament::backend::SWAP_CHAIN_CONFIG_TRANSPARENT | filament::backend::SWAP_CHAIN_CONFIG_READABLE | filament::SwapChain::CONFIG_HAS_STENCIL_BUFFER);
|
||||
}
|
||||
#endif
|
||||
_swapChains.push_back(swapChain);
|
||||
return swapChain;
|
||||
}
|
||||
|
||||
void FilamentViewer::createRenderTarget(intptr_t texture, uint32_t width, uint32_t height)
|
||||
RenderTarget* FilamentViewer::createRenderTarget(intptr_t texture, uint32_t width, uint32_t height)
|
||||
{
|
||||
// Create filament textures and render targets (note the color buffer has the import call)
|
||||
auto rtColor = filament::Texture::Builder()
|
||||
@@ -796,40 +805,44 @@ namespace thermion_filament
|
||||
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
|
||||
.format(filament::Texture::InternalFormat::DEPTH32F)
|
||||
.build(*_engine);
|
||||
_rt = filament::RenderTarget::Builder()
|
||||
auto rt = filament::RenderTarget::Builder()
|
||||
.texture(RenderTarget::AttachmentPoint::COLOR, rtColor)
|
||||
.texture(RenderTarget::AttachmentPoint::DEPTH, rtDepth)
|
||||
.build(*_engine);
|
||||
|
||||
_view->setRenderTarget(_rt);
|
||||
|
||||
Log("Created render target for texture id %ld (%u x %u)", (long)texture, width, height);
|
||||
return rt;
|
||||
}
|
||||
|
||||
void FilamentViewer::destroySwapChain()
|
||||
void FilamentViewer::destroyRenderTarget(RenderTarget* renderTarget) {
|
||||
std::lock_guard lock(_renderMutex);
|
||||
auto rtDepth = renderTarget->getTexture(RenderTarget::AttachmentPoint::DEPTH);
|
||||
if(rtDepth) {
|
||||
_engine->destroy(rtDepth);
|
||||
}
|
||||
auto rtColor = renderTarget->getTexture(RenderTarget::AttachmentPoint::COLOR);
|
||||
if(rtColor) {
|
||||
_engine->destroy(rtColor);
|
||||
}
|
||||
_engine->destroy(renderTarget);
|
||||
auto it = std::find(_renderTargets.begin(), _renderTargets.end(), renderTarget);
|
||||
if(it != _renderTargets.end()) {
|
||||
_renderTargets.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void FilamentViewer::setRenderTarget(RenderTarget *renderTarget) {
|
||||
std::lock_guard lock(_renderMutex);
|
||||
_view->setRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
void FilamentViewer::destroySwapChain(SwapChain *swapChain)
|
||||
{
|
||||
if (_rt)
|
||||
{
|
||||
_view->setRenderTarget(nullptr);
|
||||
auto rtDepth = _rt->getTexture(RenderTarget::AttachmentPoint::DEPTH);
|
||||
if(rtDepth) {
|
||||
_engine->destroy(rtDepth);
|
||||
Log("destroyed depth");
|
||||
}
|
||||
auto rtColor = _rt->getTexture(RenderTarget::AttachmentPoint::COLOR);
|
||||
if(rtColor) {
|
||||
_engine->destroy(rtColor);
|
||||
Log("destroyed color");
|
||||
}
|
||||
_engine->destroy(_rt);
|
||||
_rt = nullptr;
|
||||
}
|
||||
if (_swapChain)
|
||||
{
|
||||
_engine->destroy(_swapChain);
|
||||
_swapChain = nullptr;
|
||||
Log("Swapchain destroyed.");
|
||||
std::lock_guard lock(_renderMutex);
|
||||
auto it = std::find(_swapChains.begin(), _swapChains.end(), swapChain);
|
||||
if(it != _swapChains.end()) {
|
||||
_swapChains.erase(it);
|
||||
}
|
||||
_engine->destroy(swapChain);
|
||||
Log("Swapchain destroyed.");
|
||||
#ifdef __EMSCRIPTEN__
|
||||
_engine->execute();
|
||||
#else
|
||||
@@ -845,10 +858,10 @@ namespace thermion_filament
|
||||
|
||||
void FilamentViewer::removeEntity(EntityId asset)
|
||||
{
|
||||
mtx.lock();
|
||||
_renderMutex.lock();
|
||||
// todo - what if we are using a camera from this asset?
|
||||
_sceneManager->remove(asset);
|
||||
mtx.unlock();
|
||||
_renderMutex.unlock();
|
||||
}
|
||||
|
||||
///
|
||||
@@ -987,7 +1000,6 @@ namespace thermion_filament
|
||||
|
||||
void FilamentViewer::removeSkybox()
|
||||
{
|
||||
Log("Removing skybox");
|
||||
_scene->setSkybox(nullptr);
|
||||
if (_skybox)
|
||||
{
|
||||
@@ -1114,12 +1126,13 @@ namespace thermion_filament
|
||||
|
||||
bool FilamentViewer::render(
|
||||
uint64_t frameTimeInNanos,
|
||||
SwapChain* swapChain,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data)
|
||||
{
|
||||
|
||||
if (!_view || !_swapChain)
|
||||
if (!_view || !swapChain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1152,7 +1165,7 @@ namespace thermion_filament
|
||||
}
|
||||
|
||||
// Render the scene, unless the renderer wants to skip the frame.
|
||||
bool beginFrame = _renderer->beginFrame(_swapChain, frameTimeInNanos);
|
||||
bool beginFrame = _renderer->beginFrame(swapChain, frameTimeInNanos);
|
||||
if (!beginFrame)
|
||||
{
|
||||
_skippedFrames++;
|
||||
@@ -1165,33 +1178,6 @@ namespace thermion_filament
|
||||
|
||||
_frameCount++;
|
||||
|
||||
if (_recording)
|
||||
{
|
||||
Viewport const &vp = _view->getViewport();
|
||||
size_t pixelBufferSize = vp.width * vp.height * 4;
|
||||
auto *pixelBuffer = new uint8_t[pixelBufferSize];
|
||||
auto callback = [](void *buf, size_t size, void *data)
|
||||
{
|
||||
auto frameCallbackData = (FrameCallbackData *)data;
|
||||
auto viewer = (FilamentViewer *)frameCallbackData->viewer;
|
||||
viewer->savePng(buf, size, frameCallbackData->frameNumber);
|
||||
delete frameCallbackData;
|
||||
};
|
||||
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - _recordingStartTime).count());
|
||||
|
||||
auto frameNumber = uint32_t(floor(elapsed / _frameInterval));
|
||||
|
||||
auto userData = new FrameCallbackData{this, frameNumber};
|
||||
|
||||
auto pbd = Texture::PixelBufferDescriptor(
|
||||
pixelBuffer, pixelBufferSize,
|
||||
Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE, nullptr, callback, userData);
|
||||
|
||||
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
|
||||
}
|
||||
_renderer->endFrame();
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
@@ -1206,9 +1192,14 @@ namespace thermion_filament
|
||||
}
|
||||
};
|
||||
|
||||
void FilamentViewer::capture(uint8_t *out, bool useFence, void (*onComplete)())
|
||||
void FilamentViewer::capture(uint8_t *out, bool useFence, SwapChain* swapChain, void (*onComplete)())
|
||||
{
|
||||
|
||||
if(!swapChain) {
|
||||
Log("NO SWAPCHAIN");
|
||||
return;
|
||||
}
|
||||
|
||||
Viewport const &vp = _view->getViewport();
|
||||
size_t pixelBufferSize = vp.width * vp.height * 4;
|
||||
auto *pixelBuffer = new uint8_t[pixelBufferSize];
|
||||
@@ -1240,18 +1231,9 @@ namespace thermion_filament
|
||||
pixelBuffer, pixelBufferSize,
|
||||
Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE, dispatcher, callback, userData);
|
||||
_renderer->beginFrame(_swapChain, 0);
|
||||
|
||||
_renderer->render(_view);
|
||||
|
||||
if (_rt)
|
||||
{
|
||||
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderer->readPixels(0, 0, vp.width, vp.height, std::move(pbd));
|
||||
}
|
||||
_renderer->beginFrame(swapChain, 0);
|
||||
_renderer->render(_view);
|
||||
_renderer->readPixels(0, 0, vp.width, vp.height, std::move(pbd));
|
||||
_renderer->endFrame();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
@@ -1263,74 +1245,57 @@ namespace thermion_filament
|
||||
}
|
||||
}
|
||||
|
||||
void FilamentViewer::savePng(void *buf, size_t size, int frameNumber)
|
||||
void FilamentViewer::capture(uint8_t *out, bool useFence, SwapChain* swapChain, RenderTarget* renderTarget, void (*onComplete)())
|
||||
{
|
||||
// std::lock_guard lock(_recordingMutex);
|
||||
// if (!_recording)
|
||||
// {
|
||||
// delete[] static_cast<uint8_t *>(buf);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if(!renderTarget) {
|
||||
Log("NO SWAPCHAIN");
|
||||
return;
|
||||
}
|
||||
|
||||
Viewport const &vp = _view->getViewport();
|
||||
size_t pixelBufferSize = vp.width * vp.height * 4;
|
||||
auto *pixelBuffer = new uint8_t[pixelBufferSize];
|
||||
auto callback = [](void *buf, size_t size, void *data)
|
||||
{
|
||||
auto frameCallbackData = (std::vector<void *> *)data;
|
||||
uint8_t *out = (uint8_t *)(frameCallbackData->at(0));
|
||||
void *callbackPtr = frameCallbackData->at(1);
|
||||
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
int digits = 6;
|
||||
std::ostringstream stringStream;
|
||||
stringStream << _recordingOutputDirectory << "/output_";
|
||||
stringStream << std::setfill('0') << std::setw(digits);
|
||||
stringStream << std::to_string(frameNumber);
|
||||
stringStream << ".png";
|
||||
memcpy(out, buf, size);
|
||||
delete frameCallbackData;
|
||||
if(callbackPtr) {
|
||||
void (*callback)(void) = (void (*)(void))callbackPtr;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
std::string filename = stringStream.str();
|
||||
// Create a fence
|
||||
Fence* fence = nullptr;
|
||||
if(useFence) {
|
||||
fence = _engine->createFence();
|
||||
}
|
||||
|
||||
std::ofstream wf(filename, std::ios::out | std::ios::binary);
|
||||
auto userData = new std::vector<void *>{out, (void *)onComplete};
|
||||
|
||||
LinearImage image(toLinearWithAlpha<uint8_t>(vp.width, vp.height, vp.width * 4,
|
||||
static_cast<uint8_t *>(buf)));
|
||||
auto dispatcher = new CaptureCallbackHandler();
|
||||
|
||||
auto result = image::ImageEncoder::encode(
|
||||
wf, image::ImageEncoder::Format::PNG, image, std::string(""), std::string(""));
|
||||
auto pbd = Texture::PixelBufferDescriptor(
|
||||
pixelBuffer, pixelBufferSize,
|
||||
Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE, dispatcher, callback, userData);
|
||||
_renderer->beginFrame(swapChain, 0);
|
||||
_renderer->render(_view);
|
||||
_renderer->readPixels(renderTarget, 0, 0, vp.width, vp.height, std::move(pbd));
|
||||
_renderer->endFrame();
|
||||
|
||||
delete[] static_cast<uint8_t *>(buf);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Log("Failed to encode");
|
||||
}
|
||||
|
||||
wf.close();
|
||||
if (!wf.good())
|
||||
{
|
||||
Log("Write failed!");
|
||||
} });
|
||||
_tp->add_task(lambda);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
_engine->execute();
|
||||
emscripten_webgl_commit_frame();
|
||||
#endif
|
||||
if(fence) {
|
||||
Fence::waitAndDestroy(fence);
|
||||
}
|
||||
|
||||
void FilamentViewer::setRecordingOutputDirectory(const char *path)
|
||||
{
|
||||
_recordingOutputDirectory = std::string(path);
|
||||
auto outputDirAsPath = std::filesystem::path(path);
|
||||
if (!std::filesystem::is_directory(outputDirAsPath))
|
||||
{
|
||||
std::filesystem::create_directories(outputDirAsPath);
|
||||
}
|
||||
}
|
||||
|
||||
void FilamentViewer::setRecording(bool recording)
|
||||
{
|
||||
// std::lock_guard lock(_recordingMutex);
|
||||
if (recording)
|
||||
{
|
||||
_tp = new thermion_filament::ThreadPool(16);
|
||||
_recordingStartTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete _tp;
|
||||
}
|
||||
this->_recording = recording;
|
||||
}
|
||||
|
||||
Camera* FilamentViewer::getCamera(EntityId entity) {
|
||||
@@ -1381,7 +1346,7 @@ namespace thermion_filament
|
||||
|
||||
void FilamentViewer::grabBegin(float x, float y, bool pan)
|
||||
{
|
||||
if (!_view || !_mainCamera || !_swapChain)
|
||||
if (!_view || !_mainCamera)
|
||||
{
|
||||
Log("View not ready, ignoring grab");
|
||||
return;
|
||||
@@ -1395,7 +1360,7 @@ namespace thermion_filament
|
||||
|
||||
void FilamentViewer::grabUpdate(float x, float y)
|
||||
{
|
||||
if (!_view || !_swapChain)
|
||||
if (!_view )
|
||||
{
|
||||
Log("View not ready, ignoring grab");
|
||||
return;
|
||||
@@ -1413,7 +1378,7 @@ namespace thermion_filament
|
||||
|
||||
void FilamentViewer::grabEnd()
|
||||
{
|
||||
if (!_view || !_mainCamera || !_swapChain)
|
||||
if (!_view || !_mainCamera )
|
||||
{
|
||||
Log("View not ready, ignoring grab");
|
||||
return;
|
||||
|
||||
@@ -56,9 +56,23 @@ extern "C"
|
||||
return reinterpret_cast<TEngine*>(engine);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget* Viewer_createRenderTarget(TViewer *tViewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createRenderTarget(texture, width, height);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = viewer->createRenderTarget(texture, width, height);
|
||||
return reinterpret_cast<TRenderTarget*>(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget* tRenderTarget) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget*>(tRenderTarget);
|
||||
viewer->destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setRenderTarget(TViewer *tViewer, TRenderTarget* tRenderTarget) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget*>(tRenderTarget);
|
||||
viewer->setRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer)
|
||||
@@ -349,18 +363,22 @@ extern "C"
|
||||
cam->setModelMatrix(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool render(
|
||||
TViewer *viewer,
|
||||
EMSCRIPTEN_KEEPALIVE bool Viewer_render(
|
||||
TViewer *tViewer,
|
||||
TSwapChain *tSwapChain,
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
|
||||
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
|
||||
auto viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
return viewer->render(frameTimeInNanos, swapChain, pixelBuffer, callback, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void capture(
|
||||
TViewer *viewer,
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *tViewer,
|
||||
TSwapChain* tSwapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
@@ -369,7 +387,27 @@ extern "C"
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
((FilamentViewer *)viewer)->capture(pixelBuffer, useFence, callback);
|
||||
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
|
||||
auto viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
viewer->capture(pixelBuffer, useFence, swapChain, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *tViewer,
|
||||
TSwapChain* tSwapChain,
|
||||
TRenderTarget *tRenderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool useFence = true;
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget*>(tRenderTarget);
|
||||
auto viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
viewer->capture(pixelBuffer, useFence, swapChain, renderTarget, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
||||
@@ -379,14 +417,17 @@ extern "C"
|
||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain* tSwapChain)
|
||||
{
|
||||
((FilamentViewer *)viewer)->destroySwapChain();
|
||||
auto viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
|
||||
viewer->destroySwapChain(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(TViewer *viewer, const void *const window, uint32_t width, uint32_t height)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createSwapChain(window, width, height);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window, uint32_t width, uint32_t height) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(window, width, height);
|
||||
return reinterpret_cast<TSwapChain*>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void update_viewport(TViewer *viewer, uint32_t width, uint32_t height)
|
||||
@@ -837,16 +878,6 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording(TViewer *viewer, bool recording)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setRecording(recording);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(TViewer *viewer, const char *outputDirectory)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setRecordingOutputDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy()
|
||||
{
|
||||
Log("Dummy called");
|
||||
|
||||
@@ -49,8 +49,8 @@ public:
|
||||
|
||||
~RenderLoop()
|
||||
{
|
||||
_render = false;
|
||||
_stop = true;
|
||||
target = nullptr;
|
||||
_cv.notify_one();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
pthread_join(t, NULL);
|
||||
@@ -82,20 +82,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void requestFrame(void (*callback)())
|
||||
void requestFrame(SwapChain* swapChain, void (*callback)())
|
||||
{
|
||||
this->_render = true;
|
||||
this->target = swapChain;
|
||||
this->_requestFrameRenderCallback = callback;
|
||||
}
|
||||
|
||||
void iter()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (_render)
|
||||
if (target)
|
||||
{
|
||||
doRender();
|
||||
doRender(target);
|
||||
this->_requestFrameRenderCallback();
|
||||
_render = false;
|
||||
target = nullptr;
|
||||
|
||||
// Calculate and print FPS
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
@@ -123,7 +123,7 @@ public:
|
||||
}
|
||||
|
||||
_cv.wait_for(lock, std::chrono::microseconds(1000), [this]
|
||||
{ return !_tasks.empty() || _stop || _render; });
|
||||
{ return !_tasks.empty() || _stop; });
|
||||
|
||||
if (_stop)
|
||||
return;
|
||||
@@ -169,14 +169,14 @@ public:
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
_render = false;
|
||||
target = nullptr;
|
||||
_viewer = nullptr;
|
||||
destroy_filament_viewer(reinterpret_cast<TViewer*>(viewer)); });
|
||||
auto fut = add_task(lambda);
|
||||
fut.wait();
|
||||
}
|
||||
|
||||
bool doRender()
|
||||
bool doRender(SwapChain *swapChain)
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (emscripten_is_webgl_context_lost(_context) == EM_TRUE)
|
||||
@@ -187,7 +187,8 @@ public:
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
auto rendered = render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||
TSwapChain *tSwapChain = reinterpret_cast<TSwapChain*>(swapChain);
|
||||
auto rendered = Viewer_render(_viewer, tSwapChain, 0, nullptr, nullptr, nullptr);
|
||||
if (_renderCallback)
|
||||
{
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
@@ -217,7 +218,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
std::atomic_bool _render = false;
|
||||
SwapChain* target;
|
||||
|
||||
private:
|
||||
void(*_requestFrameRenderCallback)() = nullptr;
|
||||
@@ -270,16 +271,31 @@ extern "C"
|
||||
_rl = nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(TViewer *viewer,
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer,
|
||||
void *const surface,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)())
|
||||
void (*onComplete)(TSwapChain*))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
create_swap_chain(viewer, surface, width, height);
|
||||
auto *swapChain = Viewer_createSwapChain(viewer, surface, width, height);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete(swapChain);
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_destroySwapChain(viewer, swapChain);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
@@ -289,40 +305,8 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(TViewer *viewer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
destroy_swap_chain(viewer);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(TViewer *viewer,
|
||||
intptr_t nativeTextureId,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
create_render_target(viewer, nativeTextureId, width, height);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(TViewer *viewer, void(*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, TSwapChain* tSwapChain, void(*onComplete)())
|
||||
{
|
||||
if (!_rl)
|
||||
{
|
||||
@@ -330,7 +314,7 @@ extern "C"
|
||||
}
|
||||
else
|
||||
{
|
||||
_rl->requestFrame(onComplete);
|
||||
_rl->requestFrame(reinterpret_cast<SwapChain*>(tSwapChain), onComplete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,17 +327,24 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void render_render_thread(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TSwapChain *tSwapChain)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ _rl->doRender(); });
|
||||
{ _rl->doRender(reinterpret_cast<SwapChain*>(tSwapChain)); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void capture_render_thread(TViewer *viewer, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TSwapChain *tSwapChain, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ capture(viewer, pixelBuffer, onComplete); });
|
||||
{ Viewer_capture(viewer, tSwapChain, pixelBuffer, onComplete); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TSwapChain *tSwapChain, TRenderTarget* tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ Viewer_captureRenderTarget(viewer, tSwapChain, tRenderTarget, pixelBuffer, onComplete); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user