SDL2 + GLES3 = No Context? No version? No Everything, but black?

First:

Platform: Windows
SDL2: 2.0.16 MingW
Using: MingW64
IDE: Clion
GL:  angleproject (GLES3/gl3.h)
GPU: MSI GeForce RTX 2080 Ti Ventus
Type: Cmake Project
SDL Version: 2.0.16

So…

I want to use SDL2 as Window Framework and Show GLES3 Context inside it, to build a 2D Runtime.

The CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)

project(Tester LANGUAGES CXX)
set(TEST_PROJECT ${PROJECT_NAME})

project(TileGameStudio_Runtime LANGUAGES CXX)
set(RUNTIME_PROJECT ${PROJECT_NAME})

project(Game_Lib LANGUAGES CXX)
set(LIB_PROJECT ${PROJECT_NAME})

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

#=============================================================== Fetch GoogleTest
include(FetchContent)
FetchContent_Declare(
  googletest
  URL https://github.com/google/googletest/archive/e2239ee6043f73722e7aa812a459f54a28552929.zip
)
# For Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

#=============================================================== Setup Paths
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(PROJ_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(PROJ_INC ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(PROJ_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/libs)
set(PROJ_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/tests)

set(PROJ_SRC
    ${PROJECT_SOURCE_DIR}/src
)
set(PROJ_INC
    ${PROJECT_SOURCE_DIR}/include
)

set(PROJ_TST
    ${PROJECT_SOURCE_DIR}/test
)

set(PROJ_LIBS
    ${PROJECT_SOURCE_DIR}/libs
)

file(GLOB PROJECT_SOURCES CONFIGURE_DEPENDS
    ${PROJ_SRC}/*.cpp
)

file(GLOB PROJECT_TESTS CONFIGURE_DEPENDS
    ${PROJ_TST}/*.cpp
)

file(GLOB PROJECT_HEADERS CONFIGURE_DEPENDS
    ${PROJ_INC}/*.h
)

set(ANGLE_INCLUDE_PATH "D:/Angle/angle/include")
set(ANGLE_LIBRARY_PATH "${PROJ_LIBS}")
set(MESA_INCLUDE_PATH "C:/msys64/mingw64/include/mesa")

INCLUDE(FindPkgConfig)
pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(SDL2_IMAGE REQUIRED SDL2_image)
pkg_check_modules(SDL2_TTF REQUIRED SDL2_ttf)
pkg_check_modules(SDL2_MIXER REQUIRED SDL2_mixer)
INCLUDE(FindPkgConfig)
find_package(Freetype REQUIRED)
find_package(LuaJIT REQUIRED)
find_package(PNG REQUIRED)
find_package(FLAC REQUIRED)
find_package(OGG REQUIRED)
find_package(THEORA REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(Boost COMPONENTS system filesystem json REQUIRED)

#=============================================================== OUTPUT <LIB>_FOUND
if(NOT SDL2_FOUND)
  message(STATUS "SDL2:   NO")
else()
  message(STATUS "SDL2:   YES - under: ${SDL2_INCLUDE_DIRS}")
endif()

if(NOT GTEST_FOUND)
  message(STATUS "GoogleTest:   NO")
else()
  message(STATUS "GoogleTest:   YES - under: ${GTEST_INCLUDE_DIRS}\n                 at Root: ${GTEST_ROOT}")
endif()

if(NOT FREETYPE_FOUND)
  message(STATUS "freetype2:   NO")
else()
  message(STATUS "freetype2:   YES - under: ${FREETYPE_INCLUDE_DIR_ft2build}")
endif()

if(NOT LUAJIT_FOUND)
  message(STATUS "LuaJit:   NO")
else()
  message(STATUS "LuaJit:   YES - under: ${LUA_INCLUDE_DIR}")
endif()

if(NOT PNG_FOUND)
  message(STATUS "libPNG:   NO")
else()
  message(STATUS "libPNG:   YES - under: ${PNG_INCLUDE_DIR}")
endif()

if(NOT FLAC_FOUND)
  message(STATUS "FLAC:   NO")
else()
  message(STATUS "FLAC:   YES - under: ${FLAC_INCLUDE_DIR}")
endif()

if(NOT OGG_FOUND)
  message(STATUS "OGG:   NO")
else()
  message(STATUS "OGG:   YES - under: ${OGG_INCLUDE_DIR}")
endif()

if(NOT THEORA_FOUND)
  message(STATUS "THEORA:   NO")
else()
  message(STATUS "THEORA:   YES - under: ${THEORA_INCLUDE_DIR}")
endif()

if(NOT OPENSSL_FOUND)
  message(STATUS "OpenSSL:   NO")
else()
  message(STATUS "OpenSSL:   YES - under: ${OPENSSL_INCLUDE_DIR}")
endif()

#=============================================================== Include Directories
include_directories(
    ${PROJ_LIBS}
    ${PROJ_INC}
    ${PROJ_SRC}
    ${SDL2_INCLUDE_DIRS}
    ${SDL2_IMAGE_INCLUDE_DIRS}
    ${SDL2_TTF_INCLUDE_DIRS}
    ${SDL2_MIXER_INCLUDE_DIRS}
    ${OPENGL_INCLUDE_DIR}
    ${FREETYPE_INCLUDE_DIR_ft2build}
    ${LUA_INCLUDE_DIR}
    ${ANGLE_INCLUDE_PATH}
    ${ANGLE_LIBRARY_PATH}
    ${PNG_INCLUDE_DIR}
    ${FLAC_INCLUDE_DIR}
    ${OGG_INCLUDE_DIR}
    ${THEORA_INCLUDE_DIR}
    ${ImageMagick_INCLUDE_DIRS}
    ${ImageMagick_LIBRARIES}
    ${Boost_INCLUDE_DIRS}
    ${OPENSSL_INCLUDE_DIR}
    ${Boost_INCLUDE_DIRS}
    gtest/
)

link_directories (
    ${PROJ_LIBS}
    ${PROJ_INC}
    ${PROJ_SRC}
    ${SDL2_LIBRARY_DIRS}
    ${SDL2_IMAGE_LIBRARY_DIRS}
    ${SDL2_TTF_LIBRARY_DIRS}
    ${SDL2_MIXER_LIBRARY_DIRS}
    ${OPENGL_LIBRARY_DIRS}
    ${FREETYPE_INCLUDE_DIR_ft2build}
    ${LUA_INCLUDE_DIR}
    ${ANGLE_INCLUDE_PATH}
    ${ANGLE_LIBRARY_PATH}
    ${PNG_INCLUDE_DIR}
    ${FLAC_INCLUDE_DIR}
    ${OGG_INCLUDE_DIR}
    ${THEORA_INCLUDE_DIR}
    ${ImageMagick_INCLUDE_DIRS}
    ${ImageMagick_LIBRARIES}
    ${Boost_INCLUDE_DIRS}
    ${OPENSSL_INCLUDE_DIR}
    ${Boost_LIBRARY_DIRS}
    gtest/
)

#=============================================================== Find GLES Libraries
find_library(GLES2_Lib NAMES d3dcompiler_47 REQUIRED)
find_library(D3D_Lib NAMES libGLESv2 REQUIRED)
#find_library(EGL_Lib NAMES libEGL EGL libegl)

#=============================================================== Find GTest and GMock Libraries
#find_library(GTEST_LIBRARIES NAMES libgtest_main libgtest libgmock libgmock_main REQUIRED)

#=============================================================== Collect Sources, Tests and Headers
file(GLOB PROJECT_SOURCES CONFIGURE_DEPENDS
    ${PROJ_SRC}/*.cpp
    ${PROJ_SRC}/src_ObjectClasses/*.cpp
)

file(GLOB PROJECT_HEADERS CONFIGURE_DEPENDS
    ${PROJ_INC}/*.h
    ${PROJ_INC}/include_ObjectClasses/*.h
)

file(GLOB PROJECT_TESTS CONFIGURE_DEPENDS
    ${PROJ_TST}/*.cpp
    ${PROJ_SRC}/src_ObjectClasses/*.cpp
)

#=============================================================== Create STATIC Lib of Engine Sources
if(NOT PROJECT_SOURCES)
  message("No Sources available to build static Library!")
else()
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../TileGameStudio_Editor_Build_Debug/Shipped/Data/InitProj/Libs")
  add_library(${LIB_PROJECT} STATIC ${PROJECT_HEADERS} ${PROJECT_SOURCES})
  set_target_properties(${LIB_PROJECT} PROPERTIES OUTPUT_NAME "GameLib")
  message("Added Sources to the Library and created it in ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}!")
endif()

#=============================================================== Build App
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../TileGameStudio_Editor_Build_Debug/Shipped/Data/InitProj")
set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/res.rc")
add_executable(${RUNTIME_PROJECT}
    ${PROJECT_SOURCES}
    ${PROJECT_HEADERS}
    ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/res.rc
)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../TileGameStudio_Editor_Build_Debug/Shipped/Data/InitProj/Tests")
add_executable(${TEST_PROJECT}
    ${PROJECT_SOURCES}
    ${PROJECT_HEADERS}
    ${PROJECT_TESTS}
)

set_target_properties(${RUNTIME_PROJECT} PROPERTIES OUTPUT_NAME "Game" SUFFIX ".exe")
set_target_properties(${TEST_PROJECT} PROPERTIES OUTPUT_NAME "Tests" SUFFIX ".exe")

#=============================================================== Link Libraries
target_link_libraries (${RUNTIME_PROJECT} 
    ${SDL2_LIBRARIES}
    ${SDL2_IMAGE_LIBRARIES}
    ${SDL2_TTF_LIBRARIES}
    ${SDL2_MIXER_LIBRARIES}
    ${OPENGL_gl_LIBRARY}
    ${FREETYPE_LIBRARIES}
    ${LUA_LIBRARY}
    ${GLES2_Lib}
    ${D3D_Lib}
    #${EGL_Lib}
    ${PNG_LIBRARY}
    ${FLAC_LIBRARY}
    ${OGG_LIBRARY}
    ${THEORA_LIBRARY}
    ${ImageMagick_LIBRARIES}
    ${OPENSSL_CRYPTO_LIBRARY}
    ${OPENSSL_SSL_LIBRARY}
    ${OPENSSL_LIBRARIES}
    ${Boost_LIBRARIES}
    ${Boost_SYSTEM_LIBRARY}
    ${Boost_FILESYSTEM_LIBRARY}
)

target_link_libraries (${TEST_PROJECT} 
    ${SDL2_LIBRARIES}
    ${SDL2_IMAGE_LIBRARIES}
    ${SDL2_TTF_LIBRARIES}
    ${SDL2_MIXER_LIBRARIES}
    ${OPENGL_gl_LIBRARY}
    ${FREETYPE_LIBRARIES}
    ${LUA_LIBRARY}
    ${GLES2_Lib}
    ${D3D_Lib}
    #${EGL_Lib}
    ${PNG_LIBRARY}
    ${FLAC_LIBRARY}
    ${OGG_LIBRARY}
    ${THEORA_LIBRARY}
    ${ImageMagick_LIBRARIES}
    ${OPENSSL_CRYPTO_LIBRARY}
    ${OPENSSL_SSL_LIBRARY}
    ${OPENSSL_LIBRARIES}
    ${Boost_LIBRARIES}
    ${Boost_SYSTEM_LIBRARY}
    ${Boost_FILESYSTEM_LIBRARY}
    gtest_main
)
enable_testing()
include(GoogleTest)

#=============================================================== Add GoogleTests
message("")
message("Adding Tests to ${TEST_PROJECT}")
message("")
if(NOT PROJECT_TESTS)
    message("No Tests available!")
else()
    gtest_add_tests(TARGET ${TEST_PROJECT} TEST_LIST var)
    message("Tests were added to ${TEST_PROJECT}. The List:")
    foreach(X ${var})
        message("-  ${X}")
    endforeach()
endif()
message("")

The main function is very simple:

//include basics
#include <iostream>
//include Runtime Code
#include "GameLoop.h"


//the main Function
int main(int argc, char* argv[])
{
    GameLoop gameLoop;
    gameLoop.runGame();

    return 0;
}

The GameLoop.h:

#pragma once
//include Basics
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <angle_gl.h>
//include project Sided
#include "Game_Error.h"

enum EnGameState {RUNNING, QUIT};

class GameLoop{
    public:
    GameLoop();
    ~GameLoop();
    void runGame();

private:
    void initSystems();
    void gameLoop();
    void processInput();
    void drawGame();
    SDL_Window* _window;
    int _screenWidth, _screenHeight;
    int _windowFlags;
    EnGameState _gameState;
};

The GameLoop.cpp:

#include "GameLoop.h"

GameLoop::GameLoop(){
    _gameState = EnGameState::RUNNING;
}

void GameLoop::runGame(){
    initSystems();
    gameLoop();
}

void GameLoop::initSystems(){
    //Initialize SDL2
    SDL_Init(SDL_INIT_EVERYTHING);
    //Set SDL Attributes for GLES3
    //SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1");
    SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles");
    SDL_SetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER, "none");
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 1);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,  SDL_GL_CONTEXT_PROFILE_ES);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
    //Set SDL basic Settings for a Window
    _screenWidth = 1280;
    _screenHeight = 720;
    _windowFlags = SDL_WindowFlags::SDL_WINDOW_OPENGL | SDL_WindowFlags::SDL_WINDOW_SHOWN;

    SDL_version compiled;
    SDL_version linked;

    SDL_VERSION(&compiled);
    SDL_GetVersion(&linked);
    printf("We compiled against SDL version: %d.%d.%d\n", compiled.major, compiled.minor, compiled.patch);
    printf("We are linking against SDL version: %d.%d.%d\n", linked.major, linked.minor, linked.patch);

    //Create the Window
    _window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _screenWidth, _screenHeight, _windowFlags);
    //Check for Window errors
    if(_window == nullptr) {
        Game_Error::drawError(EnErrorType::CRIT, "SDL Window could not be initialized!", "GL#0003", "GameLoop::initSystems()");
    }else{
        Game_Error::drawError(EnErrorType::INFO, "SDL Window initialized.", "", "GameLoop::initSystems()");
    }
    //Create GL Context and make it current
    auto _glContext = SDL_GL_CreateContext(_window);
    //SDL_GL_MakeCurrent(_window, _glContext);
    glViewport(0, 0, 480, 320);
    //Check for GLContext errors
    if(_glContext == nullptr){
        Game_Error::drawError(EnErrorType::CRIT, "GLContext could not be created!", "GL#0004", "GameLoop::initSystems()");
    }else{
        Game_Error::drawError(EnErrorType::INFO, "GLContext created.", "", "GameLoop::initSystems()");
    }
    SDL_GL_SetSwapInterval(0);

    printf("OpenGL ES Version: (%s) \n", glGetString(GL_VERSION));
    printf("OpenGL ES Vendor: (%s) \n", glGetString(GL_VENDOR));
    printf("OpenGL ES Renderer: (%s) \n", glGetString(GL_RENDERER));
    if(glGetError() != GL_NO_ERROR){ //Check if there are any GL Errors
        printf("OpenGL ES Error: (%d) \n", glGetError());
    }
    Game_Error::drawError(EnErrorType::INFO, "Initialization done!", "", "GameLoop::initSystems()");
}

void GameLoop::gameLoop(){
    Game_Error::drawError(EnErrorType::INFO, "Starting Game Loop", "", "GameLoop::gameLoop()");
    while(_gameState  != EnGameState::QUIT){
        processInput();
        drawGame();
    }
}

void GameLoop::processInput(){
    SDL_Event  _eventInput;
    while(SDL_PollEvent(&_eventInput)){
        switch(_eventInput.type){
            case SDL_QUIT:
                _gameState = EnGameState::QUIT;
                break;
            case SDL_MOUSEMOTION:
                //std::cout << "Mouse Position: " << _eventInput.motion.x << " , " << _eventInput.motion.y << std::endl;
                break;
            default:
                break;
        }
    }
}

void GameLoop::drawGame() {
    //set GL Clear Background Color
    glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
    //Clear GL Buffer and set Depth
    glClearDepthf(1.0f);
    //Clear Color Buffer and Depth Buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    SDL_GL_SwapWindow(_window);
}

GameLoop::~GameLoop(){

}

This results in:
Emptyness.jpg

a black Screen inside the Window.

For all who read the GameLoop.cpp… i change the ClearColor like this:

glClearColor(1.0f, 0.0f, 1.0f, 1.0f);

Means… the Screen should be completely Pink… instead of black…
Now… i added some Info Messages (the error ones), and printed the GL_VERSION

This is the Outcome:

Info in: GameLoop::initSystems()      >> SDL Window initialized.
Info in: GameLoop::initSystems()      >> GLContext created.
OpenGL ES Version: ((null))
OpenGL ES Vendor: ((null))
OpenGL ES Renderer: ((null))
Info in: GameLoop::initSystems()      >> Initialization done!
Info in: GameLoop::gameLoop()      >> Starting Game Loop

Yes… no GL_VERSION… but no error in Context Creation or anywhere else…

Can someone lead me into the right direction, why this isn´t working?

Also tried to include angle_gl.h, too… no Fix… Why i tried including GLES3/gl3.h directly…

also tried gl31.h, gl32.h, GLES2/gl2.h… no change… still black screen…

I really need help in this ^^"

I’ve not tried using OpenGL ES in Windows, but for regular OpenGL you need a hint, otherwise SDL2 will use Direct3D. So you could try adding:

SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles");

before the SDL_CreateWindow().

1 Like

That hint is not needed to use OpenGL with SDL on Windows.

It’s only used to force SDL_Renderer (CategoryRender - SDL Wiki) to use OpenGL (instead of Direct3D), but does not (or should not) influence using OpenGL directly.

Regarding the original problem, no idea, I guess something goes wrong with ANGLE.

2 Likes

This hint may be relevant though: https://github.com/emscripten-ports/SDL2/blob/master/include/SDL_hints.h#L1010-L1039

and make sure to have the ANGLE dlls (libGLESv2.dll and libEGL.dll and maybe that d3d shader DLL as well? and is there a libGLESv3.dll or is this handled by the same DLL?) next to your executable so SDL2 can find them

1 Like

Some random points:

(Actually, I choose not to rely on SDL2 for any EGL handling in ANGLE platforms and creating EGL context using ANGLE extension instead thus the code above is not used with ANGLE. But in 99% cases, just using SDL2’s own EGL/GLES support should suffice.)

and make sure to have the ANGLE dlls (libGLESv2.dll and libEGL.dll and maybe that d3d shader DLL as well?

It’s really a good point. It’d be better to check GL commands such as glGetStrings are routed to ANGLE’s DLL(libGLESv2.dll), not system OpenGL(on Windows, Opengl32.dll).

1 Like

Thanks for your Hints the last Hours.

I tried to include the Hint

SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1");

But get a Critical Error, that the SDL Window couldn´t be initialized anymore.

The libGLESv2.dll and d3dcompiler_47.dll are in the /libs Folder of the Project, and Cmake found them… since they are REQUIRED and there is no Error.

Only libEGL.dll gives problems… even if it´s in the same /libs Folder… Cmake can´t get it by Name… why

#find_library(EGL_Lib NAMES libEGL EGL libegl)

is commented out…

MESA… is just Pathed to… not linked… so… it´s not in the Project.

I cloned the latest repo aof angle tonight… build it… and same Problems… So… my systems are all up-2-date.

glGetString and glGetError are routed from gl3.h… see:
UsingGL3

So you have to dig down why it fails.

Typically, just linking against .dll isn’t sufficient to use DLLs – you’ll have to place libGLESv2.dll, libEGL.dll and d3dcompiler_xx.dll beside of your .exe (it’s just same as SDL2.dll if you’re dynamically linking against SDL2). CMake itself do not take care of this.

1 Like

It’s not reliable way to check what-you-really-use inside .exe. Run .exe with some debugger and place a breakpoint and step into it instead.

1 Like

The dlls (+the SDL2 dlls) are beside the Game.exe

And… from the Debugger of CLion:


using gl3.h from angle GLES3

No GL Functions throws any Error…
Except

SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1");

That makes the SDL_CreateWindow being nullptr if not commented out…

Have you checked SDL_GetError content?

1 Like

Nice advice… Done SLD_GetError on every line… This is the result:

Error on set SDL_HINT_OPENGL_ES_DRIVER:
Error on set SDL_HINT_RENDER_DRIVER:
Error on set SDL_HINT_VIDEO_WIN_D3DCOMPILER:
Error on set SDL_GL_CONTEXT_EGL:
Error on set SDL_GL_CONTEXT_PROFILE_MASK:
Error on set SDL_GL_CONTEXT_MAJOR_VERSION:
We compiled against SDL version: 2.0.16
We are linking against SDL version: 2.0.16
Error on SDL_CreateWindow: Could not load EGL library
Critical Error<GL#0003> in: GameLoop::initSystems()      >> SDL Window could not be initialized!
Hit any Key to quit...

interesting is the “Could not load EGL library”

So… i´m sooo stupid… and need to thank you all Very Much… but especially @OKUMURA_Yuki !

I´m so intelligent… to forget to copy the libEGL.dll to the Game.exe…

Thought, when CmakeLists can´t link that lib… it can´t be used… but… i was wrong here…

Working now… Shame on me… Blessings to you :smiley: