Skip to content

Commit

Permalink
Improve webgl render fps
Browse files Browse the repository at this point in the history
  • Loading branch information
halx99 committed Feb 11, 2025
1 parent e7ee137 commit f4bef15
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 48 deletions.
2 changes: 1 addition & 1 deletion cmake/Modules/AXBuildHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ set(AX_WASM_SHELL_FILE "${_AX_ROOT}/core/platform/wasm/shell_minimal.html" CACHE

option(AX_WASM_ENABLE_DEVTOOLS "Enable wasm devtools" ON)

set(_AX_WASM_EXPORTS "_main,_axmol_wgl_context_lost,_axmol_wgl_context_restored,_axmol_hdoc_visibilitychange")
set(_AX_WASM_EXPORTS "_main,_axmol_frame_step,_axmol_webglcontextlost,_axmol_webglcontextrestored,_axmol_hdoc_visibilitychange")
if(AX_WASM_ENABLE_DEVTOOLS)
string(APPEND _AX_WASM_EXPORTS ",_axmol_dev_pause,_axmol_dev_resume,_axmol_dev_step")
endif()
Expand Down
15 changes: 12 additions & 3 deletions core/base/JobSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
#include <functional>
#include <stdexcept>

#if defined(__EMSCRIPTEN__)
# include <emscripten/emscripten.h>
#endif

namespace ax
{

Expand Down Expand Up @@ -135,15 +139,20 @@ static int clampThreads(int nThreads)
{
if (nThreads <= 0)
{
#if !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)
#if !defined(__EMSCRIPTEN__)
# if defined(AX_PLATFORM_PC)
nThreads = (std::max)(static_cast<int>(std::thread::hardware_concurrency() * 3 / 2), 2);
# else
nThreads = (std::clamp)(static_cast<int>(std::thread::hardware_concurrency()) - 2, 2, 8);
# endif
#else
AXLOGW("The emscripten pthread not enabled, JobSystem not working");
# if defined(__EMSCRIPTEN_PTHREADS__)
nThreads = EM_ASM_INT(return PThread.unusedWorkers.length);
AXLOGI("The emscripten pthread enabled, unused workers count:{}", nThreads);
# else
nThreads = 0;
AXLOGW("The emscripten pthread not enabled, JobSystem not working");
# endif
#endif
}

Expand Down Expand Up @@ -235,4 +244,4 @@ void JobSystem::enqueue(std::function<void()> task, std::function<void()> done)

#pragma endregion

}
} // namespace ax
2 changes: 1 addition & 1 deletion core/platform/android/Application-android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Application::~Application()

int Application::run()
{
// Initialize instance and cocos2d.
// Initialize instance and axmol.
if (!applicationDidFinishLaunching())
{
return 0;
Expand Down
95 changes: 67 additions & 28 deletions core/platform/wasm/Application-wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ THE SOFTWARE.
# include "base/Director.h"
# include "base/Utils.h"
# include "platform/FileUtils.h"
# include "yasio/utils.hpp"
# include <emscripten/emscripten.h>

extern void axmol_wasm_app_exit();

extern "C" {
//
void axmol_hdoc_visibilitychange(bool hidden)
Expand All @@ -47,13 +50,13 @@ void axmol_hdoc_visibilitychange(bool hidden)
}

// webglcontextlost
void axmol_wgl_context_lost()
void axmol_webglcontextlost()
{
AXLOGI("receive event: webglcontextlost");
}

// webglcontextrestored
void axmol_wgl_context_restored()
void axmol_webglcontextrestored()
{
AXLOGI("receive event: webglcontextrestored");

Expand Down Expand Up @@ -90,7 +93,13 @@ namespace ax
// sharedApplication pointer
Application* Application::sm_pSharedApplication = nullptr;

Application::Application() : _animationSpeed(60)
static int64_t NANOSECONDSPERSECOND = 1000000000LL;
static int64_t NANOSECONDSPERMICROSECOND = 1000000LL;
static int64_t FPS_CONTROL_THRESHOLD = static_cast<int64_t>(1.0f / 1200.0f * NANOSECONDSPERSECOND);

static int64_t s_animationInterval = static_cast<int64_t>(1/60.0 * NANOSECONDSPERSECOND);

Application::Application() : _animationInterval(1/60.0 * NANOSECONDSPERSECOND)
{
AX_ASSERT(!sm_pSharedApplication);
sm_pSharedApplication = this;
Expand All @@ -102,13 +111,49 @@ Application::~Application()
sm_pSharedApplication = nullptr;
}

extern "C" void mainLoopIter(void)
{
auto director = Director::getInstance();
static Director* __director;
static int64_t mLastTickInNanoSeconds = 0;

static void axmol_native_render() {
auto director = __director;
auto glview = director->getGLView();

director->mainLoop();
glview->pollEvents();

if (glview->windowShouldClose())
{
AXLOGI("shuting down axmol wasm app ...");
emscripten_cancel_main_loop(); // Cancel current loop and set the cleanup one.

if (glview->isOpenGLReady())
{
director->end();
director->mainLoop();
}
glview->release();

axmol_wasm_app_exit();
}
}

extern "C" void axmol_frame_step(void)
{
axmol_native_render();

/*
* No need to use algorithm in default(60,90,120... FPS) situation,
* since onDrawFrame() was called by system 60 times per second by default.
*/
if (s_animationInterval > FPS_CONTROL_THRESHOLD) {
auto interval = yasio::xhighp_clock() - mLastTickInNanoSeconds;

if (interval < s_animationInterval) {
std::this_thread::sleep_for(std::chrono::nanoseconds(s_animationInterval - interval));
}

mLastTickInNanoSeconds = yasio::xhighp_clock();
}
}

int Application::run()
Expand All @@ -120,33 +165,27 @@ int Application::run()
return 1;
}

auto director = Director::getInstance();
auto glview = director->getGLView();
__director = Director::getInstance();

// Retain glview to avoid glview being released in the while loop
glview->retain();

// emscripten_set_main_loop(&mainLoopIter, 0, 1);
emscripten_set_main_loop(&mainLoopIter, _animationSpeed, 1);
// TODO: ? does these cleanup really run?
/* Only work on Desktop
* Director::mainLoop is really one frame logic
* when we want to close the window, we should call Director::end();
* then call Director::mainLoop to do release of internal resources
*/
if (glview->isOpenGLReady())
{
director->end();
director->mainLoop();
director = nullptr;
}
glview->release();
__director->getGLView()->retain();

/*
The JavaScript environment will call that function at a specified number
of frames per second. If called on the main browser thread, setting 0 or
a negative value as the fps will use the browser’s requestAnimationFrame mechanism
o call the main loop function. This is HIGHLY recommended if you are doing rendering,
as the browser’s requestAnimationFrame will make sure you render at a proper smooth rate
that lines up properly with the browser and monitor.
*/
emscripten_set_main_loop(axmol_frame_step, -1, false);

return 0;
}

void Application::setAnimationInterval(float interval)
{
_animationSpeed = 1.0f / interval;
s_animationInterval = static_cast<int64_t>(interval * NANOSECONDSPERSECOND);
}

void Application::setResourceRootPath(const std::string& rootResDir)
Expand Down Expand Up @@ -209,7 +248,7 @@ const char* Application::getCurrentLanguageCode()
var lang = localStorage.getItem('localization_language');
if (lang == null)
{
stringToUTF8(window.navigator.language.replace(/ - .*/, ""), $0, 16);
stringToUTF8(window.navigator.language.replace(/ -.*/, ""), $0, 16);
}
else
{
Expand All @@ -231,7 +270,7 @@ LanguageType Application::getCurrentLanguage()
var lang = localStorage.getItem('localization_language');
if (lang == null)
{
stringToUTF8(window.navigator.language.replace(/ - .*/, ""), $0, 16);
stringToUTF8(window.navigator.language.replace(/ -.*/, ""), $0, 16);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion core/platform/wasm/Application-wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class Application : public ApplicationBase
*/
virtual Platform getTargetPlatform() override;
protected:
long _animationSpeed; // micro second
int64_t _animationInterval; // nanoseconds
std::string _resourceRootPath;

static Application * sm_pSharedApplication;
Expand Down
4 changes: 2 additions & 2 deletions core/platform/wasm/shell_minimal.html
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { Module.ccall('axmol_wgl_context_lost'); alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
canvas.addEventListener("webglcontextrestored", function(e) { Module.ccall('axmol_wgl_context_restored'); e.preventDefault(); }, false);
canvas.addEventListener("webglcontextlost", function(e) { Module.ccall('axmol_webglcontextlost'); alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
canvas.addEventListener("webglcontextrestored", function(e) { Module.ccall('axmol_webglcontextrestored'); e.preventDefault(); }, false);

document.addEventListener("visibilitychange", () => { Module.ccall('axmol_hdoc_visibilitychange', document.hidden); });

Expand Down
17 changes: 10 additions & 7 deletions templates/common/proj.wasm/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,23 @@

using namespace ax;

int axmol_main()
namespace
{
// create the application instance
AppDelegate app;
return Application::getInstance()->run();
std::unique_ptr<AppDelegate> appDelegate;
}

int main(int argc, char** argv)
void axmol_wasm_app_exit()
{
auto result = axmol_main();
appDelegate = nullptr;

#if AX_OBJECT_LEAK_DETECTION
Object::printLeaks();
#endif
}

return result;
int main(int argc, char** argv)
{
// create the application instance
appDelegate.reset(new AppDelegate());
return Application::getInstance()->run();
}
2 changes: 2 additions & 0 deletions tests/cpp-tests/Source/AppDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ AppDelegate::AppDelegate() : _testController(nullptr) {}

AppDelegate::~AppDelegate()
{

AXLOGI("AppDelegate::~AppDelegate");
// SimpleAudioEngine::end();
// TODO: minggo
// cocostudio::ArmatureDataManager::destroyInstance();
Expand Down
12 changes: 11 additions & 1 deletion tests/cpp-tests/proj.wasm/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@

using namespace ax;

namespace
{
std::unique_ptr<AppDelegate> appDelegate;
}

void axmol_wasm_app_exit()
{
appDelegate = nullptr;
}

int main(int argc, char** argv)
{
// create the application instance
AppDelegate app;
appDelegate.reset(new AppDelegate());
return Application::getInstance()->run();
}
12 changes: 11 additions & 1 deletion tests/fairygui-tests/proj.wasm/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@

using namespace ax;

namespace
{
std::unique_ptr<AppDelegate> appDelegate;
}

void axmol_wasm_app_exit()
{
appDelegate = nullptr;
}

int main(int argc, char** argv)
{
// create the application instance
AppDelegate app;
appDelegate.reset(new AppDelegate());
return Application::getInstance()->run();
}
12 changes: 11 additions & 1 deletion tests/live2d-tests/proj.wasm/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@

using namespace ax;

namespace
{
std::unique_ptr<AppDelegate> appDelegate;
}

void axmol_wasm_app_exit()
{
appDelegate = nullptr;
}

int main(int argc, char** argv)
{
// create the application instance
AppDelegate app;
appDelegate.reset(new AppDelegate());
return Application::getInstance()->run();
}
12 changes: 11 additions & 1 deletion tests/lua-tests/proj.wasm/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@

using namespace ax;

namespace
{
std::unique_ptr<AppDelegate> appDelegate;
}

void axmol_wasm_app_exit()
{
appDelegate = nullptr;
}

int main(int argc, char** argv)
{
// create the application instance
AppDelegate app;
appDelegate.reset(new AppDelegate());
return Application::getInstance()->run();
}
12 changes: 11 additions & 1 deletion tests/unit-tests/proj.wasm/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,19 @@

using namespace ax;

namespace
{
std::unique_ptr<AppDelegate> appDelegate;
}

void axmol_wasm_app_exit()
{
appDelegate = nullptr;
}

int main(int argc, char** argv)
{
// create the application instance
AppDelegate app;
appDelegate.reset(new AppDelegate());
return Application::getInstance()->run();
}

0 comments on commit f4bef15

Please sign in to comment.