Multiple rendering contexts problems

Working on a 3D editor type app with 4 views (left top etc).

At the moment, when the app is first run the contexts are created and the rendering does work and show as expected in the 4 areas of the app.

Now for the problems;

At this stage I am rendering a simple cube in each view for testing purposes. I added some code to get the cube to rotate. If I only activate (wglmakecurrent) one of the contexts, then the rotation works as expected. If I activate all 4 of the contexts the cube does not rotate.

Same thing if I try and change the location of the cube. In one window it works, but once all 4 contexts are activated it fails (actually it only updates the last activated context).

Any ideas?

Code for display is basically

//first view
wglMakeCurrent(cameraDC,cameraRC);
<render opengl stuff here>
//second view
wglMakeCurrent(leftDC,leftRC);
<render opengl stuff here>
etc
etc for the other 2 views

The contexts are created when the app first starts up and are not deleted.

Writing this in Delphi if that helps at all.

Any help or ideas will be greatly appreciated.

Thanks,
Jason.

I think we can be fairly sure that wglMakeCurrent() is working (Doom wouldn’t run if it didn’t), and you haven’t shown us any of your other code - so I doubt anyone could help you.

There’s probably a very good chance of the problem being in the code you use to render your mesh.

OK, some more snippets that may help (I hope).

Creating contexts when app starts;

 //setup pixel format descriptor
 FillChar(PFD,SizeOf(PFD),0);
 with PFD do
 begin
      nSize      := SizeOf(PFD);                  // Size of this structure
      nVersion   := 1;                            // Version of this structure
      dwFlags    := PFD_SUPPORT_OPENGL;           // Support OpenGL calls
      dwFlags    := dwFlags or PFD_DRAW_TO_BITMAP; // Draw into a bitmap
      iPixelType := PFD_TYPE_RGBA;                // RGBA color mode
      cColorBits := 24;
      cDepthBits := 24;                           // Size of depth buffer
      iLayerType := PFD_MAIN_PLANE;               // Draw in main plane
 end;

 cameraDC:=camerabitmap.canvas.handle;
 PFI:=ChoosePixelFormat(cameraDC, @PFD);
 SetPixelFormat(cameraDC, PFI, @PFD);
 cameraRC:=wglCreateContext(cameraDC);
 wglMakeCurrent(cameraDC,cameraRC);

cameraaspect:=camerabitmap.width/camerabitmap.height;
glenable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(camerafovy,cameraaspect,cameraznear,camerazfar);
glViewport(0, 0, camerabitmap.Width, camerabitmap.Height);

Above is repeated for the other 3 contexts. Same code with names changed.

And for the “update display” code;

 wglMakeCurrent(cameraDC,cameraRC);
 glenable(GL_COLOR_MATERIAL);
 glClearColor(0, 0, 0, 0);
 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity;
 gluLookAt(eyex,eyey,eyez,lookatx,lookaty,lookatz,0,1,0);
 glRotatef(strtofloat(xrot.text),1,0,0);
 glRotatef(strtofloat(yrot.text),0,1,0);
 glRotatef(strtofloat(zrot.text),0,0,1);
      glbegin(gl_quads);CubeGL(0,0,0,80);glend;
 glflush;
 cameraimage.canvas.draw(0,0,camerabitmap);

The above is only for the main camera view, but the code for the other views looks identical (except for the context names).

The cube does get rendered, it just doesn’t rotate if all 4 views are being displayed. It is like OpenGL is ignoring the rotate commands for some reason.

Rendering a single view works as expected. Rendering the 4 views at the same time (well one after another) causes the problem.

Any other ideas?

Thanks,
Jason.

i’m just guessing here.
but maybe you need to invalidate the windows before rendering the bitmap?
otherwise windows thinks the window doesn’t need to be updated.

besides, why are you rendering to bitmaps and not directly to the window?

I suggest, you check the return value of wglMakeCurrent for possibly occured errors.

Thanks for the suggestions.

Invaldating the window didn’t make a difference. Exact same result.

Tracking the return value of wglmakecurrent and the various context handles was more interesting.

When app first starts and displays are updated (which all 4 do display correctly);

CAMERA: wglmakecurrent = True getlasterror = 8 cameradc = 838928627 getcurrentdc = 838928627
FRONT: wglmakecurrent = True getlasterror = 8 frontdc = 721488187 getcurrentdc = 721488187
LEFT: wglmakecurrent = True getlasterror = 8 leftdc = 117508407 getcurrentdc = 117508407
TOP: wglmakecurrent = True getlasterror = 8 topdc = 83953890 getcurrentdc = 83953890

If I refresh all the displays again (which uses the exact same code as when app is first run), results are;

CAMERA: wglmakecurrent = False getlasterror = 6 cameradc = 838928627 getcurrentdc = 83953890
FRONT: wglmakecurrent = False getlasterror = 2000 frontdc = 721488187 getcurrentdc = 0
LEFT: wglmakecurrent = False getlasterror = 6 leftdc = 117508407 getcurrentdc = 83953890
TOP: wglmakecurrent = False getlasterror = 2000 topdc = 83953890 getcurrentdc = 0

For the third (and all subsequent refreshes) the results are;

CAMERA: wglmakecurrent = False getlasterror = 6 cameradc = 838928627 getcurrentdc = 0
FRONT: wglmakecurrent = False getlasterror = 2000 frontdc = 721488187 getcurrentdc = 0
LEFT: wglmakecurrent = False getlasterror = 6 leftdc = 117508407 getcurrentdc = 0
TOP: wglmakecurrent = False getlasterror = 2000 topdc = 83953890 getcurrentdc = 0

How can I find out what getlasterror values of 6 and 2000 mean?

Any other suggestions? This should be a simple problem to fix.

Thanks,
Jason.

OK, turns out that the displays I thought were working but not rotating were not working. The last update to the bitmap was just being redisplayed without being changed by OpenGL. Cleared all the bitmaps and filled them with a fuschia color, so if the OpenGL calls do not update the bitmap correctly then it will be shown as a solid pink square.

Now what happens…

First run - all displays fine - return codes;

CAMERA: wglmakecurrent = True getlasterror = 8 cameradc = 3036744299 wglgetcurrentdc = 3036744299
FRONT: wglmakecurrent = True getlasterror = 8 frontdc = 1426131632 wglgetcurrentdc = 1426131632
LEFT: wglmakecurrent = True getlasterror = 8 leftdc = 234949323 wglgetcurrentdc = 234949323
TOP: wglmakecurrent = True getlasterror = 8 topdc = 2550205167 wglgetcurrentdc = 2550205167

Second refresh - only the “top” view is updated - all the other views are fuschia - return codes

CAMERA: wglmakecurrent = False getlasterror = 6 cameradc = 3036744299 wglgetcurrentdc = 2550205167
FRONT: wglmakecurrent = False getlasterror = 6 frontdc = 1426131632 wglgetcurrentdc = 2550205167
LEFT: wglmakecurrent = False getlasterror = 6 leftdc = 234949323 wglgetcurrentdc = 2550205167
TOP: wglmakecurrent = False getlasterror = 6 topdc = 2550205167 wglgetcurrentdc = 2550205167

This is strange. If the wglmakecurrent call returned false, then why does it work and update the view?

Regards,
Jason.

Maybe this will help too. I remarked out all the OpenGL rendering code and left only the wglmakecurrent calls. So code structure when updating is now just (variables used to track return values etc);

cb:=wglMakeCurrent(cameraDC,cameraRC);
cle:=getlasterror;
ccdc:=wglgetcurrentdc;
lb:=wglMakeCurrent(leftDC, leftRC);
lle:=getlasterror;
lcdc:=wglgetcurrentdc;
fb:=wglMakeCurrent(frontDC, frontRC);
fle:=getlasterror;
fcdc:=wglgetcurrentdc;
tb:=wglMakeCurrent(topDC, topRC);
tle:=getlasterror;
tcdc:=wglgetcurrentdc;

No OpenGL rendering calls. Results are the same as the last run, ie

First display results;
CAMERA: wglmakecurrent = True getlasterror = 8 cameradc = 4261480786 wglgetcurrentdc = 4261480786
FRONT: wglmakecurrent = True getlasterror = 8 frontdc = 3288402361 wglgetcurrentdc = 3288402361
LEFT: wglmakecurrent = True getlasterror = 8 leftdc = 2181106456 wglgetcurrentdc = 2181106456
TOP: wglmakecurrent = True getlasterror = 8 topdc = 872483203 wglgetcurrentdc = 872483203

Second and all further results;
CAMERA: wglmakecurrent = False getlasterror = 6 cameradc = 4261480786 wglgetcurrentdc = 872483203
FRONT: wglmakecurrent = False getlasterror = 6 frontdc = 3288402361 wglgetcurrentdc = 872483203
LEFT: wglmakecurrent = False getlasterror = 6 leftdc = 2181106456 wglgetcurrentdc = 872483203
TOP: wglmakecurrent = False getlasterror = 6 topdc = 872483203 wglgetcurrentdc = 872483203

So from this, it looks like at the end of the first display the currentdc is locked into the dc for the top view.

Don’t know what else to try.

Jason.

Typically the technique of keeping separate GLRCs open per window DC is intended for multiple rendering threads. For non-multi-threaded rendering you will probably need to close each GLRC before going on to the next one. ie,

wglMakeCurrent(cameraDC,cameraRC);
// draw and update…
wglMakeCurrent(cameraDC,NULL);

wglMakeCurrent(topDC,topRC);
// draw and update…
wglMakeCurrent(topDC,NULL);

Otherwise the GL driver may be using cached info on what it thinks is the current GLRC and keeping that GL command pipe open for the corresponding window DC until it detects some change.

I tried to add a specific wglmakecurrent(cameradc,NULL) calls and it didn’t make a difference.

Elsewhere I saw info that when you make a wglmakecurrent call to another DC/RC it automatically “deselects” the current context anyway.

Is there any info somewhere about the return values of wglmakecurrent and getlasterror?

When the app first runs and all 4 displays update correctly the 4 wglmakecurrent calls return true, and they have a getlasterror value of 8.

When the displays are updated after the frist run (using exact same code as when the app starts) wglmakecurrent returns false and getlasterror returns 2000. BUT, one of the windows does still update correctly.

So when tracking the DCs RCs etc;

First run when all 4 windows show correctly;
C: wglmakecurrent = True getlasterror = 8 rc = 65536 dc = 4261480657 wglgetcurrentdc = 4261480657
F: wglmakecurrent = True getlasterror = 8 rc = 65538 dc = 3875606279 wglgetcurrentdc = 3875606279
L: wglmakecurrent = True getlasterror = 8 rc = 65537 dc = 167841436 wglgetcurrentdc = 167841436
T: wglmakecurrent = True getlasterror = 8 rc = 65539 dc = 1627457575 wglgetcurrentdc = 1627457575

Second and all subsequent runs;
C: wglmakecurrent = False getlasterror = 2000 rc = 65536 dc = 4261480657 wglgetcurrentdc = 1627457575
F: wglmakecurrent = False getlasterror = 2000 rc = 65538 dc = 3875606279 wglgetcurrentdc = 1627457575
L: wglmakecurrent = False getlasterror = 2000 rc = 65537 dc = 167841436 wglgetcurrentdc = 1627457575
T: wglmakecurrent = False getlasterror = 2000 rc = 65539 dc = 1627457575 wglgetcurrentdc = 1627457575

And the only window that shows is the one that has the right DC.

