emscripten-core / emscripten-core/emscripten
Pressing with 2 fingers on an Emscripten web page causes an assertion failure on some tablets
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
I made an Emscripten SDL webpage. When I press with 2 fingers on the webpage when running it on my Amazon Fire tablet with Firefox web browser (version 88.1.2), there's a crash / freeze. It didn't happen on 2 other tablets I tried, an iPad and a Windows tablet.
Using Firefox Remote Debugging I discovered that it's an assertion failure in the generated .js code that Emscripten created. In __registerTouchEventCallback, there are 3 assertions which all fail:
`assert(!touch.isChanged);`
`assert(!touch.onTarget);`
`assert(!touch.onTarget);`
This comment was an explanation for those asserts, though I don't quite understand it:
`// Verify that browser does not recycle touch objects with old stale data, but reports new ones each time.`
Does this mean it's a bug in the browser? If so, is there a workaround?
I reproduced it with a simple test program with Emscripten 2.0.18, as well as 1.39.18, the version I was using the most.
I think it's related to, or the same as, this bug:
https://github.com/emscripten-core/emscripten/issues/12826
In that bug, @lpotter claimed that it doesn't happen with Emscripten 1.39.8. I downgraded to that version and it also fixed my problem.
Here is my test program:
```
#include
#include
#include
#ifdef __EMSCRIPTEN__
#include
#endif
using namespace std;
namespace {
/** The main SDL window */
SDL_Window* window = NULL;
/** The renderer used to render to the screen */
SDL_Renderer* renderer = NULL;
bool blink = false;
bool quit = false;
unsigned int currentTime = 0;
unsigned int startTime = 0;
}
void render() {
SDL_Rect rect;
rect.x = 10;
rect.y = 10;
rect.h = 100;
rect.w = 100;
currentTime = SDL_GetTicks();
unsigned int quarterSecondsSinceStart = (currentTime - startTime) / 250;
blink = quarterSecondsSinceStart % 2 == 1;
if (0 != SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0)) {
printf("Error setting clear colour");
}
if (0 != SDL_RenderClear(renderer)) {
printf("Error clearing");
}
int r, g, b;
r = 251; g = 211; b = 146;
if (0 != SDL_SetRenderDrawColor(renderer, r, g, b, 0)) {
printf("Error setting colour");
}
if (blink) {
if (SDL_RenderDrawRect(renderer, &rect) != 0) {
printf("Error in SDL_RenderDrawRect");
}
} else {
if (SDL_RenderFillRect(renderer, &rect) != 0) {
printf("Error in SDL_RenderDrawRect");
}
}
SDL_RenderPresent(renderer);
}
/** Called repeatedly to redraw the screen and process input */
void mainLoopFunction()
{
//Struct for handling events
SDL_Event input;
render();
//---Event polling method---
//It runs until the number of events to be polled gets to zero
while (SDL_PollEvent(&input) > 0)
{
//If they quit the game, e.g. by closing the window
if (input.type == SDL_QUIT) {
#ifdef __EMSCRIPTEN__
emscripten_cancel_main_loop();
#endif
return;
}
}
}
int main(int argc, char** args)
{
if (0 != SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS)) {
printf("Error initializing SDL: %s", SDL_GetError());
return 1;
}
startTime = SDL_GetTicks();
window = SDL_CreateWindow("Test",
SDL_WINDOWPOS_CENTERED_DISPLAY(0), SDL_WINDOWPOS_CENTERED_DISPLAY(0),
640, 480,
(SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE));
if (window == NULL) {
printf("Error creating window");
return 1;
} else {
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
if (renderer == NULL) {
printf("Error creating renderer");
return 2;
} else {
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(mainLoopFunction, -1, 1);
#else
do {
mainLoopFunction();
} while (quit == false);
#endif
if (renderer) {
SDL_DestroyRenderer(renderer);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
}
}
return 0;
}
```
Contributor guide
Assessment
This issue has not been assessed yet.