Failed to draw a triangle with Emscripten, SDL 3.0 and OpenGL ES 2.0 on old phone Redmi 4X, Android 7

The next example draws a triangle using OpenGL ES 2.0 and SDL 3.0 and it works on Infinix Hot 30, Android 13 without problems: https://65c8fc0851792f3dc1fbd7d9--spiffy-trifle-f2dd69.netlify.app/ Short url: t.ly/b9Wbp But it doesn’t work on old phone Redmi 4X, Android 7. Is it possible to solve it? I use the next template with guide: GitHub - Ravbug/sdl3-sample: Minimal HowTo for building and using SDL3 on a variety of platforms, including mobile and web

Note. Open CMakeLists.txt and set target_link_libraries adding android EGL GLESv2 here:

target_link_libraries(${EXECUTABLE_NAME} PUBLIC SDL3::SDL3 android EGL GLESv2)

image

main.cpp

#include <SDL.h>
#include <cmath>
#include <iostream>
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
// On UWP, we need to not have SDL_main otherwise we'll get a linker error
#define SDL_MAIN_HANDLED
#endif
#include <SDL_main.h>
#if __EMSCRIPTEN__
#include <emscripten.h>
#endif

#include <SDL_opengles2.h>

void SDL_Fail()
{
    SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
    exit(1);
}

static bool app_quit = false;
SDL_Window *window = nullptr;
const float maxFPS = 5.f;

const char *vertexShaderSource =
    "attribute vec2 aPosition;\n"
    "void main()"
    "{\n"
    "    gl_Position = vec4(aPosition, 0.0, 1.0);\n"
    "}\n";

const char *fragmentShaderSource =
    "void main()"
    "{\n"
    "    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
    "}\n";

GLuint createShader(const char *shaderSource, int shaderType)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &shaderSource, NULL);
    glCompileShader(shader);
    GLint status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        GLint maxLength = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
        std::vector<GLchar> errorLog(maxLength);
        glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
        glDeleteShader(shader); // Don't leak the shader.
        std::printf("%s\n", &(errorLog[0]));
        // fatalError("Shader failed to compile");
    }
    return shader;
}

GLuint createShaderProgram()
{
    GLuint program = glCreateProgram();
    GLuint vShader = createShader(vertexShaderSource, GL_VERTEX_SHADER);
    GLuint fShader = createShader(fragmentShaderSource, GL_FRAGMENT_SHADER);

    glAttachShader(program, vShader);
    glAttachShader(program, fShader);
    glLinkProgram(program);
    glUseProgram(program);

    return program;
}

void initVertexBuffers(GLuint program)
{
    float vertPositions[] = {
        -1.f, -1.f,
        1.f, -1.f,
        0.f, 1.f
    };
    GLuint vertPosBuffer;
    glGenBuffers(1, &vertPosBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertPosBuffer);
    int amount = sizeof(vertPositions) / sizeof(vertPositions[0]);
    glBufferData(GL_ARRAY_BUFFER, amount * sizeof(GLfloat),
        vertPositions, GL_STATIC_DRAW);
    GLint aPositionLocation = glGetAttribLocation(program, "aPosition");
    glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(aPositionLocation);
}

void main_loop()
{
    // Get events. If you are making a game, you probably want SDL_PollEvent instead of SDL_WaitEvent.
    // you cannot use WaitEvent on Emscripten, because you cannot block the main thread there.

    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
        if (event.type == SDL_EVENT_QUIT)
            app_quit = true;
        break;
    }
    float startTicks = SDL_GetTicks();

    // draw a color
    // auto time = SDL_GetTicks() / 1000.f;
    // auto red = (std::sin(time) + 1) / 2.0 * 255;
    // auto green = (std::sin(time / 2) + 1) / 2.0 * 255;
    // auto blue = (std::sin(time) * 2 + 1) / 2.0 * 255;
    // auto red = 50;
    // auto green = 255;
    // auto blue = 50;
    auto red = 0.2f;
    auto green = 0.2f;
    auto blue = 0.2f;

    glClearColor(red, green, blue, 1.f);
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    SDL_GL_SwapWindow(window);
    // Limit FPS to the max FPS
    float frameTicks = SDL_GetTicks() - startTicks;
    if (1000.f / maxFPS > frameTicks)
    {
        SDL_Delay(1000.f / maxFPS - frameTicks);
    }
}

// Note: your main function __must__ take this form, otherwise on nonstandard platforms (iOS, etc), your app will not launch.
int main(int argc, char *argv[])
{
    // init the library, here we make a window so we only need the Video capabilities.
    if (SDL_Init(SDL_INIT_VIDEO))
    {
        SDL_Fail();
    }

    // create a window
    SDL_Window *window = SDL_CreateWindow("Window", 352, 430, SDL_WINDOW_OPENGL);
    if (!window)
    {
        SDL_Fail();
    }

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GLContext glContext = SDL_GL_CreateContext(window);
    if (!glContext)
    {
        SDL_Fail();
    }

    GLuint program = createShaderProgram();
    initVertexBuffers(program);

    // print some information about the window
    SDL_ShowWindow(window);
    {
        int width, height, bbwidth, bbheight;
        SDL_GetWindowSize(window, &width, &height);
        SDL_GetWindowSizeInPixels(window, &bbwidth, &bbheight);
        SDL_Log("Window size: %ix%i", width, height);
        SDL_Log("Backbuffer size: %ix%i", bbwidth, bbheight);
        if (width != bbwidth)
        {
            SDL_Log("This is a highdpi environment.");
        }
    }

    SDL_Log("Application started successfully!");

#if __EMSCRIPTEN__
    // on Emscripten, we cannot have an infinite loop in main. Instead, we must
    // tell emscripten to call our main loop.
    emscripten_set_main_loop(main_loop, 0, 1);
#else
    while (!app_quit)
    {
        main_loop();
    }
#endif

    // cleanup everything at the end
#if !__EMSCRIPTEN__
    SDL_DestroyWindow(window);
    SDL_Quit();
    SDL_Log("Application quit successfully!");
#endif
    return 0;
}

Cross-ref: Failed to draw a triangle with Emscripten, SDL 3.0 and OpenGL ES 2.0 on old phone Redmi 4X, Android 7 - SDL Development - Simple Directmedia Layer

I have created the issue: Failed to draw a triangle with Emscripten, SDL 3.0 and OpenGL ES 2.0 on old phone Redmi 4X, Android 7 · Issue #9047 · libsdl-org/SDL · GitHub

Maybe I made something wrong or Ravbug has fixed his example GitHub - Ravbug/sdl3-sample: Minimal HowTo for building and using SDL3 on a variety of platforms, including mobile and web but I don’t see now the problem above.

My step by step tutorials about running OpenGL ES 2.0 apps on Android and WebAssembly: