How to distinct window creation from driver initialization

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

How to distinct window creation from driver initialization

Post by teto »

Hi,

When trying to load ogl driver as plugin, I modified the source so that the window creation got separated from gl context initialization. As hybrid showed interest in this peculiar feature, I intend to do sthg cleaner for windows/linux/ogl/directX (would eventually need help for osx). I intend to propose a first patch without any change for the user.

What are the advantages of such a feature ?
-you could create the device first, ask for avaible video modes and only then creates your window.
-in a future, irrlicht could handle several window
- I read that having several contexts could help for threading ? http://irrlicht.sourceforge.net/forum/v ... 8&start=60 I have no idea about that
-in the future makes it easier to add a new driver.

I have a few questions about the best way to do things. Right now I have a IRenderWindow (to which I have deported windowing functions such as setWindowCaption, isMinimized() etc...) from which inherits CRenderWindowWin32/CRenderWindowLinux etc...

Here are the two possibilities I have in mind (maybe you have another):
-each driver could specialize inherits IRenderWindow . For example we could have COpenGLRenderWindowWin32() inheriting from CRenderWindowWin32
-the other solution would be to add a IVideoContext to inherit from COpenGLVideoContext and then in Device, you would have a core::map <window,context>.

I lack yet (I hope I will have soon) a vision of how intertwined windows and contexts are. For example could you switch contexts within a same window ? seems ok with opengl, but harder with directX ?
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: How to distinct window creation from driver initializati

Post by REDDemon »

that is nice. It makes Irrlicht more SFML-like. In opengl is possible and easy. I don't know with DX maybe there will be problems.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

Hi to give some news.

Just to give some update about my progress. I've madea patch against rev4126 (on windows "svn diff > mypatch" ) to show it's not all talk. Nevertheless I wouldn't recommand to apply it since it's WIP:
-it will break software driver on linux. ogl and burning's ok
-breaks d3d8 on windows (started modifications on those 2 drivers without finishing). d3d9,ogl, burning and software ok
-not thoroughly tested (only with example 1)
-currently breaks the use of SExposedVideoData in beginScene. Could be fixed.


I just wanted to explain a bit how this first version -which does not change the external API- differs from current irrlicht:
-Creation of a class IRenderWindow with specializations ( CRenderWindowLinux & CRenderWindowWin32) to which I've moved all window-specific functions such as
minimizeWindow(),maximizeWindow() etc... To keep the API intact, IrrlichtDevice keeps those functions but redirects the call towards the current IRenderWindow, for example.
void IrrlichtDevie::maximizeWindow() { getActiveWindow()->maximizeWindow() }
-the aim is to dissociate window creation from IrrlichtDevice initialization so that one can create a device, asks the device for available video modes and then create a window. For that purpose I've added a function: IRenderWindow* IrrlichtDevice::createWindow(SRenderWindowConfig& config). Still with that idea of not breaking the API in mind, SRenderWindowConfig is generated from SIrrlichtCreationParameters.
-removed all driver-related code from different devices (CirrDeviceStub/CIrrDeviceWin32/CIrrDeviceLinux). The idea behind that is that you shouldn't modify a device to add a custom driver. As we have dissociated window creation from device creation, we could possibly have one device handle several windows (not implemented yet since it would require API changes). But with this idea in mind, I thought we could have a driver creating several contexts. That's why I've added a function IVideoContext* IVideoDriver::createContext(SVideoContextConfig& config, IRenderWindow*).
SVideoContextConfig is generated from SIrrlichtCreationParameters. Basically this new class "IVideoContext" is the equivalent of SExposedVideoData. There are specializations like COpenGLContextWin32,COpenGLContextLinux,CD3D8Context etc... which are meant to replace SExposedVideoData in beginScene (well it depends on the API you want to draw to multiple windows, is the window responsible for its own drawing calls or not etc...).

I happen to have a lot of free time right now and it's likely to last for a few months. Before further commiting myself into this, I wanted to know if there was interest (for irr 1.9 or 2.0 for example) and if that's the case, if a mac developer would be interested to join me to have a more comprehensive patch. To sum up, my current modifications aim at separating window creation from device creation and/or from driver/videocontext creation. Without any external API changes, these modifications *just* makes creation of drivers easier.