Sometimes after mutliple refreshes the wglgetcurrentdc will change to one of the other DCs and another of the windows will update correctly.

Very strange? Any indepth doco on the getlasterror values for wglmakecurrent?

Thanks,
Jason.

OK, narrowed it down a bit more.

  1. If I move the display code out of the program startup (form creation) code the first display update of all 4 windows works perfectly all returning a 0 for get last error.

  2. Second time the update display code is called the return code from getlasterror is 7D0 (hex) and windows reports this means “The pixel format is invalid”.

The offscreen bitmaps and the pixelformatdescriptor are both set to 24 bit and are not changed in any part of the program.

Anyone have any ideas on why the pixel format would be invalid after a second display update (exact same code that works the first time it is called)?

Thanks,
Jason.

Hmmm, getting closer. Two final questions (I hope).

The 4 displays now work correctly if I call SetPixelFormat before each wglmakecurrent call.

Are there any dangers with doing this?

Also, now the getlasterror returns “Not enough storage is available to process this command”, but seeing as the displays are now working maybe I shouldn’t be concerned?

Maybe all this rambling may help another Delphi user in the future.

Jason.

You must not call SetPixelFormat more than once per window, consult MSDN about it.

Originally posted by skynet:
You must not call SetPixelFormat more than once per window, consult MSDN about it.
I’ve seen somebody do it and it works. He was using the render to bitmap flag in SetPixelFormat.

Jason666, What is your renderer? glGetString(GL_RENDERER)

I saw the warning about SetPixelFormat in MSDN, but in this case I am not rendering to a Window, and the call doesn’t seem to cause any issues with the app (even after thousands of repeated calls to the update display routine). What symptoms would I see if multiple calls to SetPixelFormat caused a problem?

glgetstring(GL_RENDERER) returns “GDI Generic”.

Thanks again,
Jason.

why are you using different rendering contexts in first place? It is better to use single when possible, and in your case they are essentially identical and you re-set all the states all the time anyway. Generally the context switching is a heavy operation for the driver, and cumbersome for your app. Also you better not set the pixel format multiple times. Even if it’s harmless, it does not help either.

Originally posted by Jason666:
glgetstring(GL_RENDERER) returns “GDI Generic”.

This is most likely because you are rendering to a bitmap instead of windows. I would guess that you will not have any extensions greater than v1.1 available to you because “GDI_GENERIC” is running in software - so you wouldn’t be getting any HW T&L.

You’d be much better off just rendering directly to the window(s).

Jason666,
please make sure that your window class (the structure you pass to RegisterClass) has the CS_OWNDC style, and a meaningful hInstance.

l_belev: If I only use one RC, it does not render to the viewports correctly. This is rendering to bitmaps, not direct to windows. The viewports are 4 seperate TImage components from Delphi, so I prefer to render to a bitmap and then have the ability to draw (BitBlt) to the TImages.

rgpc: No worries without hardware acceleration. Generic software mode is fast enough for my needs in this app. Even if I did render direct to the windows it wouldn’t be accelerated anyway right? In my past OpenGL apps, to get hardware acceleration I had to use fullscreen mode, so smaller sub-windows would not be accelerated anyway, right?

zeckensack: That C stuff has no meaning to a Delphi app. Well it may, but it is well hidden in the background, so I never have needed to manually worry about the window api creation stuff.

Thanks to everyone who replied with suggestions. Now that the 4 displays render OK, I can start on the real workings of the app.

Jason.

Originally posted by Jason666:
zeckensack: That C stuff has no meaning to a Delphi app. Well it may, but it is well hidden in the background, so I never have needed to manually worry about the window api creation stuff.
Well, I’ve never worked with Delphi, but I hope this gets handled correctly.
A “standard” window is not entirely fit for OpenGL rendering. Things may start to break when it receives a WM_PAINT message (and it inevitably will at some point).

Maybe Tom Nuydens, our local Delphi guru, can tackle this.