AMD Catalyst 11.9 crashes with wglCreateContext

Having just upgraded my catalyst drivers from 11.1 to 11.9 I have noticed that non of my OpenGL development projects work.

The problem seems to be wglCreateContent because when I run my projects through a debugger, this is the function call which produces an exception.

Does anyone else have this issue? Is there a workaround?

As I understand it, you have to first create a 2.x glContext in order to establish which version of OpenGl the h/w supports. Then you are able to call the newer wglCreateContextAttributes.

here’s the pertinent windows code:


  h_RC := wglCreateContext(h_DC);

  if (h_RC = 0) then
  begin
    glKillWnd;
    MessageBox(0, 'Unable to create a legacy OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Makes the specified OpenGL rendering context the calling thread's current rendering context
  if (not wglMakeCurrent(h_DC, h_RC)) then
  begin
    glKillWnd;
    MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  //Now have Open GL context. Initilialise all the GL functions.
  extgl_Initialize;


  // modify current context - add a OpenGL 3.x rendering context
  if supportedExtensions.WGL[WGL_ARB_create_context] then
  begin
   oldh_RC := h_RC;
   if supportedExtensions.OpenGL.Major < 3 then h_RC := wglCreateContextAttribsARB(h_DC,0,@GLattribs30)
   else begin
       //try and create a context using the new API using the highest available GL version.
       //OpenGL 3.1 does not support the extended profile mask settings...
       if (supportedExtensions.OpenGL.Major = 3) AND (supportedExtensions.OpenGL.Minor = 1) then h_RC := wglCreateContextAttribsARB(h_DC,0,@GLattribs31)
       else begin
           if NOT SupportedExtensions.wgl[WGL_ARB_create_context_profile] then
           begin
               setlength (ContextArrtibs, 7);
               ContextArrtibs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB; ContextArrtibs[1] := supportedExtensions.OpenGL.Major;
               ContextArrtibs[2] := WGL_CONTEXT_MINOR_VERSION_ARB; ContextArrtibs[3] := supportedExtensions.OpenGL.minor;
               ContextArrtibs[4] := WGL_CONTEXT_FLAGS_ARB; ContextArrtibs[5] := 0;
               ContextArrtibs[6] := 0;  //terminator
           end else
           begin
               setlength (ContextArrtibs, 9);
               ContextArrtibs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB; ContextArrtibs[1] := supportedExtensions.OpenGL.Major;
               ContextArrtibs[2] := WGL_CONTEXT_MINOR_VERSION_ARB; ContextArrtibs[3] := supportedExtensions.OpenGL.minor;
               ContextArrtibs[4] := WGL_CONTEXT_FLAGS_ARB; ContextArrtibs[5] := 0;
               ContextArrtibs[6] := WGL_CONTEXT_PROFILE_MASK_ARB; ContextArrtibs[7] := WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
               ContextArrtibs[8] := 0;  //terminator
          end;
       end;

       h_RC := wglCreateContextAttribsARB(h_DC,0,@ContextArrtibs[0]);
   end;

   if (h_RC = 0) then
   begin
       MessageBox(0, 'Unable to set attributes for an OpenGL 3.x rendering context', 'Error', MB_OK or MB_ICONERROR);
       error := getLastError ();
       case error of
           0:MessageBox(0, 'No information about the error from wglCreateContextAttribsARB available.', 'Error', MB_OK or MB_ICONERROR);
           ERROR_INVALID_VERSION_ARB:MessageBox(0, 'Invalid OpenGL version requested', 'Error', MB_OK or MB_ICONERROR);
           ERROR_INVALID_PROFILE_ARB:MessageBox(0, 'Invalid OpenGL profile requested', 'Error', MB_OK or MB_ICONERROR);
       end;

       h_RC := oldh_RC;
   end else
   begin
       //release old GL context
       wglMakeCurrent(h_DC, 0);
       wglDeleteContext(oldh_RC);
   end;

What about a simple glut program, does it crash too ?

Did you also try a sample C code (might then be your language port of wgl that has a bug) ?

As I understand it, you have to first create a 2.x glContext in order to establish which version of OpenGl the h/w supports. Then you are able to call the newer wglCreateContextAttributes.

Creating a default (pre 3) context allows you to be able to retreive pointers from wgl extensions (ie wglCreateContextAttribsARB) so that you can create 3.x contexts, since it is impossible to retrive function pointers without a valid and made current context.

I don’t and never have used glut.
I have been using the same open gl window initialisation code for 10 years now and only has to tweak it recently for the wglcreatecontextattribute extension which was introduced for GL3.

So I doubt that my language porting has an issue.
This crash has only happened since the driver update which points to a fundamental bug in the AMD driver.

This crash has only happened since the driver update which points to a fundamental bug in the AMD driver.

Well, you might be right, but having such a bug that makes a crash on context creation implies that ATI does not test their driver at all, which I highly doubt.

11.9 works okay for me, what are you doing prior to the code you showed? Are you doing anything like calling SetPixelFormat multiple times, or not choosing a pixel format that supports OpenGL. A re-download/re-install might help too, could just be a bad install.

I know, the implication is that ATI have not tested their code, but I can’t see how/why it’s failing now immediately after a driver upgrade (I upgraded becuase I wanted to play ‘Rage’). That’s not working either (different story) so I also upgraded again to AMD Cat 11.10 preview2 drivers.
Guess what…the wglCreateContext has been fixed!

Rage doesn’t work still.

For those who are interested…here’s my OpenGl create window/context code.

I don’t think I’m doing anything odd here.


 {------------------------------------------------}
{  Attaches a OpenGL rendering context to Window  }
{-------------------------------------------------}
function TOpenGLWindow.glWnd(Width, Height : Integer; Fullscreen : Boolean; PixelDepth : Integer) : Boolean;
var
  dmScreenSettings : DEVMODE;   // Screen settings (fullscreen, etc...)
  PixelFormat : GLuint;         // Settings for the OpenGL rendering
//  h_Instance : HINST;           // Current instance
  pfd : PIXELFORMATDESCRIPTOR;  // Settings for the OpenGL window
  myScreen: Trect;
  i,error: integer;
  ContextArrtibs: TintegerArray;
const
// OpenGL context examples:
 GLattribs31_core: array [0..6] of integer = (WGL_CONTEXT_MAJOR_VERSION_ARB, 3,WGL_CONTEXT_MINOR_VERSION_ARB, 1, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,0);
 GLattribs32: array [0..8] of integer = (WGL_CONTEXT_MAJOR_VERSION_ARB, 3,WGL_CONTEXT_MINOR_VERSION_ARB, 2,
  WGL_CONTEXT_FLAGS_ARB, 0,WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0); //terminate with a Zero
 GLattribs30: array [0..6] of integer = (WGL_CONTEXT_MAJOR_VERSION_ARB, 3,WGL_CONTEXT_MINOR_VERSION_ARB, 0,WGL_CONTEXT_FLAGS_ARB, 0, 0); //terminate with a Zero
 GLattribs31: array [0..6] of integer = (WGL_CONTEXT_MAJOR_VERSION_ARB, 3,WGL_CONTEXT_MINOR_VERSION_ARB, 1,WGL_CONTEXT_FLAGS_ARB, 0, 0); //terminate with a Zero

begin
  result := false;
//  extgl_InitializeWGL;     //need to call this before OpenGl init...becase of OpenGL 3.x context
//  extgl_SetupWGL;


  flags := 0;
  SetWindowFlags;

  if UseGLWindow then
  begin
    MakeGLWindow (fglFormw,fglFormh, fullscreen);        //Create OpenGl Window

//    h_Instance := GetModuleHandle(nil);       //Grab An Instance For Our Window
    // Change to fullscreen if so desired
    fFullScreen := fullscreen;

    if fFullscreen then
    begin
      EnumDisplaySettings(nil, ENUM_CURRENT_SETTINGS, DMsaved);	// Save Current Display
//      ZeroMemory(@DMSaved, SizeOf(DMSaved));
      DMSaved.dmPelsWidth := screen.Width;                    // Window width
      DMSaved.dmPelsHeight := screen.Height;                   // Window height
//      ChangeDisplaySettings(DMSaved,CDS_TEST);


      ZeroMemory(@dmScreenSettings, SizeOf(dmScreenSettings));
      with dmScreenSettings do begin              // Set parameters for the screen setting
        dmSize := SizeOf(dmScreenSettings);
        dmPelsWidth := Width;               // Window width
        dmPelsHeight := Height;            // Window height
        dmBitsPerPel := PixelDepth;        // Window color depth
        dmDisplayFlags := 0;       //DM_GRAYSCALE  DM_INTERLACED
//       dmDisplayFrequency := 60;
//       dmFields := DM_DISPLAYFREQUENCY or DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL or DM_DISPLAYFLAGS;
        dmFields := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL or DM_DISPLAYFLAGS;
      end;

      // Try to change screen mode to fullscreen.  CDS_FULLSCREEN = Remove START bar
      if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL) then
      begin
        MessageBox(0, 'Unable to switch to fullscreen!', 'Error', MB_OK or MB_ICONERROR);
        fFullscreen := False;
      end;

    end;  {fullscreen}


    // If we are not in fullscreen then
    if NOT (fFullscreen) then ShowMouse (true)    // Turn on in window mode
    else ShowMouse (fShowCursor);                 // Turn off the cursor (gets in the way)

  end {UseGlWindow}
  else h_Wnd := GLhwnd;   {user suplied window handle}

  if h_Wnd = 0 then
  begin
    glKillWnd;                // Undo all the settings we've changed
    MessageBox(0, 'Unable to initialise window!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Try to get a device context
  h_DC := GetDC(h_wnd);
  if (h_DC = 0) then
  begin
    glKillWnd;
    MessageBox(0, 'Unable to get a device context!', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Settings for the OpenGL window
  with pfd do
  begin
    nSize           := SizeOf(PIXELFORMATDESCRIPTOR); // Size Of This Pixel Format Descriptor
    nVersion        := 1;                    // The version of this data structure
    dwFlags         := Flags;
    iPixelType      := PFD_TYPE_RGBA;        // RGBA color format
    cColorBits      := PixelDepth;           // OpenGL color depth
    cRedBits        := 0;                    // Number of red bitplanes
    cRedShift       := 0;                    // Shift count for red bitplanes
    cGreenBits      := 0;                    // Number of green bitplanes
    cGreenShift     := 0;                    // Shift count for green bitplanes
    cBlueBits       := 0;                    // Number of blue bitplanes
    cBlueShift      := 0;                    // Shift count for blue bitplanes
    cAlphaBits      := 0;                    // Not supported
    cAlphaShift     := 0;                    // Not supported
    cAccumBits      := 0;                    // No accumulation buffer
    cAccumRedBits   := 0;                    // Number of red bits in a-buffer
    cAccumGreenBits := 0;                    // Number of green bits in a-buffer
    cAccumBlueBits  := 0;                    // Number of blue bits in a-buffer
    cAccumAlphaBits := 0;                    // Number of alpha bits in a-buffer
    cDepthBits      := FDepthBits;           // Specifies the depth of the depth buffer. (16-bits or 32-bits)
    cStencilBits    := 0;                    // Turn off stencil buffer
    cAuxBuffers     := 0;                    // Not supported
    iLayerType      := PFD_MAIN_PLANE;       // Ignored
    bReserved       := 0;                    // Number of overlay and underlay planes
    dwLayerMask     := 0;                    // Ignored
    dwVisibleMask   := 0;                    // Transparent color of underlay plane
    dwDamageMask    := 0;                     // Ignored
  end;

    // If component's settings specifies that the accumulation buffer is enabled
  // then set its depth (which enables it)
  if FAccumBufferEnabled then
    pfd.cAccumBits := FAccumBits;

  // If component's settings specifies that the stencil buffer is enabled
  // then set its depth (which enables it)
  if FStencEnabled then
    pfd.cStencilBits := FStencBits;


  if not InitOpenGL (fGlLib,fGluLib) then
  begin
    MessageBox(0, 'Unable to initialise OpenGL library', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;


  // Attempts to find the pixel format supported by a device context that is the best match to a given pixel format specification.
  PixelFormat := ChoosePixelFormat(h_DC, @pfd);
  if (PixelFormat = 0) then
  begin
    glKillWnd;
    MessageBox(0, 'Unable to find a suitable pixel format', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Sets the specified device context's pixel format to the format specified by the PixelFormat.
  //NB  can only be set once!
  if Not glPixelSet then
   if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then
   begin
    glKillWnd;
    MessageBox(0, 'Unable to set the pixel format', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
   end;

  glPixelset := true;

  h_RC := wglCreateContext(h_DC);

  if (h_RC = 0) then
  begin
    glKillWnd;
    MessageBox(0, 'Unable to create a legacy OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  // Makes the specified OpenGL rendering context the calling thread's current rendering context
  if (not wglMakeCurrent(h_DC, h_RC)) then
  begin
    glKillWnd;
    MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  //Now have Open GL context. Initilialise all the GL functions.
  extgl_Initialize;


  // modify current context - add a OpenGL 3.x rendering context - not fully tested
  if supportedExtensions.WGL[WGL_ARB_create_context] then
  begin
   oldh_RC := h_RC;
   if supportedExtensions.OpenGL.Major < 3 then h_RC := wglCreateContextAttribsARB(h_DC,0,@GLattribs30)
   else begin
       //try and create a context using the new API using the highest available GL version.
       //OpenGL 3.1 does not support the extended profile mask settings...
       if (supportedExtensions.OpenGL.Major = 3) AND (supportedExtensions.OpenGL.Minor = 1) then h_RC := wglCreateContextAttribsARB(h_DC,0,@GLattribs31)
       else begin
           if NOT SupportedExtensions.wgl[WGL_ARB_create_context_profile] then
           begin
           setlength (ContextArrtibs, 7);
           ContextArrtibs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB; ContextArrtibs[1] := supportedExtensions.OpenGL.Major;
           ContextArrtibs[2] := WGL_CONTEXT_MINOR_VERSION_ARB; ContextArrtibs[3] := supportedExtensions.OpenGL.minor;
           ContextArrtibs[4] := WGL_CONTEXT_FLAGS_ARB; ContextArrtibs[5] := 0;
           ContextArrtibs[6] := 0;  //terminator
           end else
           begin
           setlength (ContextArrtibs, 9);
           ContextArrtibs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB; ContextArrtibs[1] := supportedExtensions.OpenGL.Major;
           ContextArrtibs[2] := WGL_CONTEXT_MINOR_VERSION_ARB; ContextArrtibs[3] := supportedExtensions.OpenGL.minor;
           ContextArrtibs[4] := WGL_CONTEXT_FLAGS_ARB; ContextArrtibs[5] := 0;
           ContextArrtibs[6] := WGL_CONTEXT_PROFILE_MASK_ARB; ContextArrtibs[7] := WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
           ContextArrtibs[8] := 0;  //terminator
          end;
       end;

       h_RC := wglCreateContextAttribsARB(h_DC,0,@ContextArrtibs[0]);
   end;

   if (h_RC = 0) then
   begin
       MessageBox(0, 'Unable to set attributes for an OpenGL 3.x rendering context', 'Error', MB_OK or MB_ICONERROR);
       error := getLastError ();
       case error of
           0:MessageBox(0, 'No information about the error from wglCreateContextAttribsARB available.', 'Error', MB_OK or MB_ICONERROR);
           ERROR_INVALID_VERSION_ARB:MessageBox(0, 'Invalid OpenGL version requested', 'Error', MB_OK or MB_ICONERROR);
           ERROR_INVALID_PROFILE_ARB:MessageBox(0, 'Invalid OpenGL profile requested', 'Error', MB_OK or MB_ICONERROR);
       end;

       h_RC := oldh_RC;
   end else
   begin
       //release old GL context
       wglMakeCurrent(h_DC, 0);
       wglDeleteContext(oldh_RC);
   end;

   if (h_RC = 0) then
   begin
       glKillWnd;
       Result := False;
       Exit;
   end;   

   //use new GL 3.x context
   wglMakeCurrent(h_DC, h_RC);    //use GL context
   extgl_Initialize;
  end;


  //read back Pixel format to see what OpenGL has assigned
  PixelFormat := GetPixelFormat(h_dc);
  DescribePixelFormat(h_dc, PixelFormat, sizeof(PIXELFORMATDESCRIPTOR), runtime.screen.pfd);
  frequestedPixelDepth := PixelDepth;
  RunTime.Screen.ColorDepth := runtime.screen.pfd.cColorbits;
  AUX_vars.JPG_ALPHA := 255;        //All JPG have the same default alpha.


  fglInit := true;
  result := true;
  exit;

    // Call assinged initialization routine and resize routine
  GetClientRect(h_Wnd, myScreen);          // get screen dimensions
  fWindowW := myScreen.right;             // save initial screen size for later
  fWindowH := myScreen.bottom;

  glResizeWnd(fWindowW, fWindowH);       //SetRunTimeScreen;

end;

The program logic is right. People are doing the same to create 3.x context. Most of them use c though. Could you let me know which line throws the exception?

Thanks for your interest.
The exact line which fails is the first call to wglCreateContext.


  glPixelset := true;

  h_RC := wglCreateContext(h_DC);

It is wired. I can’t understand how can this line is culprit as it is the must-be-called function for every windows ogl program. If this function is buggy, everyone should have complained. I am wondering if the ogl binding has something wrong. Are you using pascal or something else? Sorry I don’t know much about other languages. But anyway, I’ll keep looking into this problem and make you happy hopefully. :slight_smile:

If you have declared these functions yourself, rather than using Delphi’s built in (out of date) OpenGL headers, then are you using the right calling convention for these functions? (eg. stdcall on Win32)

Yes it’s weired and yes I’m surprised noone else has mentioned it. There are some hit on Google however!
The code is Pascal Delphi and yes I have checked the function pointers over and over. Bare in mind that I have used the same code for nearly Ten years without incident (after all how often does wglCreateContext change)?

Anyway the issue resolved itself with your Cat 11.10 preview 2 drivers!
Something odd going on in your driver builds!

I have exactly the same problem. After the update to Catalyst 11.9, the wglCreateContext function fails in one of my applications. The system reports a division by zero exception. I am also a Delphi programmer and I use the dglOpenGL interface unit of the DGL-OpenGl2-Portteam. Not all of my applications are affected. Unfortunately I cannot see why one application fails and the other doesn’t fail. It must have to do with the order of the function calls in the initialization routine (i.e. getting device context, setting pixelformat).

If you have declared these functions yourself, rather than using Delphi’s built in (out of date) OpenGL headers, then are you using the right calling convention for these functions? (eg. stdcall on Win32)

To answer your question: all OpenGL functions and extensions I have implemented my self (using stdcall) and I am not using any 3rd party OpenGL headers. All of these functions are known to work and have been for many years on both nVidia and AMD hardware. I only had a problem recently after switching driver version…

I want to point to another strange problem I was confronted with a while ago and I think it could give us an idea what the source of the problem might be. After a call to wglCreateContext, where I tried to get a rendering Context for a bitmap, the function returned with a changed (destroyed) CPU control word. It seemed as if the CPU was in an MMX mode and all subsequent floating point operations failed after this call to wglCreateContext. To solve the problem, I changed the code and I push the CPU control word before the call and restore it after the call to wglCreateContext. But this is a very unsatisfactory solution, because it is obvious that there is a problem with the implementation of the wglCreateContext function in combination with ATI gpus. The problem didn’t arise when I used wglCreateContext in order to get a rendering context for a window, only rendering contexts for bitmaps were affected.

Could it be that the catalyst 11.9 implementation of wglCreateContext forgets to switch back the CPU from the MMX state, i.e. forgets to empties the MMX state with the EMMS instruction?

Ah, have you included the following code at initialization?


  Set8087CW($133F);

see http://docwiki.embarcadero.com/VCL/XE2/en/System.Set8087CW

But why a floating point exception is happening on creating a context, I don’t know.

I experienced a similar problem when calling a particular OpenCL function with AMD drivers. IIRC it was that it was dividing by zero + by default Delphi doesn’t just ignore those errors, but Visual Studio does.

Thank you for the hint.

As we use the dglOpenGl interface unit, the FPU control word is set during the initialization of the dglOpenGl unit:

  initialization

  {$IFDEF CPU386}
    Set8087CW($133F);
  {$ENDIF}

But when I check the control word before the first call to wglCreateContext, I find it changed again. Some other initialization routines seem to change the FPU control word, too. This could explain why not all of our applications are affected by the error. Dependent on when the initialization of the dglOpenGl unit takes place, the FPU control word is possibly but not necessarily changed afterwards by other routines.

I feel not happy with the solution to disable all floating point exceptions. As we develop commercial software for a branch where the safe operation of the software is required, I would prefer to get the exceptions when they occur. An exception is a clear indicator to the user that something went wrong. If the user cannot see the exceptions, he will not be able to recognize that something went wrong! That is not good programing style, isn’t it?

Set8087CW($133F);

This is interesting and could explain why an exception is thrown for one set of drivers but not another.

I’ll try and set the code in my engine and see what effect it has on the Cat 11.9 drivers which had the problem.

The forum has obviously come to the result that all floating point exceptions of the cpu have to be disabled when OpenGl is used within an application. What do you think, is this true?

Although its not mentioned in any specification i can find, it seems to be quite common for OpenGL drivers to perform divisions by zero during their normal processing, so it is necisary to prevent this from raising an exception.
Every OpenGL.pas file i have back to Delphi 2 includes the Set8087CW($133f) command in its initialization.
There are posts on this forum going back to 2002 that recommend doing it.
My compiler documentation also mentions it: