PDA

View Full Version : Multithread problem



JimS
08-14-2007, 07:48 PM
Here's some simple code I'm trying:

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#define MULTITHREADED

#include <windows.h>
#include <gl/gl.h>

#include <stdio.h>

#ifdef MULTITHREADED
#include <process.h>
#endif

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
typedef void (APIENTRY *PFNWGLEXTSWAPCONTROLPROC)(int);
static PFNWGLEXTSWAPCONTROLPROC wglSwapIntervalEXT = NULL;

static HWND gameWindow;
static HGLRC gameRC;
static int quit;

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
static int ogl_init(void)
{
PIXELFORMATDESCRIPTOR pixeldesc;
int pixelformat;
HDC hDC;

hDC = GetDC(gameWindow);

memset(&amp;pixeldesc, 0, sizeof pixeldesc);
pixeldesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pixeldesc.nVersion = 1;

pixeldesc.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pixeldesc.iPixelType = PFD_TYPE_RGBA;
pixeldesc.cColorBits = 32;

pixeldesc.cRedBits = 0;
pixeldesc.cGreenBits = 0;
pixeldesc.cBlueBits = 0;
pixeldesc.cAlphaBits = pixeldesc.cAlphaShift = 0;
pixeldesc.cAccumBits = 32;
pixeldesc.cAccumRedBits =
pixeldesc.cAccumGreenBits = pixeldesc.cAccumBlueBits = 0;
pixeldesc.cAccumAlphaBits = 0;

pixeldesc.cDepthBits = 32;

pixeldesc.cStencilBits = 0;
pixeldesc.cAuxBuffers = 0;

pixeldesc.bReserved = 0;
pixeldesc.dwLayerMask = 0;
pixeldesc.dwVisibleMask = 0;
pixeldesc.dwDamageMask = 0;

if ((pixelformat = ChoosePixelFormat(hDC, &amp;pixeldesc)) == 0)
return 0;

if (pixeldesc.dwFlags & PFD_NEED_PALETTE)
return 0;

if (SetPixelFormat(hDC, pixelformat, &amp;pixeldesc) == FALSE)
return 0;

DescribePixelFormat(hDC, pixelformat, sizeof pixeldesc, &amp;pixeldesc);

gameRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, gameRC);

ReleaseDC(gameWindow, hDC);

if (strstr((const char *)glGetString(GL_EXTENSIONS), "WGL_EXT_swap_control"))
{
wglSwapIntervalEXT = (PFNWGLEXTSWAPCONTROLPROC)wglGetProcAddress("wglSwapIntervalEXT");
if (wglSwapIntervalEXT)
wglSwapIntervalEXT(1);
}

return 1;
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
static void ogl_shutdown(void)
{
wglMakeCurrent(NULL, NULL);

if (gameRC)
{
wglDeleteContext(gameRC);
gameRC = 0;
}
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
void ogl_flip(void)
{
HDC dc;
GLenum err;

err = glGetError();
if (err != GL_NO_ERROR)
{
char tmp[256];
sprintf(tmp, "GLERROR %08X %d\n", err, err);
OutputDebugString(tmp);
}

dc = GetDC(gameWindow);
SwapBuffers(dc);
ReleaseDC(gameWindow, dc);
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#define BAR_HEIGHT 80

void ogl_draw(void)
{
static int ry,gy,by;
static int ri=1, gi=2, bi=3;

glDepthRange(0.0, 1.0);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glPixelZoom(1.0, -1.0);

glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);

glClearDepth(1.0);
glClearColor(0,0,0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glOrtho(0.0, (GLdouble)SCREEN_WIDTH, (GLdouble)SCREEN_HEIGHT, 0.0, 0.0, 1.0);
glViewport(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);

glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);

glColor3ub(0,0,0);
glBegin(GL_QUAD_STRIP);
glVertex2i(0,ry);
glVertex2i(SCREEN_WIDTH,ry);
glColor3ub(0xff,0,0);
glVertex2i(0,ry+BAR_HEIGHT/2);
glVertex2i(SCREEN_WIDTH,ry+BAR_HEIGHT/2);
glColor3ub(0,0,0);
glVertex2i(0,ry+BAR_HEIGHT);
glVertex2i(SCREEN_WIDTH,ry+BAR_HEIGHT);
glEnd();

glColor3ub(0,0,0);
glBegin(GL_QUAD_STRIP);
glVertex2i(0,gy);
glVertex2i(SCREEN_WIDTH,gy);
glColor3ub(0,0xff,0);
glVertex2i(0,gy+BAR_HEIGHT/2);
glVertex2i(SCREEN_WIDTH,gy+BAR_HEIGHT/2);
glColor3ub(0,0,0);
glVertex2i(0,gy+BAR_HEIGHT);
glVertex2i(SCREEN_WIDTH,gy+BAR_HEIGHT);
glEnd();

glColor3ub(0,0,0);
glBegin(GL_QUAD_STRIP);
glVertex2i(0,by);
glVertex2i(SCREEN_WIDTH,by);
glColor3ub(0,0,0xff);
glVertex2i(0,by+BAR_HEIGHT/2);
glVertex2i(SCREEN_WIDTH,by+BAR_HEIGHT/2);
glColor3ub(0,0,0);
glVertex2i(0,by+BAR_HEIGHT);
glVertex2i(SCREEN_WIDTH,by+BAR_HEIGHT);
glEnd();

ry += ri;
gy += gi;
by += bi;
if (ry < 0) ry = 0, ri=-ri;
else if (ry >= SCREEN_HEIGHT-BAR_HEIGHT) ry = SCREEN_HEIGHT-BAR_HEIGHT-1, ri=-ri;
if (gy < 0) gy = 0, gi=-gi;
else if (gy >= SCREEN_HEIGHT-BAR_HEIGHT) gy = SCREEN_HEIGHT-BAR_HEIGHT-1, gi=-gi;
if (by < 0) by = 0, bi=-bi;
else if (by >= SCREEN_HEIGHT-BAR_HEIGHT) by = SCREEN_HEIGHT-BAR_HEIGHT-1, bi=-bi;
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#ifdef MULTITHREADED
static unsigned int __stdcall runasthread(void *args)
{
HDC dc;

args;

dc = GetDC(gameWindow);
wglMakeCurrent(dc, gameRC);
ReleaseDC(gameWindow, dc);

while (!quit)
{
ogl_draw();
ogl_flip();
}

_endthreadex(0);
return 0;
}
#endif

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg )
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
break;

case WM_ERASEBKGND:
return 1;

case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
break;
}

return 0;
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------------------------------------------
static char GLSampleClass[32] = "GLSampleClass";

int WINAPI WinMain(HINSTANCE this_inst, HINSTANCE prev_inst, LPSTR cmdline, int cmdshow)
{
WNDCLASS wc;
int style, exstyle;
RECT rect;

wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = this_inst;
wc.hIcon = LoadIcon(NULL, (LPCSTR)IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = GLSampleClass;
RegisterClass(&amp;wc);

style = WS_OVERLAPPED|WS_SYSMENU|WS_CAPTION;
exstyle = WS_EX_APPWINDOW;
gameWindow = CreateWindowEx(
0,
GLSampleClass, // class
"OpenGL Sample",
style,
CW_USEDEFAULT,CW_USEDEFAULT, // init. x,y pos
SCREEN_WIDTH,SCREEN_HEIGHT,
NULL, // parent window
NULL, // menu handle
this_inst, // program handle
NULL // create parms
);

GetWindowRect(gameWindow, &amp;rect);
AdjustWindowRectEx(&amp;rect, style, FALSE, exstyle);
SetWindowPos(gameWindow, NULL, 0,0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE);

ShowWindow(gameWindow, cmdshow);
UpdateWindow(gameWindow);

if (ogl_init() == 0)
{
MessageBox(gameWindow, "Failed Initialising OpenGL", "Failed", MB_OK);
return 0;
}

#ifdef MULTITHREADED
wglMakeCurrent(NULL, NULL);
_beginthreadex(NULL, 0, runasthread, NULL, 0, NULL);
#endif

quit = 0;
do
{
MSG msg;
while (PeekMessage(&amp;msg,NULL,0,0, PM_NOREMOVE))
{
if (GetMessage(&amp;msg,NULL,0,0)>0)
{
TranslateMessage(&amp;msg);
DispatchMessage(&amp;msg);
}
else
{
quit = 1;
break;
}
}
#ifndef MULTITHREADED
ogl_draw();
ogl_flip();
#else
Sleep(50);
#endif

} while (!quit);

ogl_shutdown();

return 0;
}It should work with or without MULTITHREADED defined.

Symptoms are:
MULTITHREADED NOT defined.
All OK

MULTITHREADED defined.
sometimes the display runs correctly.
sometimes the display is not updated.
sometimes the display is not updated but dragging the window round forces an update.
sometimes there is a delay before anything is displayed.

The problem seems only to exist on Windows Vista 32bit. Windows XP SP2 works fine.

This is on an nVidia 8600GT, latest drivers, Core2 Duo.

Has anyone got any ideas?

Jim

JimS
08-15-2007, 09:56 PM
Can anyone confirm that they get the same problems?

I've found a post here that suggests adding

SetProcessAffinityMask(GetCurrentProcess(), 0x1);at the very start of the program might fix multithread problems.

That does indeed fix the problem, but it's obvious the race condition is not in my sample.

Jim