Display List sharing between contexts, disapearing

Hello,
I’m using wglShareLists() to share display lists between contexts. My problem is that when I dynamically create a context (a sub window) and use one of the display lists in it, the display list stops displaying on the parent window.

Note: Both contexts have the same pixel format. (they are instances of the same class)

I’ma lost. Any help is much appreciated.

Frank V.

You dont need to create new contex for each subwindow… just set same pixelformat for all windows that need to host OpenGL rendering contex. When you need to repaint some subwindow in WM_PAINT call:

  • wglMakeCurrent(win_dc, global_rc);
  • draw stuff,
  • swap buffers and
  • wglMakeCurrent(win_dc, NULL);
    Using this way you just move rendering contex between subviews. All textures, buffers, vertices, states, etc. remain same in all views.

You dont need to create new contex for each subwindow…

I’m pretty sure that you do. Just changing the pixel format of the window doesn’t initialize OpenGL to render to those windows. The default framebuffer of your “global_rc” will only go to the first window you created.

IMO it’ll work iff you set the pixel format on each subwindow you draw to. E.g. you could create an invisible root window for the app with the desired PF then SetPixelFormat on each window touched thereafter. There may be a multithreading consequence or two in such an approach, and AFAIK WPF will flat out refuse to work owing to some top-level window-handle monkey business.

But it’s not supposed to work. There is nothing that says it should work, and nothing that guarantees that it will work on other OS’s. Have you tried this on Vista/Win7, for example?

Well, as far as I can comprehend wglMakeCurrent only mandates that hdc exist on the same device and have the same pixel format - which seems to imply basic goodness overall.

Following is my open gl window class. when I try and create multiples of the class, to share the textures loaded, only one of the windows displays the textures correctly. Sometimes my textures get moved around. Could someone point out my error, perhaps in the init or the create functions?

Thanks in advanced.

My code:
class OpenGLDisplayClass : public CWnd
{
public:
OpenGLDisplayClass();
virtual BOOL Create(CWnd*, const RECT&, int TypeOfWindow = 0);
virtual void Update();

virtual void Display(){};
void ChangeViewPort(double angle, int x1, int y1, int width, int height, int projection = 0);
void MakeContextCurrent(BOOL onOff);
~OpenGLDisplayClass();

protected:
// declare event functions
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnSize (UINT, int, int);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
DECLARE_MESSAGE_MAP ()

void CreateViewPort(double angle, int x1, int y1, int width, int height);

static HGLRC m_first_hRC ; 	//OpenGL Rendering Context
static CDC*  m_first_pDC;   //Device Context
HGLRC m_hRC ; 			    //OpenGL Rendering Context
CDC* m_pDC;                 //Device Context
HDC m_hdc;			
CRect m_window_area;
ViewType m_view;
BOOL SetupPixelFormat();
BOOL InitOpenGL();
static int m_objects;
static bool m_initialized;

private:
};

int OpenGLDisplayClass::m_objects = 0;
bool OpenGLDisplayClass::m_initialized = false;
HGLRC OpenGLDisplayClass::m_first_hRC = NULL; //OpenGL Rendering Context
CDC* OpenGLDisplayClass::m_first_pDC = NULL;
//CDC* OpenGLDisplayClass::m_pDC; //Device Context

BEGIN_MESSAGE_MAP (OpenGLDisplayClass, CWnd)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP ()

//-----------------------------------------------------------------------------
OpenGLDisplayClass::OpenGLDisplayClass()
{
m_view = view_chase;
m_objects++;
};

//-----------------------------------------------------------------------------
OpenGLDisplayClass::~OpenGLDisplayClass()
{
wglMakeCurrent(0,0);
wglDeleteContext(m_hRC);
if(m_pDC)
{
delete m_pDC;
}
m_pDC = NULL;
m_objects–;

if (m_objects<= 0)
{
    m_initialized = false;
    m_objects = 0;
}

};

//-----------------------------------------------------------------------------
BOOL OpenGLDisplayClass::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // Size of this pixel format descriptor.
1, // Version number
PFD_DRAW_TO_WINDOW | // Format must support windows
PFD_SUPPORT_OPENGL | // Use OpenGL
PFD_DOUBLEBUFFER | // Use double buffer
PFD_GENERIC_ACCELERATED |
PFD_GENERIC_FORMAT, // Pixel format is for a window.
PFD_TYPE_RGBA, // Request A RGBA Format
24, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
32, // 32bit Z-buffer (depth buffer)
1, // 1 Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};

//int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
int m_nPixelFormat = ::ChoosePixelFormat(m_hdc, &pfd);
if (m_nPixelFormat == 0)
    return FALSE;

// return ::SetPixelFormat(dc.m_hDC, nPixelFormat, &pfd);
// return ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd);
return ::SetPixelFormat(m_hdc, m_nPixelFormat, &pfd);

};

