vdrivers/vd_win32.c has a race condition with the loadcolor SetDIBColorTable function call, which happens sometimes on fast multiprocessor machines. If the WndThread is currently executing its BitBlt during WM_PAINT processing and the GRX user thread is calling GrAllocColor, the SetDIBColorTable function call fails, as the DC is locked by the BitBlt. This results in the color not being set, which could also happen during the initial setting of the VGA colors in _GrResetColors.
This affects only 8 bpp modes, as loadcolor is not called in 32 bpp modes.
I can reproduce this problem on a modern dual core Vista system, and on a dual core Linux system running Wine. It happens less often on a modern dual core XP system, but it happens.
My proposed fix delays the SetDIBColorTable call and moves it to the WM_PAINT processing, making it synchronous with the BitBlt call.
Hope that helps,
*** vdrivers/vd_win32.c- Mon Nov 24 19:32:14 2008 --- vdrivers/vd_win32.c Mon Nov 24 21:25:56 2008 *************** *** 101,106 **** --- 101,113 ---- static volatile int isWindowThreadRunning = 0; static volatile int isMainWaitingTermination = 0;
+ struct _GR_modifiedColors { + int modified; + RGBQUAD color; + }; + static struct _GR_modifiedColors modifiedColors[256]; + static volatile int isColorModified = 0; + static DWORD WINAPI WndThread(void *param); static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); *************** *** 112,119 **** color.rgbGreen = g; color.rgbRed = r; color.rgbReserved = 0; ! SetDIBColorTable(hDCMem, c, 1, &color); ! InvalidateRect(hGRXWnd, NULL, FALSE); }
static HBITMAP CreateDIB8(HDC hdc, int w, int h, char **pBits) --- 119,130 ---- color.rgbGreen = g; color.rgbRed = r; color.rgbReserved = 0; ! if (c >= 0 && c <= 256) { ! modifiedColors[c].color = color; ! modifiedColors[c].modified = 1; ! isColorModified = 1; ! InvalidateRect(hGRXWnd, NULL, FALSE); ! } }
static HBITMAP CreateDIB8(HDC hdc, int w, int h, char **pBits) *************** *** 595,600 **** --- 606,626 ---- { PAINTSTRUCT ps;
+ if (isColorModified) { + int c; + + isColorModified = 0; + for (c = 0; c < 256; c++) { + if (modifiedColors[c].modified) { + int res; + + modifiedColors[c].modified = 0; + if ((res = SetDIBColorTable(hDCMem, c, 1, &modifiedColors[c].color)) != 1) + DBGPRINTF(DBG_DRIVER,("SetDIBColorTable returned %d (%ld) color %d\n", res, GetLastError(), c)); + } + } + } + if (BeginPaint(hWnd, &ps)){ BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top,