But once those modifications are done, it's very little work to add new features:
-handling of several windows (wich might use different drivers)
-I've never tried but I read one could use several contexts, display one while the other loads meshes and than contexts could share these meshes.
-could add a function IrrlichtDevice::addAvailableDriver( driverId, (IVideoDriver* (*)(IrrlichtDevice*) driverCreationFunc) which would add to a core::map<> a pointer to a function that , if called, would initialize a video driver.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: How to distinct window creation from driver initializati

Post by Nadro »

I didn't look a code in Your patch, but after Your description I think that this will be a good move for our engine. Currently I'm very busy (I'm porting a game to iOS and Android and next on my list is initial support for OGL3 driver) but when I will find some free time I'll help You with a support for MacOSX.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: How to distinct window creation from driver initializati

Post by hybrid »

Yes, this would be very appreciated for Irrlicht 1.9 already. The redirection of methods is a good idea, as we could even if we start to dislike this duplication deprecate these functions later on. For now it's better to avoid user code changes as much as possible. Since this change will be merged only to a later major revision you are not restricted to non-API changes only, though. So if you feel that it would be better to change some existing things, or add new public structures to avoid complicated method calls, just do so. So far, all your descriptions look very good.
One thing I always wanted to add based on such a separation is a mode for off-screen rendering without any window creation. At least OpenGL supports FBOs without windows and pbuffers, which would be very valuable to support. Problem is, that these things are kind of windows for themselves, but not exactly.
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

nadro > I am glad you volunteer and that I still get time to improve things.

As for offscreen rendering (http://www.mesa3d.org/brianp/sig97/offscrn.htm), we could create a class IRenderTarget to which we would attach a context as I now do with my IRenderWindows. IRenderTarget would inherit from IRenderTarget. We could add overloads to IVideoDriver::setRenderTarget(IRenderTarget*) though that would come later.

I wanted to make another suggestion. I've noticed texture creation is well separated from software image creation. I was wondering if - for the sake of making driver creation easier - it wouldn't be clearer to move image loading to a ISoftwareImageManager class and then pass that instance to the driver. it would leave "createDeviceDependantDriver" and *texture* creations in IVideoDriver.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: How to distinct window creation from driver initializati

Post by hybrid »

Image creation is part of CNullDriver, which is a base class to merely all drivers. Thus, creating other drivers is not that much of a problem besides putting the driver into the engine instead of adding them externally.
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

hi,

I've had some problems since I have introduced and after spending quite some time without finding its reason, I restarted from scratch (yeah I should have used some kinfd of vcs) focusing on ogl/windows compared to the previous patch (which won't work, tried to apply it, I forgot files etc...). I will then apply them on linux.

-Right now, I can register the available drivers through a function (so I might easily add a driver at runtime)
IrrlichtDevice::registerDriver(driverId, pointerTowardsIVideoDriverCreationFunction ).
-IrrlichtDevice is able to create several window and draw the ogl context, to one of them (if same pixel format). So the window (HWND) can be separated from the HGLRC. IrrlichtDEvice::run() returns false only when all windows closed
-As the purpose of my modifications is to allow for any driver type, SExposedVideoData which corresponds to a finite set of driver is no more of utility so I've removed it and replaced by a similar system (anyway you see it, you have to cast at some point to match irrlicht coding rules). Instead you use IVideoDriver::changeRenderContext( IVideoContext, IRenderWindow*) or IVideoDriver::changeRenderContext( IVideoContext, void*) to use your own parameters (will be specific to each driver implementation, HDC for OGL driver for instance)

Code: Select all

 
virtual bool IVideoDriver::changeRenderContext(IVideoContext*, IRenderWindow* ) ;
        virtual bool IVideoDriver::changeRenderContext(IVideoContext*, void* data) ;  // data casted to a HDC on windows
 
You can also create a IRenderWindow from your externally created window with:

Code: Select all

 
        virtual video::IRenderWindow* createWindow(const video::SRenderWindowConfig&,void *data) ;  //! creates from an existing one, data casted to HWND on windows
        virtual video::IRenderWindow* createWindow(const video::SRenderWindowConfig&) ;  //! creates window from scratch
 

Here is how the createDevice function looks like.

Code: Select all

 
        extern "C" IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx(const SIrrlichtCreationParameters& params)
        {
 
                IrrlichtDevice* dev = 0;
                if (params.DeviceType == EIDT_WIN32 || (!dev && params.DeviceType == EIDT_BEST))
                        dev = new CIrrDeviceWin32(params);
 
 
 
        // to get retrocompability, we create configs from SIrrlichtCreationParameters
        video::SRenderWindowConfig windowConfig = params.generateWindowConfig() ;
        video::SVideoContextConfig contextConfig = params.generateContextConfig();
 
        //!
        video::IRenderWindow* window = dev->createWindow(windowConfig);
 
        if(! window )
        {
            os::Printer::log("Could not create window", ELL_ERROR);
            return 0;
        }
 
        // create cursor control
        dev->setActiveWindow( window );
 
 
        video::IVideoDriver* driver = dev->getVideoDriver() ;
                if (  driver)
        {
            video::IVideoContext* ctx = driver->createContext( contextConfig, window );
 
            if(!driver->changeRenderContext(ctx,window))
            {
                os::Printer::log("Could not change render context",ELL_ERROR);
                // TODO should clean things
                return 0;
            }
 
            dev->createGUIAndScene();
 
        }
        else if(params.DriverType != video::EDT_NULL)
                {
 
                    // TODO shouldn't be necessary in the future This way of doing should be changed ?
                        dev->closeDevice(); // destroy window
                        dev->run(); // consume quit message
                        dev->drop();
                        dev = 0;
 
                }
//
//              if (dev && !dev->getVideoDriver() && params.DriverType != video::EDT_NULL)
//              {
//                      dev->closeDevice(); // destroy window
//                      dev->run(); // consume quit message
//                      dev->drop();
//                      dev = 0;
//              }
 
                return dev;
        }
 

As what I aim at, ideally, is for a device to be able to run several windows with different video contexts (not necessarely from the same driver). I find fun to be able to load one scene on a driver, and display the exact same scene in another window with a different driver, or even just resize window and irrlicht would be able to transfer data (in fact reload in software mode) from one context to another.

I had to change some things into the textures scheme for example. A texture belongs to an opengl context and not to the video driver which might create several contexts. Right now it really feels like "one driver, one context" (in the software driver for example, triangle renderers are coupled with the depthbuffer. It shouldn't in case we have contexts of different sizes). For instance:

Code: Select all

 
bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
                                        bool clearZBuffer, SColor color)
{
        // check for right driver type
 
//      if (texture && texture->getDriverType() != EDT_OPENGL)  // old version
        if (texture && texture->getContext() != CurrentContext) // new version CurrentContext is a context created by the driver.
        {
                os::Printer::log("Fatal Error: Tried to set a texture not owned by current context.", ELL_ERROR);
                return false;
        }
 
Keeping this idea in mind, we should be able to decorrelate gui structure from driver. For example to be able to draw the same gui into two separate windows, we could pass the driver IGuiEnvironment::drawAll( driver ) instead of passing the driver during the construction of the gui env (which is only used in drawAll().

All this to give you a better understanding.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

ok I got it working (2 windows with each one its context) on windows & linux for all drivers (except d3d8 which I don't intend to do until really needed). This is an example of 2 windows created from 1 device. In each window is displayed the same scene manager but in a different ogl context:
http://downloads.tuxfamily.org/bluecosm ... Window.PNG
It shows why texture management should be moved from CNullDriver to driver specific contexts (IOpenGLContext in my case) and potential API problems with ISceneManager (linked to a driver, not a context etc...).

As for moving software image mgmt out of CNullDriver (a precedent point I made), from the moment you don't need to choose a driver when creating an irrlicht device, that you could use several drivers or none, I think it's only logical to create a IImageManager on its own and then pass it to drivers. ( then you could use irrlicht as an image converter XD ! What it's not irrlicht objective :p ?)


I don't send code since you are working on 1.8 release anyway :p I will tester further the system and try to display a same context in several windows.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

So finally here is the code for a proof of concept: http://downloads.tuxfamily.org/bluecosm ... indow2.zip

I don't send this as a patch as there are so many changes, files, examples added it would make little sense (+ being complicated). The code is not something you could apply out of the blue but a way to get some feedback to improve it and shows it works. Which means there are still parts of old code commented, I do not grab/drop correctly things as API might change etc... I do not provide binary as well since there is nothing fancy to show.

To try this (tested on windows & linux) and for all drivers except dx8 which I didn't change at all), you must use the codeblocks project (only one updated with new files. Be wary of target filenames, I've done a few modifications).

Among the broken things:
-mouse handling. If I were to touch that, I wouldn't resist to change that (the whole thing with bool UseReferenceRectangle complicates code, I think it would be best to have overloaded functions taking into account a rectangle or not than check in functions if we "UseReferenceRectangle" or not)
-stencilbuffer in dx9 (not tested)
-crash on linux when calling resize function iirc. fixable.
There might be others I didn't notice.

In the end I went a bit over my first objectives since I got bored without an internet access. That's why I created an IImageManager, added the possibility to register drivers (I added an example which loads opengl driver from dll, others are not tested. For that purpose I used a dirty hack = exported 2 more classes into irrlicht.dll, could be cleaned later), changed SIrrCreationParameters::DriverType from an enum to a string. Indeed we see many drivers coming on the forum (opengl es 1/2,dx10/11,ogl 3 etc...) so I didn't want the driver choice to be dependant from an engine (by definition limited) enum.

I've added a "createDeviceLite" function which basically does "new CPlatformDevice" and lets you handle all the rest. To browse through the code, just look at the last added (messy) examples, createDeviceEx, CIrrDeviceXXX::createWindow, CIrrDeviceXXX::getAvailableDrivers, CIrrDeviceXXX::registerDriver, CXXXDriver::createContext, CXXXDriver::changeRenderContext.

I use createContext(void* ) to create an irrlicht context from an existing one (void* could be casted into a GLXContext for example etc...) because void* lets maxium freedom to add new drivers.

On the contrary I use createWindow(void* ) to create an irrlicht window (CRenderWindowXXX) from an existing one (void* could be casted into HWND on Windows or Window on linux) but maybe using an union here would be best or even defining a different type according to platform.
Pseudocode to get an idea of what I mean:
#ifdef _IRR_WINDOWS
typedef WINDOW_TYPE HWND;
#endif
#ifdef _IRR_LINUX
typedef WINDOW_TYPE Window;
#endif

createWindow( WINDOW_TYPE* )
Let me know if you have any question or problem compiling it.


Nb: I often get 503 errors on the forum, does anyone else experience that ?
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

Now that I have a (my first) Mac, I will be able to add MacOS support =) I will then update the archive already working on windows/linux
(I may port this as well http://irrlicht.sourceforge.net/forum/v ... =2&t=44712)
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: How to distinct window creation from driver initializati

Post by REDDemon »

to use same scene manager in 2 contexts are you re-loading everything needed or are you sharing textures and vbos between differnt contexts? seem interesting anyway
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: How to distinct window creation from driver initializati

Post by teto »

REDDemon wrote:to use same scene manager in 2 contexts are you re-loading everything needed or are you sharing textures and vbos between differnt contexts? seem interesting anyway
this is just sthg that could be made easily possible by my improvement (like you say, by reloading for instance) but not something I do. I have yet to find an interesting usecase xD One possible use case would be to display the same scene with different drivers but it's really peculiar and likely not worth the effort. What I see as more interesting is that you could reload the scenemanager with another driver and as such change driver without the need to close/relaunch game.

But the main goal of my work is to add more flexibility with multiwindowing and ease of loading (external) drivers.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
Post Reply