I use BGFX framework for rendering in an application. I'm on Linux with an nvidia graphics card, and the BGFX build I use uses OpenGL as a backend (don't want to switch to Vulkan backend).
Everything worked fine, but one new feature requires me to use EGL. The first thing I do in the main is setting EGL to use OpenGL as a rendering API with:
if (not eglBindAPI(EGL_OPENGL_API) || (eglGetError() != EGL_SUCCESS))
//error handling
It works well.
Then I create an X11 window, I call eglGetDisplay, call eglInitialize, call eglChooseConfig, all of them returns without any error.
Then I call BGFX init, it runs well without any error.
At this point I have an initialized BGFX (using OpenGL backend), a current OpenGL context (created by BGFX):
std::cout << "GL Cont: " << glXGetCurrentContext() << std::endl; // Valid pointer
std::cout << "EGL Cont: " << eglGetCurrentContext() << std::endl; // 0x0
std::cout << "BGFX Renderer: " << bgfx::getRendererType() << std::endl; // 8 - OpenGL
Then I would like to execute the new EGL stuff related to the new feature on a different thread (I call eglBindAPI on the new thread as well):
EGLContext globalEglContext{};
{
static constexpr EGLint contextAttr[]{
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
};
globalEglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttr);
if (EGL_NO_CONTEXT == globalEglContext)
{ //error handling }
}
if (!eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, globalEglContext))
{
printf("Error on eglMakeCurrent (error: 0x%x)", eglGetError());
}
The context creation is fine, but the eglMakeCurrent call returns false, but the error code is 0x3000 (EGL_SUCCESS):
Error on eglMakeCurrent (error: 0x3000)
I cannot ignore the error as the next EGL operation fails, so it is an error indeed.
If I execute the very same context creation code on the main thread I get:
Error on eglMakeCurrent (error: 0x3002)
Checking 0x3002 (EGL_BAD_ACCESS) in the manual doesn't explain my case.
If I create & make my EGL context current on the main thread before initializing BGFX and I add the following X11 error handler:
XSetErrorHandler(+[](Display *display, XErrorEvent *error)
{
char buf[255];
XGetErrorText(display, error->error_code, buf, 255);
printf("X11 error: %s", buf);
return 1;
});
Then the context creation and making it current works well, but during BGFX init I get the following error message:
X11 error: GLXBadDrawableX11 error: GLXBadDrawableX11
I have two questions:
Is it possible that EGL and OpenGL contexts cannot be used in the same time? (On a thread I would have a current OpenGL context while on another thread an EGL context)
If it is not possible to use OpenGL and EGL contexts in the same time not even on different threads then how could I use EGL features while I would like to continue using OpenGL as a rendering backend in the same time?
UPDATE:
I created a test app that creates and makes current a GLX context, then creates and tries to make current an EGL context and it fails.
Does it mean that EGL and OpenGL cannot be used in the same time?
The full source code (main.cpp):
#include <iostream>
#include <assert.h>
#include <thread>
#include <chrono>
#include <future>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
int main()
{
if (not eglBindAPI(EGL_OPENGL_API) || (eglGetError() != EGL_SUCCESS))
{
printf("Could not bind EGL ES API (error: 0x%0x)\n", eglGetError());
return -1;
}
XSetErrorHandler(+[](Display *display, XErrorEvent *error)
{
char buf[255];
XGetErrorText(display, error->error_code, buf, 255);
printf("X11 error: %s\n", buf);
return 1;
});
//
// WINDOW
//
uint32_t flags = SDL_WINDOW_RESIZABLE;
const auto sdlWindow = SDL_CreateWindow("win", 0, 0, 640, 480, flags);
SDL_ShowWindow(sdlWindow);
SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
if (!SDL_GetWindowWMInfo(sdlWindow, &wmi))
{
return -1;
}
auto display = wmi.info.x11.display;
//
// EGL INIT
//
void *eglConfig{};
void *eglDisplay{};
void *eglSurface{};
// EGL init
{
// Get EGL display
eglDisplay = eglGetDisplay((EGLNativeDisplayType)display);
if (eglDisplay == EGL_NO_DISPLAY)
{
printf("Could not create EGLDisplay (error: 0x%0x)\n", eglGetError());
return -1;
}
// Init EGL display
{
EGLint major;
EGLint minor;
if (!eglInitialize(eglDisplay, &major, &minor))
{
printf("Failed initializing EGL (error: 0x%0x)\n", eglGetError());
return -1;
}
else
{
printf("EGL initialized (Version: %d.%d)\n", major, minor);
}
}
// Choose EGL config
{
static constexpr EGLint cfgAttr[]{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_DEPTH_SIZE, 1,
EGL_NONE
};
EGLint numConfigs{0};
if (!eglChooseConfig(eglDisplay, cfgAttr, &eglConfig, 1, &numConfigs))
{
printf("Failed on eglChooseConfig (error: 0x%0x)\n", eglGetError());
return false;
}
}
// Create EGL surface
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, wmi.info.x11.window, nullptr);
if(eglSurface == EGL_NO_SURFACE)
{
printf("Could not create EGLSurface (error: 0x%0x)\n", eglGetError());
return -1;
}
}
//
// OpenGL context
//
const auto screen = DefaultScreenOfDisplay(display);
const auto screenId = DefaultScreen(display);
static GLint glxAttribs[] = {
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_SAMPLE_BUFFERS, 0,
GLX_SAMPLES, 0,
None
};
XVisualInfo* visual = glXChooseVisual(display, screenId, glxAttribs);
if (visual == 0)
{
printf("Could not create correct visual window.\n");
return -1;
}
GLXContext context = glXCreateContext(display, visual, NULL, GL_TRUE);
if( !glXMakeContextCurrent(display, None, None, context))
{
printf("Could not make context current.\n");
return -1;
}
std::cout << "GL Cont: " << glXGetCurrentContext() << std::endl;
std::cout << "EGL Cont: " << eglGetCurrentContext() << std::endl;
/*
// Uncomment this and EGL context creation works
if( !glXMakeContextCurrent(display, None, None, NULL))
{
printf("Could not make context current.\n");
return -1;
}
std::cout << "GL Cont: " << glXGetCurrentContext() << std::endl;
std::cout << "EGL Cont: " << eglGetCurrentContext() << std::endl;
*/
//
// EGL CONTEXT
//
auto launchPolicy = std::launch::deferred; // change it to std::launch::async to create EGL context on a thread
auto res = std::async(launchPolicy, [&](){
void *globalEglContext;
{
static constexpr EGLint contextAttr[]{
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
};
globalEglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttr);
if (EGL_NO_CONTEXT == globalEglContext)
{
printf("Error creating EGL context (error: 0x%x)\n", eglGetError());
exit(-2);
}
}
// fails with 0x3000 (EGL_SUCCESS) on a different thread.
// fails with 0x3002 (EGL_BAD_ACCESS) on the main thread.
if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, globalEglContext))
{
printf("Error on eglMakeCurrent (error: 0x%x)\n", eglGetError());
exit(-3);
}
return 0;
});
res.wait();
std::cout << "GL Cont: " << glXGetCurrentContext() << std::endl;
std::cout << "EGL Cont: " << eglGetCurrentContext() << std::endl;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(EGLTest LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(OpenGL REQUIRED COMPONENTS EGL)
find_package(PkgConfig REQUIRED)
pkg_check_modules(X11 REQUIRED x11)
pkg_check_modules(SDL2 REQUIRED sdl2)
add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(
${PROJECT_NAME}
SYSTEM
PUBLIC ${OPENGL_EGL_INCLUDE_DIRS}
PUBLIC ${SDL2_INCLUDE_DIRS}
)
target_link_libraries(
${PROJECT_NAME}
OpenGL::EGL
${SDL2_LIBRARIES}
)
UPDATE 2:
My config:
Kubuntu 22.04 LTS 5.15.0-52-generic
Operating System: Ubuntu 22.04
KDE Plasma Version: 5.24.6
KDE Frameworks Version: 5.98.0
Qt Version: 5.15.3
Kernel Version: 5.15.0-52-generic (64-bit)
Graphics Platform: X11
Processors: 16 × 11th Gen Intel® Core™ i7-11800H # 2.30GHz
NVIDIA-SMI 470.141.03 Driver Version: 470.141.03 CUDA Version: 11.4
OpenGL vendor string: NVIDIA Corporation
OpenGL renderer string: NVIDIA GeForce RTX 3050 Ti Laptop GPU/PCIe/SSE2
OpenGL core profile version string: 4.6.0 NVIDIA 470.141.03
OpenGL core profile shading language version string: 4.60 NVIDIA
OpenGL ES profile version string: OpenGL ES 3.2 NVIDIA 470.141.03
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
UPDATE 3:
adam#pc:~/git/bgfx_test/build$ ldd BgfxTest | grep GL
libEGL.so.1 => /lib/x86_64-linux-gnu/libEGL.so.1 (0x00007f32b95dd000)
libGLX.so.0 => /lib/x86_64-linux-gnu/libGLX.so.0 (0x00007f32b95a9000)
libGLdispatch.so.0 => /lib/x86_64-linux-gnu/libGLdispatch.so.0 (0x00007f32b8d9d000)
I am trying to start using SDL2 (with CLion as my IDE), but I'm running into errors. I'm on Pop!_OS 19.10 (based on ubuntu)
Here are the relevant project files:
CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(sdlpractice)
set(CMAKE_CXX_STANDARD 20)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
add_executable(sdlpractice main.cpp)
target_link_libraries(sdlpractice ${SDL2_LIBRARIES})
Main.cpp
#include "SDL2/SDL.h"
#include "stdio.h"
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main(int argc, char* args[]) {
// The window we will be rendering to
SDL_Window * ptrWindow = NULL;
// The surface contained by the window
SDL_Surface * ptrScreenSurface = NULL;
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
} else {
// Create window
ptrWindow = SDL_CreateWindow("SDL Practice",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (ptrWindow == nullptr) {
printf("Window creation failed: %s\n", SDL_GetError());
}
// Get window surface
ptrScreenSurface = SDL_GetWindowSurface(ptrWindow);
// Fill the surface white
SDL_FillRect(ptrScreenSurface, NULL, SDL_MapRGB(ptrScreenSurface->format, 0xFF, 0xFF, 0xFF));
// Update the surface
SDL_UpdateWindowSurface(ptrWindow);
// Wait 2 seconds
SDL_Delay(2000);
// Destroy window, quit SDL subsystems
SDL_DestroyWindow(ptrWindow);
SDL_Quit();
return 0;
}
}
I get the following error:
SDL could not initialize! SDL_Error: No available video device
I have tried setting DISPLAY=:0.0 in CLion's run configurations. Same error results. Futhermore, I ran
echo $DISPLAY
:1
and tried using :1 as well, same error persists.
Removing /usr/local/bin/sdl2-config,/usr/local/include/SDL2 and /usr/local/lib/libSDL2* (as suggested by Botje) solved the problem due to the self-built version of SDL2 missing the required video headers.
I am attempting to set up SDL2 for creating a C++ game for windows. When I run the below make file with just a single source file, I get no errors, and the program can run. When I attempt to run the make file with multiple source files, the compilation goes smoothly, but when I attempt to run the program, i get the error seen in the title. It appears to only happen when I attempt to create an instance of a class in the second source file, and try to access either members or instance functions.
I have tried redownloading and setting up my environment, updating mingw (didnt hurt to try) and triple checking my code. I have included the makefile, as well as the source files I am using. Thank you for any help.
EDIT: It seems that the delete call in the main function causes this error... Not sure if that is a coincidence or if the cause does lie somewhere there...
#OBJS specifies which files to compile as part of the project
OBJS = src/*.cpp src/*.hpp
#CC specifies which compiler we're using
CC = g++
#INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS = -Iinclude/SDL2
#LIBRARY_PATHS specifies the additional library paths we'll need
LIBRARY_PATHS = -Llib
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
# -Wl,-subsystem,windows gets rid of the console window
COMPILER_FLAGS =
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lSDL2main -lSDL2
#OBJ_NAME specifies the name of our exectuable
OBJ_NAME = demoGame
#This is the target that compiles our executable
all : $(OBJS)
$(CC) $(OBJS) $(INCLUDE_PATHS) $(LIBRARY_PATHS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
#include <SDL.h>
#include <stdio.h>
#include "grid.hpp"
#include <iostream>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int main( int argc, char* args[] )
{
//The window we'll be rendering to
SDL_Window* window = NULL;
//The surface contained by the window
SDL_Surface* screenSurface = NULL;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
}
else
{
//Create window
window = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( window == NULL )
{
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
}
else
{
//Get window surface
screenSurface = SDL_GetWindowSurface( window );
//Fill the surface white
SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF ) );
//Update the surface
SDL_UpdateWindowSurface( window );
//Wait two seconds
SDL_Delay( 2000 );
}
}
Grid* grid = new Grid(1, 2);
// These two lines seem to cause an issue.
std::cout << grid->getRows() << std::endl;
delete grid;
//Destroy window
SDL_DestroyWindow( window );
//Quit SDL subsystems
SDL_Quit();
return 0;
}
class Grid {
public:
Grid(int rows, int columns) {
this->rows = rows;
this->columns = columns;
}
int getRows() {
return this->rows;
}
private:
int rows;
int columns;
};
SDL just pisses me off, please help.
I'm trying just to show a window, this is the code :
#include <iostream>
#define SDL_MAIN_HANDLED
#include "SDL.h"
int main()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *window = SDL_CreateWindow("Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 600, 480, SDL_WINDOW_SHOWN);
if (window == NULL)
return 1;
SDL_Event event;
bool running = true;
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
}
}
}
SDL_Quit();
std::cout << "Hello :)" << std::endl;
return 0;
}
Now, the issue is that it says that the program now responding and I have a "loading" icon for the mouse. Second issue is that I cannot use SDL_INIT_EVERYTHING for some reason, it just gets stuck and nothing outputs when I try to output after init.
I tried multiple sdl files x86 , x64.
I have windows 10 64bit OS.
I really start to lose my sanity here , please help.
EDIT :
the window works perfectly fine with SDL_INIT_EVERYTHING but it takes the computer to load everything for 1 minute and 50 seconds. which is a lot of time.
But when I only init SDL_INIT_VIDEO , it's not responding.
Any solution ?
Okay, so I have downloaded an older version 2.0.5 instead of the new "stable" version and seems like it works. I guess the new version just have bugs that needs to be fixed.
I have been trying to make a PNG image appear on-screen to my SDL window. I am using the Eclipse CDT. SDL.h and SDL_image.h both seem to have been correctly linked, in that the functions pop up with colour on the compiler. When I run my code, however, literally nothing happens. There are no errors in the compiler, no comments, nothing. The window doesn't appear. I would really appreciate if anyone could help me out on the matter.
Also, SDL has worked previously on my computer before (without using SDL_image) - in which I ran a particle simulation that worked perfectly fine.
My code:
#include <iostream>
#include "SDL.h"
#include "SDL_image.h"
using namespace std;
SDL_Window *m_window; //Window upon which the game will be displayed.
SDL_Renderer *m_renderer; //Renderer used to draw the objects on the window.
SDL_Texture *playerTex;
int SCREEN_WIDTH = 600;
int SCREEN_HEIGHT = 600;
int main(int argc, char* args[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
cout << "Video init failed" << endl;
return 1;
}
//Creates the actual SDL-window and stores it in the m_window variable.
m_window = SDL_CreateWindow("Marko Beocanin SDD Project",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_FULLSCREEN);
//Error-checking method that determines if SDL could not create a window - returns false if unsuccessful.
if (m_window == NULL) {
cout << "Window Creation failed" << endl;
SDL_Quit();
IMG_Quit();
return 2;
}
//Creates an SDL-Renderer: a tool used to actually draw objects on the Window
m_renderer = SDL_CreateRenderer(m_window, -1, 0);
//Error-checking method that determines if SDL could not create a renderer - returns false if unsuccessful.
if (m_renderer == NULL) {
cout << "Renderer creation failed." << endl;
SDL_DestroyWindow(m_window);
SDL_Quit();
IMG_Quit();
return 3;
}
SDL_Surface *tmpSurface = IMG_Load("img.png");
playerTex = SDL_CreateTextureFromSurface(m_renderer, tmpSurface);
SDL_FreeSurface(tmpSurface);
SDL_RenderClear(m_renderer);
SDL_RenderCopy(m_renderer, playerTex, NULL, NULL);
SDL_RenderPresent(m_renderer);
SDL_Delay(2000);
SDL_DestroyWindow(m_window);
SDL_Quit();
IMG_Quit();
return 0;
}
The problem I had was a result of me using the wrong SDL_image library - I was using x64 instead of x86, which meant that it didn't throw an error per se, just didn't work properly!