Skip to content

Commit 3ab1ca2

Browse files
authored
Improve webgl render fps (#2379)
Improve webgl fps
1 parent 11f1108 commit 3ab1ca2

File tree

13 files changed

+174
-81
lines changed

13 files changed

+174
-81
lines changed

cmake/Modules/AXBuildHelpers.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ set(AX_WASM_SHELL_FILE "${_AX_ROOT}/core/platform/wasm/shell_minimal.html" CACHE
533533

534534
option(AX_WASM_ENABLE_DEVTOOLS "Enable wasm devtools" ON)
535535

536-
set(_AX_WASM_EXPORTS "_main,_axmol_wgl_context_lost,_axmol_wgl_context_restored,_axmol_hdoc_visibilitychange")
536+
set(_AX_WASM_EXPORTS "_main,_axmol_webglcontextlost,_axmol_webglcontextrestored,_axmol_hdoc_visibilitychange")
537537
if(AX_WASM_ENABLE_DEVTOOLS)
538538
string(APPEND _AX_WASM_EXPORTS ",_axmol_dev_pause,_axmol_dev_resume,_axmol_dev_step")
539539
endif()

core/base/JobSystem.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
#include <functional>
3636
#include <stdexcept>
3737

38+
#if defined(__EMSCRIPTEN__)
39+
# include <emscripten/emscripten.h>
40+
#endif
41+
3842
namespace ax
3943
{
4044

@@ -135,15 +139,20 @@ static int clampThreads(int nThreads)
135139
{
136140
if (nThreads <= 0)
137141
{
138-
#if !defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__)
142+
#if !defined(__EMSCRIPTEN__)
139143
# if defined(AX_PLATFORM_PC)
140144
nThreads = (std::max)(static_cast<int>(std::thread::hardware_concurrency() * 3 / 2), 2);
141145
# else
142146
nThreads = (std::clamp)(static_cast<int>(std::thread::hardware_concurrency()) - 2, 2, 8);
143147
# endif
144148
#else
145-
AXLOGW("The emscripten pthread not enabled, JobSystem not working");
149+
# if defined(__EMSCRIPTEN_PTHREADS__)
150+
nThreads = EM_ASM_INT(return PThread.unusedWorkers.length);
151+
AXLOGI("The emscripten pthread enabled, unused workers count:{}", nThreads);
152+
# else
146153
nThreads = 0;
154+
AXLOGW("The emscripten pthread not enabled, JobSystem not working");
155+
# endif
147156
#endif
148157
}
149158

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

236245
#pragma endregion
237246

238-
}
247+
} // namespace ax

core/platform/android/Application-android.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Application::~Application()
6565

6666
int Application::run()
6767
{
68-
// Initialize instance and cocos2d.
68+
// Initialize instance and axmol.
6969
if (!applicationDidFinishLaunching())
7070
{
7171
return 0;

core/platform/wasm/Application-wasm.cpp

Lines changed: 91 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@ THE SOFTWARE.
3636
# include "base/Director.h"
3737
# include "base/Utils.h"
3838
# include "platform/FileUtils.h"
39+
# include "yasio/utils.hpp"
3940
# include <emscripten/emscripten.h>
4041

42+
extern void axmol_wasm_app_exit();
43+
4144
extern "C" {
4245
//
4346
void axmol_hdoc_visibilitychange(bool hidden)
@@ -47,13 +50,13 @@ void axmol_hdoc_visibilitychange(bool hidden)
4750
}
4851

4952
// webglcontextlost
50-
void axmol_wgl_context_lost()
53+
void axmol_webglcontextlost()
5154
{
5255
AXLOGI("receive event: webglcontextlost");
5356
}
5457

5558
// webglcontextrestored
56-
void axmol_wgl_context_restored()
59+
void axmol_webglcontextrestored()
5760
{
5861
AXLOGI("receive event: webglcontextrestored");
5962

@@ -90,7 +93,76 @@ namespace ax
9093
// sharedApplication pointer
9194
Application* Application::sm_pSharedApplication = nullptr;
9295

93-
Application::Application() : _animationSpeed(60)
96+
static int64_t NANOSECONDSPERSECOND = 1000000000LL;
97+
static int64_t NANOSECONDSPERMICROSECOND = 1000000LL;
98+
static int64_t FPS_CONTROL_THRESHOLD = static_cast<int64_t>(1.0f / 1200.0f * NANOSECONDSPERSECOND);
99+
100+
static int64_t s_animationInterval = static_cast<int64_t>(1/60.0 * NANOSECONDSPERSECOND);
101+
102+
static Director* __director;
103+
static int64_t mLastTickInNanoSeconds = 0;
104+
105+
static void renderFrame() {
106+
auto director = __director;
107+
auto glview = director->getGLView();
108+
109+
director->mainLoop();
110+
glview->pollEvents();
111+
112+
if (glview->windowShouldClose())
113+
{
114+
AXLOGI("shuting down axmol wasm app ...");
115+
emscripten_cancel_main_loop(); // Cancel current loop and set the cleanup one.
116+
117+
if (glview->isOpenGLReady())
118+
{
119+
director->end();
120+
director->mainLoop();
121+
}
122+
glview->release();
123+
124+
axmol_wasm_app_exit();
125+
}
126+
}
127+
128+
static void updateFrame(void)
129+
{
130+
renderFrame();
131+
132+
/*
133+
* No need to use algorithm in default(60,90,120... FPS) situation,
134+
* since onDrawFrame() was called by system 60 times per second by default.
135+
*/
136+
if (s_animationInterval > FPS_CONTROL_THRESHOLD) {
137+
auto interval = yasio::xhighp_clock() - mLastTickInNanoSeconds;
138+
139+
if (interval < s_animationInterval) {
140+
std::this_thread::sleep_for(std::chrono::nanoseconds(s_animationInterval - interval));
141+
}
142+
143+
mLastTickInNanoSeconds = yasio::xhighp_clock();
144+
}
145+
}
146+
147+
static void getCurrentLangISO2(char buf[16]) {
148+
// clang-format off
149+
EM_ASM_ARGS(
150+
{
151+
var lang = localStorage.getItem('localization_language');
152+
if (lang == null)
153+
{
154+
stringToUTF8(window.navigator.language.replace(/-.*/, ""), $0, 16);
155+
}
156+
else
157+
{
158+
stringToUTF8(lang, $0, 16);
159+
}
160+
},
161+
buf);
162+
// clang-format on
163+
}
164+
165+
Application::Application()
94166
{
95167
AX_ASSERT(!sm_pSharedApplication);
96168
sm_pSharedApplication = this;
@@ -102,15 +174,6 @@ Application::~Application()
102174
sm_pSharedApplication = nullptr;
103175
}
104176

105-
extern "C" void mainLoopIter(void)
106-
{
107-
auto director = Director::getInstance();
108-
auto glview = director->getGLView();
109-
110-
director->mainLoop();
111-
glview->pollEvents();
112-
}
113-
114177
int Application::run()
115178
{
116179
initGLContextAttrs();
@@ -120,33 +183,27 @@ int Application::run()
120183
return 1;
121184
}
122185

123-
auto director = Director::getInstance();
124-
auto glview = director->getGLView();
186+
__director = Director::getInstance();
125187

126188
// Retain glview to avoid glview being released in the while loop
127-
glview->retain();
128-
129-
// emscripten_set_main_loop(&mainLoopIter, 0, 1);
130-
emscripten_set_main_loop(&mainLoopIter, _animationSpeed, 1);
131-
// TODO: ? does these cleanup really run?
132-
/* Only work on Desktop
133-
* Director::mainLoop is really one frame logic
134-
* when we want to close the window, we should call Director::end();
135-
* then call Director::mainLoop to do release of internal resources
136-
*/
137-
if (glview->isOpenGLReady())
138-
{
139-
director->end();
140-
director->mainLoop();
141-
director = nullptr;
142-
}
143-
glview->release();
189+
__director->getGLView()->retain();
190+
191+
/*
192+
The JavaScript environment will call that function at a specified number
193+
of frames per second. If called on the main browser thread, setting 0 or
194+
a negative value as the fps will use the browser’s requestAnimationFrame mechanism
195+
o call the main loop function. This is HIGHLY recommended if you are doing rendering,
196+
as the browser’s requestAnimationFrame will make sure you render at a proper smooth rate
197+
that lines up properly with the browser and monitor.
198+
*/
199+
emscripten_set_main_loop(updateFrame, -1, false);
200+
144201
return 0;
145202
}
146203

147204
void Application::setAnimationInterval(float interval)
148205
{
149-
_animationSpeed = 1.0f / interval;
206+
s_animationInterval = static_cast<int64_t>(interval * NANOSECONDSPERSECOND);
150207
}
151208

152209
void Application::setResourceRootPath(const std::string& rootResDir)
@@ -203,20 +260,7 @@ const char* Application::getCurrentLanguageCode()
203260
{
204261
static char code[3] = {0};
205262
char pLanguageName[16];
206-
207-
EM_ASM_ARGS(
208-
{
209-
var lang = localStorage.getItem('localization_language');
210-
if (lang == null)
211-
{
212-
stringToUTF8(window.navigator.language.replace(/ - .*/, ""), $0, 16);
213-
}
214-
else
215-
{
216-
stringToUTF8(lang, $0, 16);
217-
}
218-
},
219-
pLanguageName);
263+
getCurrentLangISO2(pLanguageName);
220264
strncpy(code, pLanguageName, 2);
221265
code[2] = '\0';
222266
return code;
@@ -225,21 +269,7 @@ const char* Application::getCurrentLanguageCode()
225269
LanguageType Application::getCurrentLanguage()
226270
{
227271
char pLanguageName[16];
228-
229-
EM_ASM_ARGS(
230-
{
231-
var lang = localStorage.getItem('localization_language');
232-
if (lang == null)
233-
{
234-
stringToUTF8(window.navigator.language.replace(/ - .*/, ""), $0, 16);
235-
}
236-
else
237-
{
238-
stringToUTF8(lang, $0, 16);
239-
}
240-
},
241-
pLanguageName);
242-
272+
getCurrentLangISO2(pLanguageName);
243273
return utils::getLanguageTypeByISO2(pLanguageName);
244274
}
245275

core/platform/wasm/Application-wasm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ class Application : public ApplicationBase
112112
*/
113113
virtual Platform getTargetPlatform() override;
114114
protected:
115-
long _animationSpeed; // micro second
116115
std::string _resourceRootPath;
117116

118117
static Application * sm_pSharedApplication;

core/platform/wasm/shell_minimal.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@
140140
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
141141
// application robust, you may want to override this behavior before shipping!
142142
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
143-
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);
144-
canvas.addEventListener("webglcontextrestored", function(e) { Module.ccall('axmol_wgl_context_restored'); e.preventDefault(); }, false);
143+
canvas.addEventListener("webglcontextlost", function(e) { Module.ccall('axmol_webglcontextlost'); alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
144+
canvas.addEventListener("webglcontextrestored", function(e) { Module.ccall('axmol_webglcontextrestored'); e.preventDefault(); }, false);
145145

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

templates/common/proj.wasm/main.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,23 @@
3333

3434
using namespace ax;
3535

36-
int axmol_main()
36+
namespace
3737
{
38-
// create the application instance
39-
AppDelegate app;
40-
return Application::getInstance()->run();
38+
std::unique_ptr<AppDelegate> appDelegate;
4139
}
4240

43-
int main(int argc, char** argv)
41+
void axmol_wasm_app_exit()
4442
{
45-
auto result = axmol_main();
43+
appDelegate = nullptr;
4644

4745
#if AX_OBJECT_LEAK_DETECTION
4846
Object::printLeaks();
4947
#endif
48+
}
5049

51-
return result;
50+
int main(int argc, char** argv)
51+
{
52+
// create the application instance
53+
appDelegate.reset(new AppDelegate());
54+
return Application::getInstance()->run();
5255
}

tests/cpp-tests/Source/AppDelegate.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ AppDelegate::AppDelegate() : _testController(nullptr) {}
3838

3939
AppDelegate::~AppDelegate()
4040
{
41+
42+
AXLOGI("AppDelegate::~AppDelegate");
4143
// SimpleAudioEngine::end();
4244
// TODO: minggo
4345
// cocostudio::ArmatureDataManager::destroyInstance();

tests/cpp-tests/proj.wasm/main.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,19 @@
3232

3333
using namespace ax;
3434

35+
namespace
36+
{
37+
std::unique_ptr<AppDelegate> appDelegate;
38+
}
39+
40+
void axmol_wasm_app_exit()
41+
{
42+
appDelegate = nullptr;
43+
}
44+
3545
int main(int argc, char** argv)
3646
{
3747
// create the application instance
38-
AppDelegate app;
48+
appDelegate.reset(new AppDelegate());
3949
return Application::getInstance()->run();
4050
}

tests/fairygui-tests/proj.wasm/main.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,19 @@
3232

3333
using namespace ax;
3434

35+
namespace
36+
{
37+
std::unique_ptr<AppDelegate> appDelegate;
38+
}
39+
40+
void axmol_wasm_app_exit()
41+
{
42+
appDelegate = nullptr;
43+
}
44+
3545
int main(int argc, char** argv)
3646
{
3747
// create the application instance
38-
AppDelegate app;
48+
appDelegate.reset(new AppDelegate());
3949
return Application::getInstance()->run();
4050
}

0 commit comments

Comments
 (0)