//-----------------------------------------------------------------------------
BOOL OpenGLDisplayClass::InitOpenGL()
{
//Get a DC for the Client Area
m_pDC = new CClientDC(this);

//Failure to Get DC
if(m_pDC == NULL)
return FALSE;

// Get device context only once.
m_hdc = GetDC()->m_hDC;
// m_hdc = m_pDC->GetSafeHdc();

if(!SetupPixelFormat())
return FALSE;

//Create Rendering Context
m_hRC = wglCreateContext(m_hdc);//m_pDC->GetSafeHdc());
//Failure to Create Rendering Context
if(m_hRC == 0)
    return FALSE;

//Make the RC Current
//if(::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC) == FALSE)
// return FALSE;
if(wglMakeCurrent(m_hdc, m_hRC) == FALSE)
return FALSE;

// set material values.
GLfloat mat_specular[] = {0.5f, 0.5f, 0.5f, 1.0};
GLfloat mat_shininess[] = {30.0f};

// set the light values.
GLfloat diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f };
GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f };
GLfloat ambient[]  = {0.3f, 0.3f, 0.3f, 1.0f };
GLfloat lightPos[] = {10000.0, 0.0, 1000.0, 0.0};
// setup lights and material
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

// glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);

glEnable(GL_DEPTH_TEST);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); // Really Nice Perspective Calculations
glHint(GL_POLYGON_SMOOTH_HINT , GL_FASTEST);
glHint(GL_POINT_SMOOTH_HINT , GL_FASTEST);
glHint(GL_LINE_SMOOTH_HINT , GL_FASTEST);

return true;

};

//-----------------------------------------------------------------------------
BOOL OpenGLDisplayClass::Create(CWnd *pParentWnd, const RECT &rect, int TypeOfWindow)
{
if (CWnd::Create(NULL, “”, WS_CHILD | WS_VISIBLE, rect, pParentWnd, 0, NULL) == -1)
return false;

GetClientRect(&m_window_area);
if (!InitOpenGL())

{
MessageBox(“Error setting up OpenGL!”,
“Init Error!”,
MB_OK | MB_ICONERROR );
return -1;
}

if (m_initialized == false)
{
    BuildFont(m_hdc);//m_pDC->GetSafeHdc());
    LoadCommonTextures();
    DrawCommonShapes(TypeOfWindow);
    m_first_hRC = m_hRC;
    m_initialized = true;
}
else
{
    wglShareLists(m_first_hRC, m_hRC);
};
return true;

};

//-----------------------------------------------------------------------------
BOOL OpenGLDisplayClass::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CS_OWNDC;
return CWnd::PreCreateWindow(cs);
}

//-----------------------------------------------------------------------------
BOOL OpenGLDisplayClass::OnEraseBkgnd(CDC* pDC)
{
//return CView::OnEraseBkgnd(pDC);
return TRUE ;
}

//-----------------------------------------------------------------------------
void OpenGLDisplayClass::CreateViewPort(double angle, int x1, int y1, int width, int height)
{
glScissor(x1, y1, width,height);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);

glViewport(x1, y1, width, height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(angle, (float) width / (float)height, 1.0, 3000000.0);

glMatrixMode(GL_MODELVIEW);
// glLoadIdentity();
}

void OpenGLDisplayClass::ChangeViewPort(double angle, int x1, int y1, int width, int height, int projection)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

int left = x1,
    right = width, 
    bottom = y1,
    top = height;
glViewport(x1, y1, width, height);
if (projection == 0) 
{

// glTranslated(x1, y1, 0);
gluPerspective(angle, (float) width / (float)height, 1.0, 3000000.0);
}
else
{
glOrtho(left, right, bottom, top, -1000, 3000);
};

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
};

//-----------------------------------------------------------------------------
void OpenGLDisplayClass::OnSize(UINT nType, int cx, int cy)
{
CClientDC dc(this);
wglMakeCurrent(dc.m_hDC, m_hRC);
m_window_area = CRect(0, 0, cx, cy);

CreateViewPort(30.0, 0, 0, cx, cy);
wglMakeCurrent(NULL, NULL);	

}

//-----------------------------------------------------------------------------
void OpenGLDisplayClass::MakeContextCurrent(BOOL onOff)
{
if (onOff)
{
// ::wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);
::wglMakeCurrent(m_hdc, m_hRC);
}
else
{
::wglMakeCurrent(NULL, NULL);
};
}

//-----------------------------------------------------------------------------
void OpenGLDisplayClass::Update()
{
Invalidate(FALSE);
UpdateWindow();
};

normally the contexts need to be completely empty before you can share display list space. You might be able to get away with just having 1 empty. I can’t remember the details exactly, but if you have already uploaded content and do the same with the second, display list sharing will fail.

Just to clear up the confusion here a bit.

  1. Its perfectly legal and possible to use one context to draw into multiple windows (DC’s). To quote MSDN about wglMakeCurrent:

The hdc parameter must refer to a drawing surface supported by OpenGL. It need not be the same hdc that was passed to wglCreateContext when hglrc was created, but it must be on the same device and have the same pixel format.

  1. wglShareLists accepts two RCs. The first one (RC1) is the one that already might have objects in it. The second (RC2) is the one that will “take over” the list of RC1. RC2 must not have any objects in at this moment.

BOOL wglShareLists(
HGLRC hglrc1, // OpenGL rendering context with which to share display lists
HGLRC hglrc2 // OpenGL rendering context to share display lists
);
hglrc1
Specifies the OpenGL rendering context with which to share display lists.
hglrc2
Specifies the OpenGL rendering context to share display lists with hglrc1. The hglrc2 parameter should not contain any existing display lists when wglShareLists is called.