Opened 4 years ago

Closed 3 years ago

Last modified 3 years ago

#17425 closed defect (fixed)

wxWidgets 3.1 new wxGLCanvas ctor results "Couldn't create GL context"

Reported by: DerEl Owned by: Vadim Zeitlin <vadim@…>
Priority: normal Milestone:
Component: OpenGL Version: 3.1.0
Keywords: wxGLContext regression Cc: mmartin@…
Blocked By: Blocking:
Patch: no

Description

I built wxWidgets 3.1 from source on Linux (OpenSuSE Leap 42.1, Mesa 11.0.8, OpenGL version 2.1, Gallium 0.4 on ATI RC410 from X.Org R300 Project )

The problem I run into is that using the new 3.1 style wxGLCanvas ctor allways brings up a log dialog stating "Couldn't create GL context" even though everything is rendered fine and wxGLAttributes instance is just initialized with Default().EndList().

Using the "old" 3.0 style ctor from the same build with the same setup runs just fine even when used with attribut list like:
static const int glAttribList[] =
{

WX_GL_RGBA,
WX_GL_DOUBLEBUFFER,
WX_GL_DEPTH_SIZE, 16,
WX_GL_STENCIL_SIZE, 8,
WX_GL_SAMPLE_BUFFERS, 1,
WX_GL_SAMPLES, 4,
0, 0 end of list

};

looked at the source src/unix/glx11.cpp but couldn't find a possible reason.


Attachments (5)

wxGLTest.cpp download (7.4 KB) - added by DerEl 4 years ago.
wxGLTest.h download (2.2 KB) - added by DerEl 4 years ago.
gtk_glcanvas_ctor.patch download (1.5 KB) - added by DerEl 4 years ago.
wxGLContext_ctor_x11Direct20160316.patch download (1.8 KB) - added by mmarsan 4 years ago.
GLReworkOldHardware20160830.patch download (16.1 KB) - added by mmarsan 4 years ago.

Download all attachments as: .zip

Change History (25)

comment:1 Changed 4 years ago by vadz

  • Cc mmartin@… added
  • Keywords regression added

Can this be reproduced in the cube OpenGL sample? If you could please make a patch showing the problem in it, it would be helpful, TIA!

comment:2 follow-up: Changed 4 years ago by mmarsan

  • Status changed from new to infoneeded_new

Current wx 3.1 wxGLContext and friends docs are written focused on modern GPU drivers. The new attributes are the preferred way, according to OpenGL consortium comments.
But old GPU drivers know nothing about these modern style, nothing about OGL context attributes.

So, to ask for a OGL 2.1 context, depending of the GPU driver being old or new there are two ways:
a) For modern GPU:

wxGLContextAttrs ctxattrs;
ctxattrs.PlatformDefaults().CompatibilityProfile().OGLVersion(2, 1).EndList();

b) For old GPU:

wxGLContextAttrs ctxattrs;
ctxattrs.PlatformDefaults().EndList();

You can try a) and if yourwxGLContext::IsOK() returns false then delete the context, create a new one and try again with b)

The OGL context created depends on vendor implementation. But it should be at least the requested version, if available by the driver.

Finally, notice the difference between 'display attributes' and 'context attributes'. For old GPUs only 'display attributes' make sense.

Anyhow, if you show a debugger BT, or they way you use this context stuff, more data we have to find what's happening.

If a) or b) works for you please tell it here and close this ticket.

comment:3 in reply to: ↑ 2 Changed 4 years ago by oneeyeman

  • Status changed from infoneeded_new to new

Hi,
Replying to mmarsan:

Current wx 3.1 wxGLContext and friends docs are written focused on modern GPU drivers. The new attributes are the preferred way, according to OpenGL consortium comments.
But old GPU drivers know nothing about these modern style, nothing about OGL context attributes.

So, to ask for a OGL 2.1 context, depending of the GPU driver being old or new there are two ways:
a) For modern GPU:

wxGLContextAttrs ctxattrs;
ctxattrs.PlatformDefaults().CompatibilityProfile().OGLVersion(2, 1).EndList();

b) For old GPU:

wxGLContextAttrs ctxattrs;
ctxattrs.PlatformDefaults().EndList();

You can try a) and if yourwxGLContext::IsOK() returns false then delete the context, create a new one and try again with b)

The OGL context created depends on vendor implementation. But it should be at least the requested version, if available by the driver.

Finally, notice the difference between 'display attributes' and 'context attributes'. For old GPUs only 'display attributes' make sense.

Anyhow, if you show a debugger BT, or they way you use this context stuff, more data we have to find what's happening.

If a) or b) works for you please tell it here and close this ticket.

Can you do this inside wxGLContext constructor?
Then the code will work independently of the hardware being used...

comment:4 Changed 4 years ago by mmarsan

It isn't a matter of hardware independence. A higher OGL version offers new features that a coder may want to use. If those features are not available then the OGL code is different.
There are two main approaches: coding for an only low version or coding several versions and chose *at run time* the one to use.
That's why asking for an OGL version and looking at the effectively context version created is a normal practice. And that is the reason for wxGLContext::IsOK().

Perhaps we just need a note in the docs showing how to set an old OGL context.

Changed 4 years ago by DerEl

Changed 4 years ago by DerEl

comment:5 Changed 4 years ago by DerEl

I tried to recreate the behaviour with the cube example but the error didn't showed up there.

I put together a small programm showing the described behaviour.
wxGLTest.cpp and wxGLTest.h

There is a define at the begin of the cpp file:
#define MAKE_USE_OF_NEW_SYNTAX

If it's commented out the 3.0 implementation is used otherwise the 3.1 implementation is used.

The 3.1 implementation shows the "Couldn't create GL context" on startup eventhough everything is rendered fine. The 3.0 implementation starts without any errors or warnings.

The only main difference compared to the cube example is that I use wxGLCanvas directly whereas the cube example uses a derived class.

Still don't know what I'm doing wrong here.

comment:6 Changed 4 years ago by DerEl

@mmarsan:

I'm using only basic display attributs like RGBA() DoubleBuffer() etc. and not the "higher level" attributes like OGLVersion() etc.

The wxGLContext is created with NO attributes as I allready noticed that I couldn't create a valid context if doing so.

comment:7 Changed 4 years ago by mmarsan

The only difference between using a wxGLAttributes object vs a 'const int*' at wxGLCanvas ctor is that the later will create a default wxGLContextAttrs object, with PlatformDefaults() and EndList().

I deduce your GPU driver uses glXCreateContextAttribsARB for creating the context but it does not accept a NULL pointer to context attributes. But, despite of flaws, it does create a context.
This goes against OGL standards (see https://www.opengl.org/registry/specs/ARB/glx_create_context.txt search for using a NULL attrib_list). This is not rare, unfortunately there are plenty of not-standards implementations in OGL world.

You can confirm my suspicion by stepping through glx11.cpp wxGLContext ctor. Try againg using a wxGLContextAttrs object with PlatformDefaults() and EndList(). See the differences.
Also, please use IsOK() to see if the GPU driver returned a valid context or not.

comment:8 Changed 4 years ago by DerEl

I had to rebuild the framework with full debug support to be able to step through glx11.cpp.

I tested two scenarios:

First:

Using 3.1 style ctor for derived wxGLCanvas class with following display attributes

wxGLAttributes glAttributes;
glAttributes.Defaults().RGBA().DoubleBuffer().Depth(16).Stencil(8).SampleBuffers(1).Samplers(4).EndList();

Second:

Using 3.0 style ctor for derived wxGLCanvas class with following attribute list

const int glAttribList[] =
{

WX_GL_RGBA,
WX_GL_DOUBLEBUFFER,
WX_GL_DEPTH_SIZE, 16,
WX_GL_STENCIL_SIZE, 8,
WX_GL_SAMPLE_BUFFERS, 1,
WX_GL_SAMPLES, 4,
0, 0 end of list

};

In both scenarios the implementation of the ctor is IDENTICAL with respect to generation of the wxGLCanvas instance using:

wxGLContextAttrs glCtxAttrs;
glCtxAttrs.PlatformDefaults().EndList();
this->mGLCTX = new wxGLContext(this, NULL, &glCtxAttrs);

Both scenarios results with a valid context (that's why everything is rendered fine), BUT the first scenario (3.1) gives "Couldn't create GL context" because g_ctxErrorOccurred is TRUE at line 539 of glx11.cpp:

if ( g_ctxErrorOccurred || !m_glContext )

wxLogMessage(_("Couldn't create OpenGL context"));

else

m_isOk = true;

Subsequent call to IsOk() returns FALSE because of g_ctxErrorOccurred was TRUE eventhough we got a context.

In scenario two (3.0) g_ctxErrorOccurred stays FALSE all the time and therefor IsOk() returns TRUE.

As the ctor for wxGLContext is called with identical parameters resulting in different results the problem seems to be either in implementation of the wxGLCanvas ctors (3.1 vs 3.0) or the way wxGLAttributes is translated to the attribute list which is used in wxGLContext ctor.

Could you give me further hints as the problem seems not the creation of the wxGLContext itself but something happening before.

comment:9 Changed 4 years ago by mmarsan

Sorry, it's not clear to me. Are you using
!#C++this->mGLCTX = new wxGLContext(this, NULL, &glCtxAttrs);
in both scenarios? It seems you don't use it for '3.1 style' and that's the reason for the fail.
See with the debugger 'contextAttribs' at glx11.cpp changing depending of 3.1/3.0 styles.

g_ctxErrorOccurred == true means X11 found some error. It is likely due to not using a wxGLContextAttrs means using an empty context-attributes list (different from a display-attributes list), as I explained in previous comment7.

To set it clear:

  1. Passing a 'const int*' at wxGLCanvas ctor creates a default wxGLContextAttrs and uses (in unices with OGL implementations accepting glXCreateContextAttribsARB, wich are virtually all since 2009) it at wxGLContext ctor. Passing a 'wxGLAttributes' does *not*.
  2. For a broken OGL implementation, use your own wxGLContextAttrs object.
  3. For OGL ver < 3.0, use a) or b) as I wrote in comment2.

comment:10 Changed 4 years ago by DerEl

To clear it up:

this->mGLCTX = new wxGLContext(this, NULL, &glCtxAttrs);

is used in both scenarios to make sure that the conditions are as similar as possible on wxGLContext creation.
In both scenarios glXCreateContextAttribsARB function is used for the creation of the context.

I stepped again through the process of wxGLCanvas AND subsequent wxGLContext creation for both scenarios, examining every possible variable which could influence the observed behaviour.

I noticed that using
glAttributes.Defaults().RGBA().DoubleBuffer().Depth(16).Stencil(8).SampleBuffers(1).Samplers(4).EndList()
results in an attribute list containing duplicates. First I thought this could be the reason but changing it to
glAttributes.PlatformDefaults().RGBA().DoubleBuffer().Depth(16).Stencil(8).SampleBuffers(1).Samplers(4).EndList()
which results in the same attribute list as in the 3.0 scenario still shows the context creation error on startup.

To summarize it again:

In both scenarious wxGLCanvas is created with the exact same set of display attributes and wxGLContext with the same context attributes (namely PlatformDefaults().EndList()).
Still the 3.1 scenario results in context creation error whereas 3.0 scenario works flawlessly.

Therefore the behaviour is NOT caused by the wxGLContext creation itself, but before which have to be the implementation differences of wxGLCanvas between 3.0 style ctor vs. 3.1 style ctor.

Point (1) of your last comment gave me the hint I searched for. Using 3.0 style ctor with const *int attribList parses the attribute list to create an instance of wxGLAttributes AND touches m_GLCTXAttrs and subsequently calls the 3.1 style Create() function, whereas the 3.1 style ctor of wxGLCanvas leaves m_GLCTXAttrs unintialized before calling the Create function.

It looks to me as if m_GLCTX_Attrs have to be initialized to something meaningfull before the Create() function of wxGLCanvas is called, eventhough the subsequent creation of wxGLContext is called explicitly with a pointer to a wxGLContextAttrs instance (again: in BOTH scenarios).

To check this I patched gtk/glcanvas.cpp, adding
this->m_GLCTXAttrs.PlatformDefaults().EndList(); before
Create(parent, dispAttrs, id, pos, size, style, name, palette); in
3.1 style ctor, recompiled the library and run both scenarios again.

This time no error is popping up on startup.

This proofs to me that m_GLCTXAttrs have to be initialized before Create() of wxGLCanvas is called to avoid possible errors in subsequent wxGLContext creation, at least on my platform.

I did not found where m_GLCTXAttrs is used BEFORE wxGLContext creation,
but that's what I observe.

Unluckily I can't test this patch on hardware which gives me the opportunity to see if this also works for OpenGL versions higher than 2.1.

I added a patch for gtk/glcanvas.cpp; could someone please check if this conficts with other OpenGL versions

Changed 4 years ago by DerEl

comment:11 Changed 4 years ago by DerEl

IMO the patch shouldn't be harmfull at least as the user still have to request an instace of wxGLContext and therefore is able to specify more elaborated context attributes for more recent OpenGL implementations.

I still don't no where m_GLCTXAttrs member of the wxGLCanvas instance come into play, as it is not used during wxGLContext creation in both of my scenarios as I'm explicitly call wxGLContext ctor with a pointer to a wxGLContxtAttrs instance initialized with PlatformDefault().EndList(). Therefore the ctor takes these attributes and doesn't ask for the attributes stored in the wxGLCanvas instance.
That why I am so puzzled as for both scenarios the preconditions before entering wxGLCanvas ctor are exactly the same beside of the uninitialized m_GLCTXAttrs member in 3.1 style scenario, even I don't see where it is ever used at all.
The only suspicion I have is that on creation on wxGLCanvas creates a visual and binds the "draw" event. This is before the actual explicit wxGLContext creation. Could it be that the underlying implementation (GTK3) tries to realize the Canvas using m_GLCTXAttrs for a creation of a dummy GL context before the "real" wxGLContext is set via set current.

This would explain the behaviour when m_GLCTXAttrs is not initialized at all and the error is not caused by the wxGLContext ctor at all but is just an artefact of an earlier attemp to an unsuccesfull context creation and then reported on XSync( dpy, False ); in wxGLContext ctor

comment:12 Changed 4 years ago by pcor

  • Status changed from new to confirmed

The data members of wxGLContextAttrs are uninitialized. This particular problem seems to be because the uninitialized value of x11Direct just happens to be 0. Since nothing ever sets either x11Direct or renderTypeRGBA to false, there doesn't seem to be any point in having either one.

comment:13 Changed 4 years ago by mmarsan

First of all, thank you very much for your efforts.
I've tried you code and it runs smoothly in my machine, both styles.
Due to you have done such a deep debugging, it pointed me to follow x11Direct. Then I remembered I have already found a flaw, (search at wx-dev for 16910: OpenGL pyramid sample update feb-25) but with no patch.

I think I have the answer:
at glx11.cpp:489:
try replacing win->GetGLCTXAttrs().x11Direct with just x11Direct
The former is taken from m_GLCTXAttrs while the later uses the correct initialized (see the first lines at wxGLContext ctor) value.

comment:14 Changed 4 years ago by DerEl

Thank you, this solved it for me.

I commented out "my" patch and altered glx11.cpp line 489 as adviced to use x11Direct (local scope) instead of win->GetGLCTXAttrs().x11Direct and it works with no error messages popping up. So it's actually the temporary context causing the error reported on XSync().

On my machine I've got the context, so there was no assertion, but still there have to been some kind of error which was then reported later.

Thank you again for your patience ...

As I'm quite new here I really don't know how to proceed further whith respect to providing an adequate patch, or changing the status of the ticket.

Changed 4 years ago by mmarsan

comment:15 Changed 4 years ago by mmarsan

OK. Now I know it works, I've attached the patch with the x11Direct thing. From now on this value depends on user's code.
It also corrects another potential issue about glXyy names that may be in use by very old driver.
Vadim, forgive me about putting two things in the same patch, both things are so tiny fixes...

DerEl, you don't need to do anything else. You've done much more than usual compared to many others.
If a solution is found without any patch, then any user can close the ticket. In our case let some administrator (likely vadz) apply the patch an close the ticket.

comment:16 Changed 4 years ago by mmarsan

I'm attaching a patch that solves (at least where I could test it) problems with old hardware.
Main changes are:

  • Don't add wxGLAttributes::Defaults() when the attributes-list is NULL.
  • Add display default attributes used in wx versions before 3.1 when the attributes-list is NULL. These attributes are different for each platform.
  • Fix wxMSW PixelFormatDescriptor initialization.
  • Don't set color buffers when RGBA() is used.
  • Fix setting colour sizes in OS X and a few other fixes.
  • Make documentation more clear about these subjects.

IMHO, this patch should also solve ticket #17595

Changed 4 years ago by mmarsan

comment:17 Changed 3 years ago by kmccarty

Hi,

Wondering about the status of this bug? We have an OpenGL WX application for which our customers use the Linux (wxGTK) port by running it on a remote Linux box, but rendering it onto a local Windows machine via the "Exceed" X-server.

All was fine with WX 3.0.2. But upon upgrading to 3.1.0, we find that we must apply the two patches wxGLContext_ctor_x11Direct20160316.patch and GLReworkOldHardware20160830.patch to our local copy of WX in order for our application to continue to be able to run this way. (DerEl and mmarsan, thank you so much for your work on these patches!)

This use case is very important to our customers. So any news about whether these patches are going to be accepted as-is would be very welcome to us!

Thanks,

  • Kevin B. McCarty

comment:18 Changed 3 years ago by vadz

I can't meaningfully review these patches, so I'm just applying both of them as they seem to solve the problems encountered by many people, thanks for making them!

FWIW OpenGL still doesn't work for me using Cygwin X server in wxGTK, it fails with

libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
The program 'cube' received an X Window System error.
This probably reflects a bug in the program.
The error was 'GLXBadContext'.

This used to work before, but I don't think many people run OpenGL applications in this configuration anyhow, so it's probably not such a big deal.

I also still get assert failures when trying to open a new stereo window in the cube sample, under both Linux and MSW, which is not very user-friendly, but this doesn't seem to be fatal neither.

Thanks again for the patches, Manuel!

Last edited 3 years ago by vadz (previous) (diff)

comment:19 Changed 3 years ago by Vadim Zeitlin <vadim@…>

  • Owner set to Vadim Zeitlin <vadim@…>
  • Resolution set to fixed
  • Status changed from confirmed to closed

In b28dd88994ec144c2235721ef8e1133b3651e790/git-wxWidgets:

Improve new wxGLCanvas compatibility with old hardware and code

Combined patch with the following changes:

  • Don't add wxGLAttributes::Defaults() when the attributes-list is NULL.
  • Add display default attributes used in wx versions before 3.1 when the attributes-list is NULL. These attributes are different for each platform.
  • Fix wxMSW PixelFormatDescriptor initialization.
  • Don't set color buffers when RGBA() is used.
  • Fix setting colour sizes in OS X and a few other fixes.
  • Make documentation more clear about these subjects.

Closes #17425.

comment:20 Changed 3 years ago by mmarsan

The problem with Cygwin X server seems, again, something related to gl visual attributes. I don't have Cygwin, sorry, I can't test.

The issue with the cube sample can be shown by anybody who has NOT a stereo-capable card. It's due to creating an invalid gl context at cube.cpp:285 MyApp::GetContext() but accepting it anyhow.
I decided not to touch previous ogl samples, so I could do better testing. Now you've commited the patches (THX!) we can make a fix for cube sample.

Note: See TracTickets for help on using tickets.