c++openglx11sfmlirrlicht

Creating Irrlicht Device from X11 handle provided by SFML. Runtime X11/OpenGL error


I want to render using Irrlicht into a window created by SFML

sf::WindowHandle sf::Window::getSystemHandle() const returns of course sf::WindowHandle, which is a typedef. On Windows it's HWND__*, on linux it's unsigned long (which is probbaly X11 windows ID), on any other platform it's void*. In Irrlicht documentation, they say that I should pass HWND here on Windows, but there is nothing else about other systems.

Irrlicht allows to create it's main object irr::IrrlichtDevice with specialized method from external window. It takes a struct irr::SIrrlichtCreationParameters. One of the struct variables is void* WindowId

So what I'm trying to do is to create a window using SFML (and later use all SFML functions to poll events etc) and make Irrlicht render inside this window.

Core code:

sf::VideoMode desktop = sf::VideoMode::getDesktopMode();
sf::ContextSettings settings;
settings.antialiasingLevel = 8;
settings.depthBits = 16;
settings.stencilBits = 0;

//my own Logger class
logger.AddLog("Requesting following settings:\n");
logger.AddLog(settings);

window = std::make_shared<sf::RenderWindow>(
    sf::VideoMode(WINDOW_SIZE_X, WINDOW_SIZE_Y, desktop.bitsPerPixel),
    sf::String("Irrlicht + SFML test"),
    sf::Style::Default,
    settings);

logger.AddLog("Created SFML Window with following settings:\n");
logger.AddLog(window->getSettings());

irr::SIrrlichtCreationParameters params;
params.AntiAlias = 8;
params.Bits = 16;
params.DeviceType = irr::EIDT_BEST;
params.DriverType = irr::video::EDT_OPENGL;
params.Doublebuffer = true;
params.EventReceiver = nullptr;
params.Fullscreen = false;
params.HandleSRGB = false;
params.IgnoreInput = true;
params.Stencilbuffer = false;
params.UsePerformanceTimer = false;
params.Vsync = false;
params.WithAlphaChannel = false;
params.ZBufferBits = 24;
params.LoggingLevel = irr::ELL_DEBUG;
params.WindowId = GetWindowHandle(window->getSystemHandle()); // Described below

device.reset(irr::createDeviceEx(params)); // device is std::unique_ptr
if(device == nullptr)
    std::cout << "Can't create device!\n";

Description of my function SFML's getSystemHandle returns unsigned long on Linux, whic is X11 widnow ID, If I understood correctly. My function GetWindowHandle takes sf::WindowHandle and returns void* For Linux it does: return reinterpret_cast< void* >(handle); This seems to be correct way, any other way I tried yields X11 error BadWindowId

Program execution stops after device creation and does not reach if(device == nullptr) block. My program is terminated and returns 1.

Errors I get in console: (all output before "Irrlicht Engine" is done by my logger object)

[2017.01.28 13:15:51]
Starting Application
Requesting following settings:
OpenGL context        : 1.1
flags                 : 0
antialiasing level    : 8
bits of depth   buffer: 16
bits of stencil buffer: 0
Created SFML Window with following settings:
OpenGL context        : 4.5
flags                 : 0
antialiasing level    : 8
bits of depth   buffer: 24
bits of stencil buffer: 0
Irrlicht Engine version 1.8.4
Linux 4.4.0-59-generic #80-Ubuntu SMP Fri Jan 6 17:47:47 UTC 2017 x86_64
X Error of failed request:  BadAlloc (insufficient resources for operation)
  Major opcode of failed request:  154 (GLX)
  Minor opcode of failed request:  31 (X_GLXCreateWindow)
  Serial number of failed request:  26
  Current serial number in output stream:  27

What can cause such error?

Edit Tried with sf::Window. Doesn't work either. I get the same error. According to SFML documentation this class also creates it's own context. I will probably have to give up combining these 2 libraries and use SFML only for audio and only render with Irrlicht.


Solution

  • Easy: SFML already configured the window for and created a OpenGL context on it. Then you pass that window to Irrlicht, which tries (again) to configure the window for its purposes and fails, because it's been configured already. Technically creating additional OpenGL contexts is perfectly possible, but creating a GLX window as a child of another GLX window (GLX windows are specializations of regular X11 windows) leads to problems.

    The solution in your case would be to patch SFML not to do the "fancy" OpenGL window configuration and context creation, which also means that it returns the plain X11 window without the GLX window that's usually created inside it for OpenGL (long story why that's done, mostly related to direct rendering issues).

    That being said, embedding Irrlicht into a window provided by the host program is to support things like map editors or similar preview applications.