Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2867 lines
82 KiB

/******************************Module*Header*******************************\
* Module Name: pixelfmt.c
*
* This contains the pixel format functions.
*
* Created: 15-Dec-1994 00:28:39
* Author: Gilman Wong [gilmanw] -- ported from gdi\gre\pixelfmt.cxx
*
* Copyright (c) 1994 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
// #define DBG_WNDOBJ
// #define DBG_REFCOUNTS
#ifdef _CLIENTSIDE_
// Need for glsbAttention declaration
#include "glsbcltu.h"
#include "gldci.h"
#endif
#ifdef _MCD_
#include "mcd.h"
#endif
#define SAVE_ERROR_CODE(x) SetLastError((x))
// Number of generic pixel formats. There are 5 pixel depths (4,8,16,24,32).
// See GreDescribePixelFormat for details.
// This is to convert BMF constants into # bits per pel
ULONG gaulConvert[7] =
{
0,
1,
4,
8,
16,
24,
32
};
#define MIN_GENERIC_PFD 1
#define MAX_GENERIC_PFD 24
LRESULT CALLBACK
wglDCIWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK
wglDIBWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
#define PALETTE_WATCHER_CLASS __TEXT("Palette Watcher")
static ATOM aPaletteWatcherClass = 0;
DWORD tidPaletteWatcherThread = 0;
ULONG ulPaletteWatcherCount = 0;
HWND hwndPaletteWatcher;
LONG lPaletteWatcherUsers = 0;
/******************************Public*Routine******************************\
* pwndNew
*
* Allocate a new GLGENwindow, initialize it (from input structure), and
* insert it into the global linked list.
*
* Returns:
* Pointer to structure if successful, NULL otherwise.
*
* History:
* 01-Nov-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
GLGENwindow * APIENTRY pwndNew(GLGENwindow *pwndInit)
{
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
BOOL bUseDCI = GLDCIENABLED && pwndInit->hwnd;
// If using DCI, open a WinWatch object to track vis rgn changes.
if ( !bUseDCI || (pwndInit->hww = WinWatchOpen(pwndInit->hwnd)) )
{
// Allowcate a new GLGENwindow.
pwndRet = (GLGENwindow *) LocalAlloc(LMEM_FIXED, sizeof(GLGENwindow));
if (pwndRet)
{
// Initialize from input structure.
*pwndRet = *pwndInit;
// Initialize per-window structure.
InitializeCriticalSection(&pwndRet->sem);
// Set initial usage count to one
pwndRet->lUsers = 1;
// Insert into linked list.
EnterCriticalSection(&gwndHeader.sem);
{
pwndRet->pNext = gwndHeader.pNext;
gwndHeader.pNext = pwndRet;
}
LeaveCriticalSection(&gwndHeader.sem);
}
}
else
{
WARNING("pwndNew: WinWatchOpen failed\n");
}
#ifdef DBG_WNDOBJ
if (pwndRet != NULL)
{
DbgPrint("Alloc WNDOBJ %p, HWND %p, HDC %p\n", pwndRet,
pwndRet->hwnd, pwndRet->hdc);
}
#endif
return pwndRet;
}
/******************************Public*Routine******************************\
*
* pwndUnsubclass
*
* Removes OpenGL's subclassing set when WNDOBJs are created
*
* History:
* Mon May 20 14:05:23 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void pwndUnsubclass(GLGENwindow *pwnd)
{
WNDPROC wpCur;
// We only restore the original WNDPROC if the current WNDPROC
// is one of ours. This prevents us from stomping on the WNDPROC
// pointer if somebody else has changed it.
if ((pwnd->ulFlags & GLGENWIN_OTHERPROCESS) == 0)
{
wpCur = (WNDPROC)GetWindowLong(pwnd->hwnd, GWL_WNDPROC);
if (wpCur == wglDCIWndProc || wpCur == wglDIBWndProc)
{
SetWindowLong(pwnd->hwnd, GWL_WNDPROC, (LONG) pwnd->pfnOldWndProc);
}
}
else
{
// Clean up the palette watcher window if this is the last user.
EnterCriticalSection(&gcsPaletteWatcher);
ASSERTOPENGL(lPaletteWatcherUsers > 0,
"lPaletteWatcherUsers too low\n");
if (--lPaletteWatcherUsers == 0)
{
PostMessage(hwndPaletteWatcher, WM_CLOSE, 0, 0);
tidPaletteWatcherThread = 0;
}
LeaveCriticalSection(&gcsPaletteWatcher);
}
}
/******************************Public*Routine******************************\
* pwndFree
*
* Frees the specified GLGENwindow.
*
* Returns:
* NULL if successful, pointer to structure otherwise (same convention
* as LocalFree).
*
* History:
* 07-Nov-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
GLGENwindow * APIENTRY pwndFree(GLGENwindow *pwndVictim)
{
BOOL bUseDCI = GLDCIENABLED && pwndVictim->hwnd;
#ifdef DBG_WNDOBJ
DbgPrint("Free WNDOBJ %p\n", pwndVictim);
#endif
// Check for a stray DCI lock and release if necessary.
if (pwndVictim->ulFlags & GLGENWIN_DCILOCK)
MyDCIEndAccess(pwndVictim);
// Close WinWatch object.
if (bUseDCI)
WinWatchClose(pwndVictim->hww);
// Cleanup visible region caches if they exist.
if ( pwndVictim->prgndat )
LocalFree(pwndVictim->prgndat);
if ( pwndVictim->pscandat )
LocalFree(pwndVictim->pscandat);
// Restore original WNDPROC in window.
if (pwndVictim->hwnd != NULL)
pwndUnsubclass(pwndVictim);
// Cleanup GLGENlayers.
if (pwndVictim->plyr)
{
int i;
for (i = 0; i < 15; i++)
{
if (pwndVictim->plyr->overlayInfo[i])
LocalFree(pwndVictim->plyr->overlayInfo[i]);
if (pwndVictim->plyr->underlayInfo[i])
LocalFree(pwndVictim->plyr->underlayInfo[i]);
}
LocalFree(pwndVictim->plyr);
}
// Delete victim.
DeleteCriticalSection(&pwndVictim->sem);
pwndVictim = (GLGENwindow *) LocalFree(pwndVictim);
return pwndVictim;
}
/******************************Public*Routine******************************\
*
* pwndCleanup
*
* Does all cleanup necessary for WNDOBJ destruction
*
* History:
* Mon Mar 18 17:30:49 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void APIENTRY pwndCleanup(GLGENwindow *pwndVictim)
{
GLGENwindow *pwnd, *pwndPrev;
__GLdrawablePrivate *dp;
#if DBG
ULONG ulLoops;
#endif
#ifdef DBG_WNDOBJ
DbgPrint("Clean WNDOBJ %p\n", pwndVictim);
#endif
EnterCriticalSection(&gwndHeader.sem);
// Search for victim. Maintain a prev pointer so we can do
// removal from linked list.
for (
pwndPrev = &gwndHeader, pwnd = pwndPrev->pNext;
pwnd != &gwndHeader;
pwndPrev = pwnd, pwnd = pwndPrev->pNext
)
{
if (pwnd == pwndVictim)
break;
}
// If victim was found, take it out.
if (pwnd == pwndVictim)
{
// Excise victim from linked list.
pwndPrev->pNext = pwnd->pNext;
}
LeaveCriticalSection(&gwndHeader.sem);
if (pwnd == NULL)
{
WARNING("pwndFree: pwndVictim not found in list\n");
return;
}
// If victim was found, it's out of the list so nobody
// new can get access to it.
// Wait for all current accessors to go away before cleaning up
// the WNDOBJ
#if DBG
ulLoops = 0;
#endif
for (;;)
{
if (pwndVictim->lUsers == 1)
{
break;
}
#if DBG
if (++ulLoops == 1000)
{
DbgPrint("Spinning on WNDOBJ %p\n", pwndVictim);
#ifdef DBG_WNDOBJ
DebugBreak();
#endif
}
#endif
// Wait on the critical section as a delay
// Acquiring it doesn't guarantee that we're the last
// accessor, but it does kill time in the case where
// another accessor is already holding it
EnterCriticalSection(&pwndVictim->sem);
LeaveCriticalSection(&pwndVictim->sem);
// Allow other threads time to run so we don't starve
// anybody while we're waiting
Sleep(0);
}
if (dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer)
{
wglCleanupWndobj((PVOID) &pwnd->wo);
if (dp->freePrivate)
dp->freePrivate(dp);
GenFree(dp);
}
if (pwndFree(pwndVictim))
WARNING("WNDOBJ deletion failed\n");
}
/******************************Public*Routine******************************\
* vCleanupWnd
*
* Removes and deletes all GLGENwindow structures from the linked list.
* Must *ONLY* be called from process detach (GLUnInitializeProcess).
*
* History:
* 25-Jul-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID APIENTRY vCleanupWnd()
{
GLGENwindow *pwndNext;
EnterCriticalSection(&gwndHeader.sem);
while ( gwndHeader.pNext != &gwndHeader )
{
pwndNext = gwndHeader.pNext->pNext;
pwndFree(gwndHeader.pNext);
gwndHeader.pNext = pwndNext;
}
LeaveCriticalSection(&gwndHeader.sem);
}
/******************************Public*Routine******************************\
* pwndGetFromHWND
*
* Finds the corresponding GLGENwindow for the given window handle.
*
* Returns:
* Pointer to GLGENwindow if sucessful; NULL otherwise.
*
* History:
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
GLGENwindow * APIENTRY pwndGetFromHWND(HWND hwnd)
{
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
GLGENwindow *pwnd = (GLGENwindow *) NULL;
EnterCriticalSection(&gwndHeader.sem);
{
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwnd->pNext)
if (pwnd->hwnd == hwnd)
{
pwndRet = pwnd;
InterlockedIncrement(&pwnd->lUsers);
break;
}
}
LeaveCriticalSection(&gwndHeader.sem);
#ifdef DBG_REFCOUNTS
if (pwndRet != 0)
{
DbgPrint("GetHWND %p to %d\n", pwndRet, pwndRet->lUsers);
}
#endif
return pwndRet;
}
/******************************Public*Routine******************************\
* pwndGetFromMemDC
*
* Finds the corresponding GLGENwindow for the given mem DC handle.
*
* Returns:
* Pointer to GLGENwindow if sucessful; NULL otherwise.
*
* History:
* 21-Jan-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
GLGENwindow *pwndGetFromMemDC(HDC hdcMem)
{
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
GLGENwindow *pwnd = (GLGENwindow *) NULL;
EnterCriticalSection(&gwndHeader.sem);
{
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwnd->pNext)
if (pwnd->hdc == hdcMem)
{
pwndRet = pwnd;
InterlockedIncrement(&pwndRet->lUsers);
break;
}
}
LeaveCriticalSection(&gwndHeader.sem);
#ifdef DBG_REFCOUNTS
if (pwndRet != 0)
{
DbgPrint("GetDC %p to %d\n", pwndRet, pwndRet->lUsers);
}
#endif
return pwndRet;
}
/******************************Public*Routine******************************\
* pwndGetFromDC
*
* Finds the corresponding GLGENwindow for the given DC handle.
*
* Returns:
* Pointer to GLGENwindow if sucessful; NULL otherwise.
*
* History:
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
GLGENwindow * APIENTRY pwndGetFromDC(HDC hdc)
{
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
HWND hwnd;
switch (wglObjectType(hdc))
{
case OBJ_DC:
hwnd = WindowFromDC(hdc);
if (hwnd == NULL)
{
pwndRet = pwndGetFromMemDC(hdc);
}
else
{
pwndRet = pwndGetFromHWND(hwnd);
}
break;
case OBJ_ENHMETADC:
case OBJ_MEMDC:
pwndRet = pwndGetFromMemDC(hdc);
break;
default:
WARNING("pwndGetFromDC(): bad hdc\n");
break;
}
return pwndRet;
}
/******************************Public*Routine******************************\
*
* pwndRelease
*
* Decrements the user count of a WNDOBJ
*
* History:
* Mon Mar 18 19:35:28 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#if DBG
void APIENTRY pwndRelease(GLGENwindow *pwnd)
{
ASSERTOPENGL(pwnd->lUsers > 0, "Decrement lUsers below zero\n");
InterlockedDecrement(&pwnd->lUsers);
#ifdef DBG_REFCOUNTS
DbgPrint("Release %p to %d\n", pwnd, pwnd->lUsers);
#endif
}
#endif
/******************************Public*Routine******************************\
*
* pwndUnlock
*
* Releases an owner of a WNDOBJ
*
* History:
* Mon Mar 18 17:25:56 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void APIENTRY pwndUnlock(GLGENwindow *pwnd)
{
ASSERTOPENGL(pwnd, "pwndUnlock: null pwnd\n");
LeaveCriticalSection(&pwnd->sem);
pwndRelease(pwnd);
}
/******************************Public*Routine******************************\
*
* wglValidateWndobjs
*
* Walks the WNDOBJ list and prunes away any DC-based WNDOBJs with
* invalid DCs. This is necessary because, unlike window-based
* WNDOBJs, we usually aren't notified when a memory DC goes away
* so if it has a WNDOBJ it just hangs around
*
* History:
* Thu May 02 17:44:23 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void APIENTRY wglValidateWndobjs(void)
{
GLGENwindow *pwnd, *pwndNext;
EnterCriticalSection(&gwndHeader.sem);
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwndNext)
{
pwndNext = pwnd->pNext;
if (pwnd->hdc != NULL && GetObjectType(pwnd->hdc) == 0)
{
// Increment so users count is one
InterlockedIncrement(&pwnd->lUsers);
pwndCleanup(pwnd);
}
}
LeaveCriticalSection(&gwndHeader.sem);
}
/******************************Public*Routine******************************\
* plyriGet
*
* Returns the GLGENlayerInfo for the specified layer plane from the pwnd.
* If it doesn't yet exist, the GLGENlayer and/or GLGENlayerInfo structure(s)
* are allocated.
*
* Returns:
* A non-NULL pointer if successful; NULL otherwise.
*
* History:
* 16-May-1996 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
GLGENlayerInfo * APIENTRY plyriGet(GLGENwindow *pwnd, HDC hdc, int iLayer)
{
GLGENlayerInfo *plyriRet = (GLGENlayerInfo * ) NULL;
GLGENlayerInfo **pplyri;
ASSERTOPENGL(pwnd, "plyriGet: bad pwnd\n");
// Allocate plyr if needed.
if (!pwnd->plyr)
{
pwnd->plyr = (GLGENlayers *) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT,
sizeof(GLGENlayers));
if (!pwnd->plyr)
{
WARNING("plyriGet: alloc failed (GLGENlayers)\n");
goto plyriGet_exit;
}
}
// Get info for the specified layer (positive values are overlay planes,
// negative values are underlay planes).
if (iLayer > 0)
pplyri = &pwnd->plyr->overlayInfo[iLayer - 1];
else if (iLayer < 1)
pplyri = &pwnd->plyr->underlayInfo[(-iLayer) - 1];
else
{
WARNING("plyriGet: no layer plane info for main plane!\n");
goto plyriGet_exit;
}
// Allocate plyri if needed.
if (!(*pplyri))
{
LAYERPLANEDESCRIPTOR lpd;
if (!wglDescribeLayerPlane(hdc, pwnd->ipfd, iLayer, sizeof(lpd), &lpd))
{
WARNING("plyriGet: wglDescribeLayerPlane failed\n");
goto plyriGet_exit;
}
*pplyri = (GLGENlayerInfo *)
LocalAlloc(LMEM_FIXED, (sizeof(COLORREF) * (1 << lpd.cColorBits))
+ sizeof(GLGENlayerInfo));
if (*pplyri)
{
int i;
// Initialize the new GLGENlayerInfo.
// Note that the palette is initialized with all white colors.
(*pplyri)->cPalEntries = 1 << lpd.cColorBits;
for (i = 0; i < (*pplyri)->cPalEntries; i++)
(*pplyri)->pPalEntries[i] = RGB(255, 255, 255);
}
else
{
WARNING("plyriGet: alloc failed (GLGENlayerInfo)\n");
goto plyriGet_exit;
}
}
// Success.
plyriRet = *pplyri;
plyriGet_exit:
return plyriRet;
}
/******************************Public*Routine******************************\
* wglDCIWndProc
*
* Handle size and palette changes for pixel formats that utilize DIB
* sections for rendering.
*
* History:
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
//!!!DCI
//!!!dbugBUGBUG
//!!!XXX -- if the only difference between DCI and DIB version is
// processing of WM_MOVE, combine them.
LRESULT CALLBACK
wglDCIWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
GLGENwindow *pwnd;
LRESULT lRet = 0;
WORD width, height;
pwnd = pwndGetFromHWND(hwnd);
if (pwnd)
{
__GLdrawablePrivate *dp = (__GLdrawablePrivate *) NULL;
__GLGENbuffers *buffers = (__GLGENbuffers *) NULL;
// Cache old WNDPROC because we may delete pwnd
WNDPROC pfnWndProc = pwnd->pfnOldWndProc;
// If WM_NCDESTROY, do OpenGL housekeeping after
// calling original WndProc.
// BUGBUG - We shouldn't really need this special case.
// It's present in order to allow apps to do things like
// wglDeleteContext in NCDESTROY which wouldn't work if
// we cleaned up the WNDOBJ before we passed on the message
// This used to be done in WM_DESTROY where apps do work,
// but now that it's on NCDESTROY it's much less likely that
// an app is doing anything. We preserved the old behavior
// for safety, though.
if (uiMsg == WM_NCDESTROY)
{
// Subclassing is supposed to be removed during NCDESTROY
// processing and order is important. Remove our
// subclassing before passing on the message.
pwndUnsubclass(pwnd);
if (pfnWndProc)
{
lRet = CallWindowProc(pfnWndProc, hwnd,
uiMsg, wParam, lParam);
}
}
// OpenGL housekeeping in response to windowing system messages.
switch (uiMsg)
{
case WM_SIZE:
width = LOWORD(lParam);
height = HIWORD(lParam);
EnterCriticalSection(&pwnd->sem);
{
pwnd->wo.rclClient.right = pwnd->wo.rclClient.left + width;
pwnd->wo.rclClient.bottom = pwnd->wo.rclClient.top + height;
pwnd->wo.coClient.rclBounds = pwnd->wo.rclClient;
if (dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer)
buffers = (__GLGENbuffers *)dp->data;
if (buffers)
{
buffers->WndUniq++;
buffers->WndSizeUniq++;
// Don't let it hit -1. -1 is special and is used by
// MakeCurrent to signal that an update is required
if (buffers->WndUniq == -1)
buffers->WndUniq = 0;
if (buffers->WndSizeUniq == -1)
buffers->WndSizeUniq = 0;
if (GLTEB_SRVCONTEXT())
UpdateWindowInfo((__GLGENcontext *)GLTEB_SRVCONTEXT());
}
}
LeaveCriticalSection(&pwnd->sem);
break;
case WM_MOVE:
EnterCriticalSection(&pwnd->sem);
{
WORD x = LOWORD(lParam);
WORD y = HIWORD(lParam);
width = (WORD) (pwnd->wo.rclClient.right - pwnd->wo.rclClient.left);
height = (WORD) (pwnd->wo.rclClient.bottom - pwnd->wo.rclClient.top);
ASSERTOPENGL(
(pwnd->wo.rclClient.right - pwnd->wo.rclClient.left) <= 0x0FFFF &&
(pwnd->wo.rclClient.bottom - pwnd->wo.rclClient.top) <= 0x0FFFF,
"wglDCIWndProc(): WM_MOVE - width/height overflow\n"
);
pwnd->wo.rclClient.left = x;
pwnd->wo.rclClient.right = x + width;
pwnd->wo.rclClient.top = y;
pwnd->wo.rclClient.bottom = y + height;
pwnd->wo.coClient.rclBounds = pwnd->wo.rclClient;
if (dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer)
buffers = (__GLGENbuffers *)dp->data;
if (buffers)
{
buffers->WndUniq++;
// Don't let it hit -1. -1 is special and is used by
// MakeCurrent to signal that an update is required
if (buffers->WndUniq == -1)
buffers->WndUniq = 0;
if (GLTEB_SRVCONTEXT())
UpdateWindowInfo((__GLGENcontext *)GLTEB_SRVCONTEXT());
}
}
LeaveCriticalSection(&pwnd->sem);
break;
case WM_PALETTECHANGED:
EnterCriticalSection(&pwnd->sem);
{
pwnd->ulPaletteUniq++;
if (GLTEB_SRVCONTEXT())
HandlePaletteChanges((__GLGENcontext *)GLTEB_SRVCONTEXT(), pwnd);
}
LeaveCriticalSection(&pwnd->sem);
break;
case WM_NCDESTROY:
pwndCleanup(pwnd);
// WM_NCDESTROY (and WM_DESTROY) are sent after the window has
// been removed from the screen. The window area is invalid
// but there is no API that allows us to dertermine that. This
// allows multithreaded drawing to draw on the screen area
// formerly occupied by the window. On Win95, DirectDraw does
// not force a repaint of the system when a window is destroyed.
// Therefore, if we are running multiple threads on Win95,
// we force a repaint of the desktop. Note that multithreaded
// does not mean that we are doing multithreaded drawing, but
// its a reasonable approximation.
if (WIN95_PLATFORM && (lThreadsAttached > 1))
{
InvalidateRect(NULL, NULL, FALSE);
}
return lRet;
default:
break;
}
// If !WM_NCDESTROY, do OpenGL housekeeping before calling original
// WndProc.
ASSERTOPENGL(uiMsg != WM_NCDESTROY,
"WM_NCDESTROY processing didn't terminate\n");
pwndRelease(pwnd);
if (pfnWndProc)
lRet = CallWindowProc(pfnWndProc, hwnd,
uiMsg, wParam, lParam);
}
return lRet;
}
/******************************Public*Routine******************************\
* wglDIBWndProc
*
* Handle size and palette changes for pixel formats that utilize DIB
* sections for rendering.
*
* History:
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
LRESULT CALLBACK
wglDIBWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
GLGENwindow *pwnd;
LRESULT lRet = 0;
WORD width, height;
pwnd = pwndGetFromHWND(hwnd);
if (pwnd)
{
__GLdrawablePrivate *dp = (__GLdrawablePrivate *) NULL;
__GLGENbuffers *buffers = (__GLGENbuffers *) NULL;
WNDPROC pfnWndProc = pwnd->pfnOldWndProc; // cache it because we may delete pwnd
// If WM_NCDESTROY, do OpenGL housekeeping after
// calling original WndProc.
// BUGBUG - See BUGBUG in wglDCIWndProc
if (uiMsg == WM_NCDESTROY)
{
// Subclassing is supposed to be removed during NCDESTROY
// processing and order is important. Remove our
// subclassing before passing on the message.
pwndUnsubclass(pwnd);
if (pfnWndProc)
{
lRet = CallWindowProc(pfnWndProc, hwnd,
uiMsg, wParam, lParam);
}
}
// OpenGL housekeeping in response to windowing system messages.
switch (uiMsg)
{
case WM_SIZE:
width = LOWORD(lParam);
height = HIWORD(lParam);
EnterCriticalSection(&pwnd->sem);
{
pwnd->wo.rclClient.right = pwnd->wo.rclClient.left + width;
pwnd->wo.rclClient.bottom = pwnd->wo.rclClient.top + height;
pwnd->wo.coClient.rclBounds = pwnd->wo.rclClient;
if (dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer)
buffers = (__GLGENbuffers *)dp->data;
if (buffers)
{
buffers->WndUniq++;
buffers->WndSizeUniq++;
// Don't let it hit -1. -1 is special and is used by
// MakeCurrent to signal that an update is required
if (buffers->WndUniq == -1)
buffers->WndUniq = 0;
if (buffers->WndSizeUniq == -1)
buffers->WndSizeUniq = 0;
if (GLTEB_SRVCONTEXT())
UpdateWindowInfo((__GLGENcontext *)GLTEB_SRVCONTEXT());
}
}
LeaveCriticalSection(&pwnd->sem);
break;
case WM_PALETTECHANGED:
EnterCriticalSection(&pwnd->sem);
{
pwnd->ulPaletteUniq++;
if (GLTEB_SRVCONTEXT())
HandlePaletteChanges((__GLGENcontext *)GLTEB_SRVCONTEXT(), pwnd);
}
LeaveCriticalSection(&pwnd->sem);
break;
case WM_NCDESTROY:
pwndCleanup(pwnd);
// WM_NCDESTROY (and WM_DESTROY) are sent after the window has
// been removed from the screen. The window area is invalid
// but there is no API that allows us to dertermine that. This
// allows multithreaded drawing to draw on the screen area
// formerly occupied by the window. On Win95, DirectDraw does
// not force a repaint of the system when a window is destroyed.
// Therefore, if we are running multiple threads on Win95,
// we force a repaint of the desktop. Note that multithreaded
// does not mean that we are doing multithreaded drawing, but
// its a reasonable approximation.
if (WIN95_PLATFORM && (lThreadsAttached > 1))
{
InvalidateRect(NULL, NULL, FALSE);
}
return lRet;
default:
break;
}
// If !WM_NCDESTROY, do OpenGL housekeeping before calling original WndProc.
ASSERTOPENGL(uiMsg != WM_NCDESTROY,
"WM_NCDESTROY processing didn't terminate\n");
pwndRelease(pwnd);
if (pfnWndProc)
lRet = CallWindowProc(pfnWndProc, hwnd,
uiMsg, wParam, lParam);
}
return lRet;
}
/******************************Public*Routine******************************\
* wglGetPixelFormat
*
* Get the pixel format for the window or surface associated with the given
* DC.
*
* Returns:
* 0 if error or no pixel format was previously set in the window or
* surface; current pixel format index otherwise
*
* History:
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
int WINAPI wglGetPixelFormat(HDC hdc)
{
GLGENwindow *pwnd;
int iRet = 0;
pwnd = pwndGetFromDC(hdc);
if (pwnd)
{
iRet = pwnd->ipfd;
pwndRelease(pwnd);
}
else
{
#if 0
// Too noisy for normal operation
WARNING("wglGetPixelFormat: No WNDOBJ for DC\n");
#endif
SAVE_ERROR_CODE(ERROR_INVALID_PIXEL_FORMAT);
}
return iRet;
}
/*****************************Private*Routine******************************\
*
* EnterPixelFormatSection
*
* Enters pixel format exclusive code
*
* BUGBUG - Pixel format information is maintained in the client process
* so it is not synchronized between processes. This means that two
* processes could successfully set the pixel format for a window.
* If the list becomes global, this synchronization code should also become
* cross-process aware.
*
* History:
* Mon Jun 26 17:49:04 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#define EnterPixelFormatSection() \
(EnterCriticalSection(&gcsPixelFormat), TRUE)
/*****************************Private*Routine******************************\
*
* LeavePixelFormatSection
*
* Leaves pixel format exclusive code
*
* History:
* Mon Jun 26 17:55:20 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#define LeavePixelFormatSection() \
LeaveCriticalSection(&gcsPixelFormat)
/******************************Public*Routine******************************\
* wglNumHardwareFormats
*
* Returns the number of hardware formats (ICD and MCD), supported on the
* specified hdc.
*
* History:
* 17-Apr-1996 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
VOID wglNumHardwareFormats(HDC hdc, DWORD dwType, int *piMcd, int *piIcd)
{
// It is assumed that the caller has already validated the DC.
ASSERTOPENGL((dwType == OBJ_DC) ||
(dwType == OBJ_MEMDC) ||
(dwType == OBJ_ENHMETADC),
"wglNumHardwareFormats: bad hdc\n");
// Do not call MCD or ICD for enhanced metafile DCs. In such a
// case, the code in ntgdi\client\output.c will return a non-zero value
// even if there are no ICD or MCD pixelformats.
if ( dwType == OBJ_ENHMETADC )
{
// It's a metafile DC. Therefore it cannot support MCD or ICD
// (current OpenGL metafiling support would have to be modified
// to allow this).
*piIcd = 0;
*piMcd = 0;
}
else
{
// Get ICD pixelformat count.
*piIcd = __DrvDescribePixelFormat(hdc, 1, 0, NULL);
// Get MCD pixelformat count.
#ifdef _MCD_
if ( gpMcdTable || bInitMcd(hdc) )
*piMcd = (gpMcdTable->pMCDDescribePixelFormat)(hdc, 1, NULL);
else
*piMcd = 0;
#else
*piMcd = 0;
#endif
}
}
/******************************Public*Routine******************************\
*
* PaletteWatcherProc
*
* Window proc for the palette watcher
*
* History:
* Mon Oct 14 15:29:10 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
LRESULT WINAPI PaletteWatcherProc(HWND hwnd, UINT uiMsg,
WPARAM wpm, LPARAM lpm)
{
switch(uiMsg)
{
case WM_PALETTECHANGED:
InterlockedIncrement((LONG *)&ulPaletteWatcherCount);
return 0;
default:
return DefWindowProc(hwnd, uiMsg, wpm, lpm);
}
}
/******************************Public*Routine******************************\
*
* PaletteWatcher
*
* Thread routine for the palette change monitor. Creates a hidden
* top level window and looks for WM_PALETTECHANGED.
*
* History:
* Mon Oct 14 15:16:02 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD WINAPI PaletteWatcher(LPVOID pvArg)
{
HWND hwnd;
hwnd = CreateWindow(PALETTE_WATCHER_CLASS,
PALETTE_WATCHER_CLASS,
WS_OVERLAPPED,
0, 0, 1, 1,
NULL,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL);
if (hwnd != NULL)
{
hwndPaletteWatcher = hwnd;
for (;;)
{
MSG msg;
if (GetMessage(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
break;
}
}
DestroyWindow(hwnd);
}
EnterCriticalSection(&gcsPaletteWatcher);
// Some kind of problem occurred or this thread is dying.
// Indicate that this thread is going away and that a
// new watcher needs to be created.
if (tidPaletteWatcherThread == GetCurrentThreadId())
{
tidPaletteWatcherThread = 0;
}
LeaveCriticalSection(&gcsPaletteWatcher);
return 0;
}
/******************************Public*Routine******************************\
*
* StartPaletteWatcher
*
* Spins up a thread to watch for palette change events
*
* History:
* Mon Oct 14 15:11:35 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL StartPaletteWatcher(void)
{
BOOL bRet;
EnterCriticalSection(&gcsPaletteWatcher);
bRet = FALSE;
if (tidPaletteWatcherThread == 0)
{
HANDLE h;
if (aPaletteWatcherClass == 0)
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = PaletteWatcherProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = PALETTE_WATCHER_CLASS;
aPaletteWatcherClass = RegisterClass(&wc);
}
if (aPaletteWatcherClass != 0)
{
h = CreateThread(NULL, 4096, PaletteWatcher,
NULL, 0, &tidPaletteWatcherThread);
if (h != NULL)
{
CloseHandle(h);
bRet = TRUE;
}
}
}
else
{
bRet = TRUE;
}
if (bRet)
{
lPaletteWatcherUsers++;
}
LeaveCriticalSection(&gcsPaletteWatcher);
return bRet;
}
/******************************Public*Routine******************************\
* wglSetPixelFormat
*
* Set the pixel format for the window or surface associated with the given
* DC.
*
* Note:
* Since the pixel format is per-window data (per-DC for non-display DCs), a
* side effect of this call is to create a GLGENwindow structure.
*
* Note:
* For an installable client driver, a GLGENwindow structure is still created
* to track the pixel format and the driver structure (GLDRIVER).
*
* History:
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL WINAPI wglSetPixelFormat(HDC hdc, int ipfd,
CONST PIXELFORMATDESCRIPTOR *ppfd)
{
GLGENwindow *pwnd = NULL;
int ipfdDevMax, ipfdMcdMax;
DWORD dwType;
BOOL bRet = FALSE;
GLGENwindow wndInit;
//DBGPRINT1("wglSetPixelFormat: ipfd = %ld\n", ipfd);
// Validate DC.
switch (dwType = wglObjectType(hdc))
{
case OBJ_DC:
case OBJ_MEMDC:
case OBJ_ENHMETADC:
break;
default:
WARNING1("wglSetPixelFormat: Attempt to set format of %d type DC\n",
dwType);
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
// Take the pixel format mutex
if (!EnterPixelFormatSection())
{
WARNING("wglSetPixelFormat: Unable to take pixel format mutex\n");
return FALSE;
}
// Get the number of hardware supported formats.
{
HDC hdcTmp = (HDC) NULL;
HDC hdcDriver;
int iTech;
// Cannot call driver (which wglNumHardwareFormats will do) with a mem DC.
// If specified HDC is a memory DC, we must temporarily get a display DC
// with which to call wglNumHardwareFormats.
hdcDriver = hdc;
iTech = GetDeviceCaps(hdc, TECHNOLOGY);
if ((dwType == OBJ_MEMDC) && (iTech != DT_PLOTTER) &&
(iTech != DT_RASPRINTER))
{
if (hdcTmp = GetDC((HWND) NULL))
hdcDriver = hdcTmp;
}
wglNumHardwareFormats(hdcDriver, dwType, &ipfdMcdMax, &ipfdDevMax);
if (hdcTmp)
ReleaseDC((HWND) NULL, hdcTmp);
}
// Filter out invalid (out of range) pixel format indices.
if ( (ipfd < 1) || (ipfd > (ipfdDevMax + ipfdMcdMax + MAX_GENERIC_PFD)) )
{
WARNING1("wglSetPixelFormat: ipfd %d out of range\n", ipfd);
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
goto LeaveSection;
}
// If it exists, grab pwnd. Otherwise, create one.
pwnd = pwndGetFromDC(hdc);
if ( !pwnd )
{
memset((void *) &wndInit, 0, sizeof(GLGENwindow));
if ( dwType == OBJ_DC )
{
wndInit.hwnd = WindowFromDC(hdc);
if (wndInit.hwnd == NULL)
{
wndInit.hdc = hdc;
}
else
{
wndInit.hdc = (HDC) 0;
}
}
else
{
wndInit.hwnd = (HWND) 0;
wndInit.hdc = hdc;
}
wndInit.ipfd = ipfd;
wndInit.ipfdDevMax = ipfdDevMax;
//!!!client driver
//!!!dbug -- Move SetWindowLong call to pwndNew?!? Maybe move
//!!!dbug everything from this if.. clause to pwndNew?!?
if ( wndInit.hwnd )
{
DWORD dwPid;
if (GetWindowThreadProcessId(wndInit.hwnd,
&dwPid) == 0xffffffff)
{
goto LeaveSection;
}
if (dwPid == GetCurrentProcessId())
{
if ( GLDCIENABLED )
wndInit.pfnOldWndProc =
(WNDPROC) SetWindowLong(
wndInit.hwnd,
GWL_WNDPROC,
(LONG) wglDCIWndProc
);
else
wndInit.pfnOldWndProc =
(WNDPROC) SetWindowLong(
wndInit.hwnd,
GWL_WNDPROC,
(LONG) wglDIBWndProc
);
}
else
{
wndInit.ulFlags |= GLGENWIN_OTHERPROCESS;
// Start a thread to watch for palette changes
if (!StartPaletteWatcher())
{
goto LeaveSection;
}
}
// Get *SCREEN* coordinates of client rectangle.
GetClientRect(wndInit.hwnd, (LPRECT) &wndInit.wo.rclClient);
ClientToScreen(wndInit.hwnd, (LPPOINT) &wndInit.wo.rclClient);
wndInit.wo.rclClient.right += wndInit.wo.rclClient.left;
wndInit.wo.rclClient.bottom += wndInit.wo.rclClient.top;
}
else if (dwType == OBJ_DC)
{
// A direct DC without a window is treated like a DFB
wndInit.wo.rclClient.left = 0;
wndInit.wo.rclClient.top = 0;
wndInit.wo.rclClient.right = GetDeviceCaps(hdc, HORZRES);
wndInit.wo.rclClient.bottom = GetDeviceCaps(hdc, VERTRES);
}
else if (dwType == OBJ_MEMDC)
{
DIBSECTION bmi;
// Get bitmap dimensions.
if ( !GetObject(GetCurrentObject(hdc, OBJ_BITMAP),
sizeof(DIBSECTION), (LPVOID) &bmi) )
{
WARNING("wglSetPixelFormat(): GetObject failed\n");
goto LeaveSection;
}
wndInit.wo.rclClient.left = 0;
wndInit.wo.rclClient.top = 0;
wndInit.wo.rclClient.right = bmi.dsBm.bmWidth;
wndInit.wo.rclClient.bottom = abs(bmi.dsBm.bmHeight);
}
else
{
ASSERTOPENGL(dwType == OBJ_ENHMETADC,
"Bad dwType in SetPixelFormat\n");
// Initialize metafile DC's to have no size so all output
// is clipped. This is good because there's no surface
// to draw on
wndInit.wo.rclClient.left = 0;
wndInit.wo.rclClient.top = 0;
wndInit.wo.rclClient.right = 0;
wndInit.wo.rclClient.bottom = 0;
}
wndInit.wo.coClient.rclBounds = wndInit.wo.rclClient;
wndInit.wo.coClient.iDComplexity = DC_TRIVIAL;
wndInit.wo.coClient.iFComplexity = FC_RECT;
wndInit.wo.coClient.iMode = TC_RECTANGLES;
pwnd = pwndNew(&wndInit);
if (pwnd == (GLGENwindow *) NULL)
{
WARNING("wglSetPixelFormat: Unable to allocate new WNDOBJ\n");
goto RestoreWndProc;
}
// Dispatch driver formats.
// Driver is responsible for doing its own validation of the pixelformat.
// For generic formats, we call wglValidPixelFormat to validate.
if (ipfd <= ipfdDevMax)
{
bRet = __DrvSetPixelFormat(hdc, ipfd, (PVOID) pwnd);
#if DBG
if (!bRet)
{
WARNING("__DrvSetPixelFormat failed\n");
}
#endif
}
else
{
bRet = wglValidPixelFormat(hdc, ipfd);
#if DBG
if (!bRet)
{
WARNING("wglValidPixelFormat failed\n");
}
#endif
}
// If the pixel format is not valid or could not be set in the driver,
// cleanup and return error.
if (!bRet)
{
goto FreeWnd;
}
}
else
{
// If the given pixel format is the same as the previous one, return
// success. Otherwise, as the pixel format can be set only once,
// return error.
if ( pwnd->ipfd == ipfd )
{
bRet = TRUE;
}
else
{
WARNING("wglSetPixelFormat: Attempt to set pixel format twice\n");
SAVE_ERROR_CODE(ERROR_INVALID_PIXEL_FORMAT);
}
}
pwndRelease(pwnd);
LeaveSection:
LeavePixelFormatSection();
return bRet;
FreeWnd:
pwndCleanup(pwnd);
goto LeaveSection;
RestoreWndProc:
pwndUnsubclass(&wndInit);
goto LeaveSection;
}
/******************************Public*Routine******************************\
* wglChoosePixelFormat
*
* Choose the pixel format.
*
* Returns: 0 if error; best matching pixel format index otherwise
*
* History:
*
* Sat Feb 10 11:55:22 1996 -by- Hock San Lee [hockl]
* Chose generic 16-bit depth buffer over 32-bit depth buffer.
* Added PFD_DEPTH_DONTCARE flag.
*
* 19-Oct-1994 Gilman Wong [gilmanw]
* Taken from GreChoosePixelFormat (gdi\gre\pixelfmt.cxx).
*
* History for gdi\gre\pixelfmt.cxx:
* Tue Sep 21 14:25:04 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
// Reserve some PFD_SUPPORT flags for other potential graphics systems
// such as PEX, HOOPS, Renderman etc.
#define PFD_SUPPORT_OTHER1 0x01000000
#define PFD_SUPPORT_OTHER2 0x02000000
#define PFD_SUPPORT_OTHER3 0x04000000
#define PFD_SUPPORT_OTHER4 0x08000000
// Scores for matching pixel formats
#define PFD_DRAW_TO_WINDOW_SCORE 0x10000 /* must match */
#define PFD_DRAW_TO_BITMAP_SCORE 0x01000
#define PFD_PIXEL_TYPE_SCORE 0x01000
#define PFD_SUPPORT_SCORE 0x01000
#define PFD_DOUBLEBUFFER_SCORE1 0x01000
#define PFD_DOUBLEBUFFER_SCORE2 0x00001
#define PFD_STEREO_SCORE1 0x01000
#define PFD_STEREO_SCORE2 0x00001
#define PFD_BUFFER_SCORE1 0x01010
#define PFD_BUFFER_SCORE2 0x01001
#define PFD_BUFFER_SCORE3 0x01000
// #define PFD_LAYER_TYPE_SCORE 0x01000
#define PFD_DEVICE_FORMAT_SCORE 0x00100
#define PFD_ACCEL_FORMAT_SCORE 0x00010
//!!! Add code to choose overlays?
int WINAPI wglChoosePixelFormat(HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd)
{
PIXELFORMATDESCRIPTOR pfdIn = *ppfd;
PIXELFORMATDESCRIPTOR pfdCurrent;
// Enumerate and find the best match.
int ipfdBest = 1; // assume the default is the best
int iScoreBest = -1;
int ipfdMax;
int ipfd = 1;
do
{
int iScore = 0;
ipfdMax = wglDescribePixelFormat(hdc,ipfd,sizeof(PIXELFORMATDESCRIPTOR),&pfdCurrent);
if (ipfdMax == 0)
return(0); // something went wrong
if (pfdIn.iPixelType == pfdCurrent.iPixelType)
iScore += PFD_PIXEL_TYPE_SCORE;
if ((pfdIn.cColorBits == 0)
|| (pfdIn.cColorBits == pfdCurrent.cColorBits))
iScore += PFD_BUFFER_SCORE1;
else if (pfdIn.cColorBits < pfdCurrent.cColorBits)
iScore += PFD_BUFFER_SCORE2;
else if (pfdCurrent.cColorBits != 0)
iScore += PFD_BUFFER_SCORE3;
if (!(pfdIn.dwFlags & PFD_DRAW_TO_WINDOW)
|| (pfdCurrent.dwFlags & PFD_DRAW_TO_WINDOW))
iScore += PFD_DRAW_TO_WINDOW_SCORE;
if (!(pfdIn.dwFlags & PFD_DRAW_TO_BITMAP)
|| (pfdCurrent.dwFlags & PFD_DRAW_TO_BITMAP))
iScore += PFD_DRAW_TO_BITMAP_SCORE;
if (!(pfdIn.dwFlags & PFD_SUPPORT_GDI)
|| (pfdCurrent.dwFlags & PFD_SUPPORT_GDI))
iScore += PFD_SUPPORT_SCORE;
if (!(pfdIn.dwFlags & PFD_SUPPORT_OPENGL)
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OPENGL))
iScore += PFD_SUPPORT_SCORE;
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER1)
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER1))
iScore += PFD_SUPPORT_SCORE;
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER2)
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER2))
iScore += PFD_SUPPORT_SCORE;
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER3)
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER3))
iScore += PFD_SUPPORT_SCORE;
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER4)
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER4))
iScore += PFD_SUPPORT_SCORE;
if (!(pfdCurrent.dwFlags & PFD_GENERIC_FORMAT))
iScore += PFD_DEVICE_FORMAT_SCORE;
#ifdef _MCD_
else if (pfdCurrent.dwFlags & PFD_GENERIC_ACCELERATED)
iScore += PFD_ACCEL_FORMAT_SCORE;
#endif
if ((pfdIn.dwFlags & PFD_DOUBLEBUFFER_DONTCARE)
|| ((pfdIn.dwFlags & PFD_DOUBLEBUFFER)
== (pfdCurrent.dwFlags & PFD_DOUBLEBUFFER)))
iScore += PFD_DOUBLEBUFFER_SCORE1;
else if (pfdCurrent.dwFlags & PFD_DOUBLEBUFFER)
iScore += PFD_DOUBLEBUFFER_SCORE2;
if ((pfdIn.dwFlags & PFD_STEREO_DONTCARE)
|| ((pfdIn.dwFlags & PFD_STEREO)
== (pfdCurrent.dwFlags & PFD_STEREO)))
iScore += PFD_STEREO_SCORE1;
else if (pfdCurrent.dwFlags & PFD_STEREO)
iScore += PFD_STEREO_SCORE2;
if ((pfdIn.cAlphaBits == 0)
|| (pfdIn.cAlphaBits == pfdCurrent.cAlphaBits))
iScore += PFD_BUFFER_SCORE1;
else if (pfdIn.cAlphaBits < pfdCurrent.cAlphaBits)
iScore += PFD_BUFFER_SCORE2;
else if (pfdCurrent.cAlphaBits != 0)
iScore += PFD_BUFFER_SCORE3;
if ((pfdIn.cAccumBits == 0)
|| (pfdIn.cAccumBits == pfdCurrent.cAccumBits))
iScore += PFD_BUFFER_SCORE1;
else if (pfdIn.cAccumBits < pfdCurrent.cAccumBits)
iScore += PFD_BUFFER_SCORE2;
else if (pfdCurrent.cAccumBits != 0)
iScore += PFD_BUFFER_SCORE3;
// Some applications (e.g. GLview browser) specifies a 0-bit depth buffer
// but expect this function to return a pixel format with a depth buffer.
// This works in NT 3.51 since all pixel formats have a depth buffer.
// When pixel formats with no depth buffer were added in NT 4.0, these
// applications stopped working. The flag PFD_DEPTH_DONTCARE is added to
// indicate that no depth buffer is required. If this flags is not given,
// this function will attempt to select a pixel format with a depth buffer.
if (pfdIn.dwFlags & PFD_DEPTH_DONTCARE)
{
if (pfdCurrent.cDepthBits == 0)
iScore += PFD_BUFFER_SCORE1;
else
iScore += PFD_BUFFER_SCORE2;
}
else if (pfdCurrent.cDepthBits != 0)
{
if ((pfdIn.cDepthBits == 0)
|| (pfdIn.cDepthBits == pfdCurrent.cDepthBits))
iScore += PFD_BUFFER_SCORE1;
else if (pfdIn.cDepthBits < pfdCurrent.cDepthBits)
iScore += PFD_BUFFER_SCORE2;
else if (pfdCurrent.cDepthBits != 0)
iScore += PFD_BUFFER_SCORE3;
}
if ((pfdIn.cStencilBits == 0)
|| (pfdIn.cStencilBits == pfdCurrent.cStencilBits))
iScore += PFD_BUFFER_SCORE1;
else if (pfdIn.cStencilBits < pfdCurrent.cStencilBits)
iScore += PFD_BUFFER_SCORE2;
else if (pfdCurrent.cStencilBits != 0)
iScore += PFD_BUFFER_SCORE3;
if ((pfdIn.cAuxBuffers == 0)
|| (pfdIn.cAuxBuffers == pfdCurrent.cAuxBuffers))
iScore += PFD_BUFFER_SCORE1;
else if (pfdIn.cAuxBuffers < pfdCurrent.cAuxBuffers)
iScore += PFD_BUFFER_SCORE2;
else if (pfdCurrent.cAuxBuffers != 0)
iScore += PFD_BUFFER_SCORE3;
if (iScore > iScoreBest)
{
iScoreBest = iScore;
ipfdBest = ipfd;
}
else if (iScore == iScoreBest)
{
// When everything is equal, we should choose the pixel format with a
// smaller depth size for better performance, provided that the smaller
// depth buffer satisfies the request. The best way to do this is to
// order pixel formats such that one with smaller depth buffer comes
// first. In NT 3.51, however, the generic pixel format was not ordered
// this way. As a result, pixel formats with 32-bit depth buffer are
// choosen by default. To maintain compatibility, we modify the selection
// here without reordering generic pixel formats.
if ((pfdCurrent.dwFlags & PFD_GENERIC_FORMAT) &&
#ifdef _MCD_
!(pfdCurrent.dwFlags & PFD_GENERIC_ACCELERATED) &&
#endif
(pfdIn.cDepthBits < 16 || pfdIn.dwFlags & PFD_DEPTH_DONTCARE) &&
(pfdCurrent.cDepthBits == 16) &&
(ipfd == ipfdBest + 1))
{
ipfdBest = ipfd;
}
}
ipfd++;
} while (ipfd <= ipfdMax);
return(ipfdBest);
}
/*****************************Private*Routine******************************\
*
* ComputeBitsFromMasks
*
* Determines the values for c*Bits and c*Shift from BI_BITFIELD
* channel masks
*
* History:
* Tue Feb 14 10:50:10 1995 -by- Drew Bliss [drewb]
* Created by pulling out duplicated code
*
\**************************************************************************/
static void ComputeBitsFromMasks(PIXELFORMATDESCRIPTOR *ppfd,
DWORD *pdwMasks)
{
DWORD fl;
/* Masks can't be zero and they can't overlap */
ASSERTOPENGL(pdwMasks[0] != 0 &&
pdwMasks[1] != 0 &&
pdwMasks[2] != 0,
"Bitfield mask is zero");
ASSERTOPENGL((pdwMasks[0] & pdwMasks[1]) == 0 &&
(pdwMasks[0] & pdwMasks[2]) == 0 &&
(pdwMasks[1] & pdwMasks[2]) == 0,
"Bitfield masks overlap");
ppfd->cRedBits = ppfd->cGreenBits = ppfd->cBlueBits = 0;
ppfd->cRedShift = ppfd->cGreenShift = ppfd->cBlueShift = 0;
/* First mask is for red */
/* Determine first set bit and accumulate shift count */
fl = 0x1;
while ((*pdwMasks & fl) == 0)
{
fl <<= 1;
ppfd->cRedShift++;
}
/* Count set bits */
while ((*pdwMasks & fl) != 0)
{
fl <<= 1;
ppfd->cRedBits++;
}
/* No other bits in the mask can be set */
ASSERTOPENGL(((ppfd->cRedShift+ppfd->cRedBits) == (sizeof(*pdwMasks) * 8)) ||
((*pdwMasks >> (ppfd->cRedShift+ppfd->cRedBits)) == 0),
"Invalid red mask");
/* Second mask is for green */
pdwMasks++;
/* Determine first set bit and accumulate shift count */
fl = 0x1;
while ((*pdwMasks & fl) == 0)
{
fl <<= 1;
ppfd->cGreenShift++;
}
/* Count set bits */
while ((*pdwMasks & fl) != 0)
{
fl <<= 1;
ppfd->cGreenBits++;
}
/* No other bits in the mask can be set */
ASSERTOPENGL(((ppfd->cGreenShift+ppfd->cGreenBits) == (sizeof(*pdwMasks) * 8)) ||
((*pdwMasks >> (ppfd->cGreenShift+ppfd->cGreenBits)) == 0),
"Invalid green mask");
/* Third mask is for blue */
pdwMasks++;
/* Determine first set bit and accumulate shift count */
fl = 0x1;
while ((*pdwMasks & fl) == 0)
{
fl <<= 1;
ppfd->cBlueShift++;
}
/* Count set bits */
while ((*pdwMasks & fl) != 0)
{
fl <<= 1;
ppfd->cBlueBits++;
}
/* No other bits in the mask can be set */
ASSERTOPENGL(((ppfd->cBlueShift+ppfd->cBlueBits) == (sizeof(*pdwMasks) * 8)) ||
((*pdwMasks >> (ppfd->cBlueShift+ppfd->cBlueBits)) == 0),
"Invalid red mask");
}
/******************************Public*Routine******************************\
* __wglGetDCIFormat
*
* Special case of __wglGetBitfieldColorFormat to support DCI primary
* surfaces. Fills in the cRedBits, cRedShift, cGreenBits, etc. fields
* of the PIXELFORMATDESCRIPTOR for 16, 24, and 32bpp DCI surfaces.
*
* This is done by interpreting the information in the DCISURFACEINFO
* structure returned by DCICreatePrimary (see client\dllinit.c).
*
* Returns:
* TRUE if successful, FALSE otherwise.
*
* History:
* 07-Jun-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL __wglGetDCIFormat(LPDCISURFACEINFO pDCISurfInfo, UINT cColorBits,
PIXELFORMATDESCRIPTOR *ppfd)
{
BOOL bRet = FALSE;
switch (pDCISurfInfo->dwCompression)
{
case BI_RGB: // default DIB format
#if DBG
// Dynamic color depth changes can cause this. It will not cause us to crash,
// but drawing (color) may be incorrect.
if (cColorBits != pDCISurfInfo->dwBitCount)
{
WARNING("__wglGetDCIFormat(): BI_RGB surface not 24bpp\n");
}
#endif
switch (pDCISurfInfo->dwBitCount)
{
case 16:
// 16bpp default is 555 BGR-ordering
ppfd->cRedBits = 5; ppfd->cRedShift = 10;
ppfd->cGreenBits = 5; ppfd->cGreenShift = 5;
ppfd->cBlueBits = 5; ppfd->cBlueShift = 0;
bRet = TRUE;
break;
case 24:
case 32:
// 24 and 32bpp default is 888 BGR-ordering
ppfd->cRedBits = 8; ppfd->cRedShift = 16;
ppfd->cGreenBits = 8; ppfd->cGreenShift = 8;
ppfd->cBlueBits = 8; ppfd->cBlueShift = 0;
bRet = TRUE;
break;
default:
break;
}
break;
case BI_BITFIELDS: // non-standard format, must extract from masks
// Some drivers seem to return bitfields for everything that's
// not paletted. They return correct BGR bitfields so we
// operate correctly, so remove this assert
#ifdef STRICT_BITFIELD_CHECK
ASSERTOPENGL(
cColorBits == 16 || cColorBits == 32,
"__wglGetDCIFormat(): BI_BITFIELDS surface not 16 or 32bpp\n"
);
#endif
ComputeBitsFromMasks(ppfd, &pDCISurfInfo->dwMask[0]);
bRet = TRUE;
break;
default:
RIP("__wglGetDCIFormat(): bad biCompression\n");
break;
}
return bRet;
}
/******************************Public*Routine******************************\
*
* wglIsDCIDevice
*
* Checks to see whether the given DC is a screen DC on the
* surface for which we have DCI information
*
* History:
* Fri Apr 19 15:17:30 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL wglIsDCIDevice(HDC hdc)
{
if (wglObjectType(hdc) != OBJ_DC)
{
return FALSE;
}
// BUGBUG - What about multiple displays?
return GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY;
}
/******************************Public*Routine******************************\
* __wglGetBitfieldColorFormat
*
* Fills in the cRedBits, cRedShift, cGreenBits, etc. fields of the
* PIXELFORMATDESCRIPTOR for 16, 24, and 32bpp surfaces (either device
* or bitmap surfaces).
*
* This is done by creating a compatible bitmap and calling GetDIBits
* to return the color masks. This is done with two calls. The first
* call passes in biBitCount = 0 to GetDIBits which will fill in the
* base BITMAPINFOHEADER data. The second call to GetDIBits (passing
* in the BITMAPINFO filled in by the first call) will return the color
* table or bitmasks, as appropriate.
*
* This function is used to describe the color format for both the underlying
* surface and for the device. This is the same thing if the DC is a
* display DC. However, for a memory DC, the surface and the device may have
* different formats. The bDescribeSurf flag indicates whether the caller
* wants the decription of the device (FALSE) or the surface (TRUE).
*
* Returns:
* TRUE if successful, FALSE otherwise.
*
* History:
* 07-Jun-1995 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL
__wglGetBitfieldColorFormat(HDC hdc, UINT cColorBits, PIXELFORMATDESCRIPTOR *ppfd,
BOOL bDescribeSurf)
{
HBITMAP hbm = (HBITMAP) NULL;
BOOL bRet = FALSE;
int iTech;
DWORD dwObjectType;
HDC hdcTmp = (HDC) NULL;
#if DBG
// Dynamic color depth changes can cause this. It will not cause us to crash,
// but drawing (color) may be incorrect.
if ((GetObjectType(hdc) == OBJ_DC) &&
(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
{
WARNING("Palette managed device that is greater than 8 bits\n");
}
if (cColorBits < 16)
{
WARNING("__wglGetBitfieldColorFormat with cColorBits < 16\n");
}
#endif
// Handle DCI case.
if ( GLDCIENABLED && wglIsDCIDevice(hdc) )
return __wglGetDCIFormat(GLDCIINFO->pDCISurfInfo, cColorBits, ppfd);
// Create a dummy bitmap from which we can query color format info.
//
// If we want a device format AND its a MEM_DC AND NOT a printer or plotter,
// then we need to create a compatible bitmap from a display DC (not the mem
// DC passed into this function).
//
// Otherwise, the format of the surface (whether bitmap or device) associated
// with the DC passed in will suffice.
iTech = GetDeviceCaps(hdc, TECHNOLOGY);
dwObjectType = wglObjectType(hdc);
if ( (!bDescribeSurf) && (dwObjectType == OBJ_MEMDC) &&
!(iTech == DT_PLOTTER || iTech == DT_RASPRINTER) )
{
if ( hdcTmp = GetDC((HWND) NULL) )
{
hbm = CreateCompatibleBitmap(hdcTmp, 1, 1);
if ( hbm )
{
// WinNT does not care, but the Win95 GetDIBits call might
// fail if we use a memory DC. Specifically, if the memory
// DC contains a surface that does not match the display
// (remember, the new bitmap is compatible with the display)
// the Win95 GetDIBits call will fail.
//
// So use the display DC. It works on both platforms.
hdc = hdcTmp;
}
else
{
WARNING("__wglGetBitfieldColorFormat: CreateCompatibleBitmap failed [1]\n");
}
}
else
{
WARNING("__wglGetBitfieldColorFormat: GetDC failed\n");
}
}
else
{
hbm = CreateCompatibleBitmap(hdc, 1, 1);
if ( !hbm )
{
WARNING("__wglGetBitfieldColorFormat: CreateCompatibleBitmap failed [2]\n");
}
}
// Get the color format by calling GetDIBits.
if ( hbm )
{
BYTE ajBitmapInfo[sizeof(BITMAPINFO) + 3*sizeof(DWORD)];
BITMAPINFO *pbmi = (BITMAPINFO *) ajBitmapInfo;
int iRet;
//!!!dbug -- Init masks to zero so we can
// tell if they are set by GetDIBits.
memset(pbmi, 0, sizeof(ajBitmapInfo));
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// Call first time to fill in BITMAPINFO header.
iRet = GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
#if DBG
if (pbmi->bmiHeader.biBitCount != cColorBits)
WARNING2("__wglGetBitfieldColorFormat: bit count != BITSPIXEL "
" (%ld, %ld)\n", pbmi->bmiHeader.biBitCount, cColorBits);
#endif
switch ( pbmi->bmiHeader.biCompression )
{
case BI_RGB:
#if DBG
// Dynamic color depth changes can cause this. It will not cause
// us to crash, but drawing (color) may be incorrect.
if (pbmi->bmiHeader.biBitCount != cColorBits)
{
WARNING("__wglGetBitfieldColorFormat(): bit count mismatch\n");
}
#endif
// Default DIB format. Color masks are implicit for each bit depth.
switch ( pbmi->bmiHeader.biBitCount )
{
case 16:
// 16bpp default is 555 BGR-ordering
ppfd->cRedBits = 5; ppfd->cRedShift = 10;
ppfd->cGreenBits = 5; ppfd->cGreenShift = 5;
ppfd->cBlueBits = 5; ppfd->cBlueShift = 0;
bRet = TRUE;
break;
case 24:
case 32:
// 24 and 32bpp default is 888 BGR-ordering
ppfd->cRedBits = 8; ppfd->cRedShift = 16;
ppfd->cGreenBits = 8; ppfd->cGreenShift = 8;
ppfd->cBlueBits = 8; ppfd->cBlueShift = 0;
bRet = TRUE;
break;
default:
break;
}
break;
case BI_BITFIELDS:
// Some drivers seem to return bitfields for everything that's
// not paletted. They return correct BGR bitfields so we
// operate correctly, so remove this assert
#ifdef STRICT_BITFIELD_CHECK
ASSERTOPENGL(
cColorBits == 16 || cColorBits == 32,
"__wglGetBitfieldColorFormat(): "
"BI_BITFIELDS surface not 16 or 32bpp\n"
);
#endif
// Call a second time to get the color masks.
// It's a GetDIBits Win32 "feature".
iRet = GetDIBits(hdc, hbm, 0, pbmi->bmiHeader.biHeight, NULL,
pbmi, DIB_RGB_COLORS);
ComputeBitsFromMasks(ppfd, (DWORD *) &pbmi->bmiColors[0]);
bRet = TRUE;
break;
default:
RIP("__wglGetBitfieldColorFormat(): bad biCompression\n");
break;
}
DeleteObject(hbm);
}
if ( hdcTmp )
{
ReleaseDC((HWND) NULL, hdcTmp);
}
return bRet;
}
/******************************Public*Routine******************************\
* Check3DDDICaps
*
* Checks for 3D-DDI capability.
*
* History:
* Wed March 22 1994 -by- Otto Berkes [ottob]
* Wrote it.
* 31-Jul-1995 Gilman Wong [gilmanw]
* Moved from gre directory and ported to client-side.
\**************************************************************************/
VOID Check3DDDICaps(HDC hdc, PPIXELFORMATDESCRIPTOR ppfd)
{
RXGETINFO rxGetInfo;
RXSURFACEINFO rxSurfaceInfo;
BOOL bUseDDI = TRUE;
RXWINDOWSURFACE rxWindowSurface;
rxWindowSurface.flags = RXCONTEXT_HWND;
rxWindowSurface.hwnd = NULL;
rxWindowSurface.hdc = hdc;
rxGetInfo.flags = RXGETINFO_CURRENT_MODE;
rxGetInfo.height = 0;
rxGetInfo.width = 0;
rxGetInfo.bitsPerPixel = 0;
rxGetInfo.refreshRate = 0;
// Get info for this mode
return; //!!!!!
rxGetInfo.infoType = RXINFO_SURFACE_CAPS;
if (!RxGetInfo(&rxWindowSurface, &rxGetInfo,
(UCHAR *)&rxSurfaceInfo, sizeof(RXSURFACEINFO)))
return;
// Check for a back buffer. If the 3D-DDI can't support this, it will
// not be used:
if (ppfd->dwFlags & PFD_DOUBLEBUFFER) {
if (!(rxSurfaceInfo.flags & RXSURFACE_BACK_BUFFER)) {
bUseDDI = FALSE;
}
}
if (bUseDDI) {
ppfd->cRedShift = (UCHAR)rxSurfaceInfo.rBitShift;
ppfd->cGreenShift = (UCHAR)rxSurfaceInfo.gBitShift;
ppfd->cBlueShift = (UCHAR)rxSurfaceInfo.bBitShift;
ppfd->cRedBits = (UCHAR)rxSurfaceInfo.rDepth;
ppfd->cGreenBits = (UCHAR)rxSurfaceInfo.gDepth;
ppfd->cBlueBits = (UCHAR)rxSurfaceInfo.bDepth;
ppfd->cColorBits = (UCHAR)(rxSurfaceInfo.colorBytesPerPixel * 8);
if ((ppfd->cColorBits == 8) &&
(ppfd->iPixelType == PFD_TYPE_RGBA))
ppfd->dwFlags |= PFD_NEED_SYSTEM_PALETTE;
}
}
/******************************Public*Routine******************************\
*
* wglGetDeviceDepth
*
* Returns the depth of the given HDC
* Primarily used to workaround potential problems with printers
* that lie about their depth in GetDeviceCaps
*
* History:
* Tue Apr 09 16:52:47 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
int wglGetDeviceDepth(HDC hdc)
{
int iTech;
// If this is an enhanced metafile it should return the technology
// of the reference device
iTech = GetDeviceCaps(hdc, TECHNOLOGY);
if (iTech == DT_PLOTTER || iTech == DT_RASPRINTER)
{
HBITMAP hbm;
BYTE ajBitmapInfo[sizeof(BITMAPINFO) + 3*sizeof(DWORD)];
BITMAPINFO *pbmi = (BITMAPINFO *) ajBitmapInfo;
int iRet;
// We're dealing with a printer or a metafile that has a printer
// as a reference device
// Find out the true depth by creating a compatible
// bitmap and querying its format
if ( (hbm = CreateCompatibleBitmap(hdc, 1, 1)) != NULL )
{
memset(pbmi, 0, sizeof(ajBitmapInfo));
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
iRet = GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
DeleteObject(hbm);
return iRet != 0 ? pbmi->bmiHeader.biBitCount : -1;
}
// Failure
return -1;
}
else
{
// We're dealing with a well-behaved DC so just return
// the normal depth
return GetDeviceCaps(hdc, BITSPIXEL)*GetDeviceCaps(hdc, PLANES);
}
}
/******************************Public*Routine******************************\
* wglDescribePixelFormat
*
* Describe the pixel format.
* If cjpfd is 0, just return the maximum pixel format index.
*
* Returns: 0 if error; maximum pixel format index otherwise
*
* History:
* 19-Oct-1994 Gilman Wong [gilmanw]
* Adapted from GreDescribePixelFormat (gdi\gre\pixelfmt.cxx).
*
* History for gdi\gre\pixelfmt.cxx:
* Mon Apr 25 15:34:32 1994 -by- Hock San Lee [hockl]
* Added 16-bit Z buffer formats and removed double buffered formats for bitmaps.
* Tue Sep 21 14:25:04 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
// Here are the generic formats that we enumerate. ChoosePixelFormat code
// assumes that generic pixel formats with z32 comes before z16 as given below:
//
// I. Native formats:
//
// 1. rgb.sb.z32
// 2. rgb.sb.z16
// 3. rgb.db.z32
// 4. rgb.db.z16
// 5. ci.sb.z32
// 6. ci.sb.z16
// 7. ci.db.z32
// 8. ci.db.z16
//
// II. Other formats:
//
// 1. rgb.sb.z32
// 2. rgb.sb.z16
// 3. ci.sb.z32
// 4. ci.sb.z16
//
// We always enumerate the native formats first followed by other formats
// in the BPP order {24, 32, 16, 8, 4} for a total of 1 * 8 + 4 * 4 = 24
// pixel formats.
static BYTE aabPixelBits[7][4] =
{
{24, 32, 16, 8}, // error
{24, 32, 16, 8}, // 1 bpp
{24, 32, 16, 8}, // 4 bpp
{24, 32, 16, 4}, // 8 bpp
{24, 32, 8, 4}, // 16 bpp
{32, 16, 8, 4}, // 24 bpp
{24, 16, 8, 4} // 32 bpp
};
static BYTE abPixelType[MAX_GENERIC_PFD] =
{
PFD_TYPE_RGBA,PFD_TYPE_RGBA, PFD_TYPE_RGBA,PFD_TYPE_RGBA,
PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX, PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX,
PFD_TYPE_RGBA,PFD_TYPE_RGBA,PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX,
PFD_TYPE_RGBA,PFD_TYPE_RGBA,PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX,
PFD_TYPE_RGBA,PFD_TYPE_RGBA,PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX,
PFD_TYPE_RGBA,PFD_TYPE_RGBA,PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX
};
int WINAPI wglDescribePixelFormat(HDC hdc, int ipfd, UINT cjpfd,
LPPIXELFORMATDESCRIPTOR ppfd)
{
int iRet = 0;
int ipfdDevMax, ipfdMcdMax, ipfdGen;
int iTech;
DWORD dwObjectType;
UINT iDitherFormat;
BYTE cColorBitsNative;
HDC hdcTmp = (HDC) NULL;
HDC hdcDriver;
// Validate DC.
switch (dwObjectType = wglObjectType(hdc))
{
case OBJ_DC:
case OBJ_MEMDC:
case OBJ_ENHMETADC:
break;
default:
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(0);
}
// Cannot call driver DescribePixelFormat entry points with a memory DC.
// If the HDC passed in is a memory DC handle, grab a temporary display
// DC with which to call these entry points.
hdcDriver = hdc;
iTech = GetDeviceCaps(hdc, TECHNOLOGY);
if ((dwObjectType == OBJ_MEMDC) && (iTech != DT_PLOTTER) &&
(iTech != DT_RASPRINTER))
{
hdcTmp = GetDC((HWND) NULL);
if (hdcTmp)
hdcDriver = hdcTmp;
// NOTE: From this point on, all exit cases must cleanup hdcTmp.
}
// Get the number of hardware supported formats.
wglNumHardwareFormats(hdcDriver, dwObjectType, &ipfdMcdMax, &ipfdDevMax);
// If cjpfd is 0, just return the maximum pixel format index.
if (cjpfd == 0 || ppfd == (LPPIXELFORMATDESCRIPTOR) NULL)
{
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
goto wglDescribePixelFormat_cleanup;
}
// Validate the size of the pixel format descriptor.
if (cjpfd < sizeof(PIXELFORMATDESCRIPTOR))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
goto wglDescribePixelFormat_cleanup;
}
// Validate pixel format index.
// If a driver support device pixel formats 1..ipfdDevMax, the generic
// pixel formats will be (ipfdDevMax+1)..(ipfdDevMax+MAX_GENERIC_PFD).
// Otherwise, ipfdDevMax is 0 and the generic pixel formats are
// 1..MAX_GENERIC_PFD.
if ((ipfd < 1) || (ipfd > ipfdDevMax + ipfdMcdMax + MAX_GENERIC_PFD))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
goto wglDescribePixelFormat_cleanup;
}
// Dispatch ICD driver formats.
if (ipfd <= ipfdDevMax)
{
int iDrvRet = __DrvDescribePixelFormat(hdcDriver,ipfd,cjpfd,ppfd);
if (iDrvRet)
{
ASSERTOPENGL(iDrvRet == ipfdDevMax, "wglDescribePixelFornat: Bad ipfdDevMax");
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
}
goto wglDescribePixelFormat_cleanup;
}
#ifdef _MCD_
// Dispatch MCD driver formats.
ipfdGen = ipfd - ipfdDevMax;
if (ipfdGen <= ipfdMcdMax)
{
int iMcdRet;
// Note: don't need to check if gpMcdTable is valid because we can't get
// here unless ipfdDevMax is non-zero and that can't happen unless the
// the table is valid.
ASSERTOPENGL(gpMcdTable, "wglDescribePixelFormat: bad MCD table\n");
iMcdRet = (gpMcdTable->pMCDDescribePixelFormat)(hdcDriver, ipfdGen, ppfd);
if (iMcdRet)
{
ASSERTOPENGL(iMcdRet == ipfdMcdMax, "wglDescribePixelFornat: Bad ipfdMcdMax");
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
}
goto wglDescribePixelFormat_cleanup;
}
// Generic implementation.
// Normalize the generic pixel format index to 0..(MAX_GENERIC_PFD-1).
ipfdGen = ipfdGen - ipfdMcdMax - 1;
#else
// Generic implementation.
// Normalize the generic pixel format index to 0..(MAX_GENERIC_PFD-1).
ipfdGen = ipfd - ipfdDevMax - 1;
#endif
// Get the native BPP format.
cColorBitsNative = wglGetDeviceDepth(hdcDriver);
if (cColorBitsNative < 1)
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
goto wglDescribePixelFormat_cleanup;
}
if (cColorBitsNative <= 1) {
cColorBitsNative = 1;
iDitherFormat = BMF_1BPP;
} else if (cColorBitsNative <= 4) {
cColorBitsNative = 4;
iDitherFormat = BMF_4BPP;
} else if (cColorBitsNative <= 8) {
cColorBitsNative = 8;
iDitherFormat = BMF_8BPP;
} else if (cColorBitsNative <= 16) {
cColorBitsNative = 16;
iDitherFormat = BMF_16BPP;
} else if (cColorBitsNative <= 24) {
cColorBitsNative = 24;
iDitherFormat = BMF_24BPP;
} else {
cColorBitsNative = 32;
iDitherFormat = BMF_32BPP;
}
// Fill in the pixel format descriptor.
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
ppfd->iPixelType = abPixelType[ipfdGen];
if (ipfdGen < 8)
ppfd->cColorBits = max(cColorBitsNative,4); // 1 bpp not supported
else
ppfd->cColorBits = aabPixelBits[iDitherFormat][(ipfdGen - 8) / 4];
// If the color format is compatible to that of the device and the
// color bits is 16 or greater, use the device description.
// Otherwise, use the generic format.
if (ipfdGen < 8 && cColorBitsNative >= 16)
{
// Handle compatible formats that are greater than 16-bits.
if ( !__wglGetBitfieldColorFormat(hdc, cColorBitsNative, ppfd, FALSE) )
{
// Don't know how to deal with this device!
WARNING("Unknown device format");
SAVE_ERROR_CODE(ERROR_NOT_SUPPORTED);
goto wglDescribePixelFormat_cleanup;
}
}
else
{
// Handle generic formats.
switch (ppfd->cColorBits)
{
case 4:
ppfd->cRedBits = 1; ppfd->cRedShift = 0;
ppfd->cGreenBits = 1; ppfd->cGreenShift = 1;
ppfd->cBlueBits = 1; ppfd->cBlueShift = 2;
break;
case 8:
ppfd->cRedBits = 3; ppfd->cRedShift = 0;
ppfd->cGreenBits = 3; ppfd->cGreenShift = 3;
ppfd->cBlueBits = 2; ppfd->cBlueShift = 6;
break;
case 16:
/*
** Even though Win95 allows arbitrary bitfield definitions
** for 16bpp DIBs, only 555BGR is usable by Win95's GDI.
*/
ppfd->cRedBits = 5; ppfd->cRedShift = 10; // 555BGR
ppfd->cGreenBits = 5; ppfd->cGreenShift = 5;
ppfd->cBlueBits = 5; ppfd->cBlueShift = 0;
break;
case 24:
case 32:
/*
** Even though Win95 allows arbitrary bitfield definitions
** for 32bpp, only 888BGR is usable by Win95's GDI. Similarly,
** NT has the concept of a RGB 24bpp DIB, but Win95 does not.
*/
ppfd->cRedBits = 8; ppfd->cRedShift = 16; // 888BGR
ppfd->cGreenBits = 8; ppfd->cGreenShift = 8;
ppfd->cBlueBits = 8; ppfd->cBlueShift = 0;
break;
default:
ASSERTOPENGL(FALSE, "wglDescribePixelFornat: Unknown format");
break;
}
}
ppfd->cAlphaBits = 0;
ppfd->cAlphaShift = 0;
if (ppfd->iPixelType == PFD_TYPE_RGBA)
{
if (ppfd->cColorBits < 8)
{
ppfd->cAccumBits = 16;
ppfd->cAccumRedBits = 5;
ppfd->cAccumGreenBits = 6;
ppfd->cAccumBlueBits = 5;
ppfd->cAccumAlphaBits = 0;
}
else
{
if (ppfd->cColorBits <= 16)
{
ppfd->cAccumBits = 32;
ppfd->cAccumRedBits = 11;
ppfd->cAccumGreenBits = 11;
ppfd->cAccumBlueBits = 10;
ppfd->cAccumAlphaBits = 0;
}
else
{
ppfd->cAccumBits = 64;
ppfd->cAccumRedBits = 16;
ppfd->cAccumGreenBits = 16;
ppfd->cAccumBlueBits = 16;
ppfd->cAccumAlphaBits = 0;
}
}
}
else
{
ppfd->cAccumBits = 0;
ppfd->cAccumRedBits = 0;
ppfd->cAccumGreenBits = 0;
ppfd->cAccumBlueBits = 0;
ppfd->cAccumAlphaBits = 0;
}
// Generic formats alternate between 16- and 32-bit depth buffer. Evens
// are 32-bit, odds are 16-bit.
if (ipfdGen & 0x1)
ppfd->cDepthBits = 16;
else
ppfd->cDepthBits = 32;
ppfd->cStencilBits = 8;
ppfd->cAuxBuffers = 0;
ppfd->iLayerType = PFD_MAIN_PLANE;
ppfd->bReserved = 0;
ppfd->dwLayerMask = 0;
ppfd->dwVisibleMask = 0;
ppfd->dwDamageMask = 0;
// Compute the buffer flags.
// Support OpenGL in all generic formats.
ppfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT;
// Bitmaps and GDI drawing are available in single buffered mode only.
if (ipfdGen == 2 || ipfdGen == 3 || ipfdGen == 6 || ipfdGen == 7)
ppfd->dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY;
else
ppfd->dwFlags |= PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI;
// Draw to window or device surface only if the format is compatible.
if (ipfdGen < 8)
{
ppfd->dwFlags |= PFD_DRAW_TO_WINDOW;
// Need a palette if it is a RGBA pixel type on a palette managed device.
if (ppfd->cColorBits == 8 && ppfd->iPixelType == PFD_TYPE_RGBA)
ppfd->dwFlags |= PFD_NEED_PALETTE;
}
// Update the pixel format to be compatible with the 3D-DDI if this
// is a display DC, and an RGB native format:
if (ppfd->iPixelType == PFD_TYPE_RGBA)
{
// Update the pixel format to be compatible with the 3D-DDI if this
// is a display DC, and a native format:
if ( (dwObjectType == OBJ_DC) &&
(ipfdGen < 8) )
Check3DDDICaps(hdc, ppfd);
}
// If this is a 1 bpp surface, we don't support drawing to window and
// double buffered mode. Re-set the buffer flags.
if (cColorBitsNative < 4)
{
#ifndef GL_METAFILE
ASSERTOPENGL(ppfd->cColorBits == 4,
"wglDescribePixelFormat: bad cColorBits for 1 bpp surface\n");
#endif
ppfd->dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI
| PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT;
}
// To support other potential graphics systems, we reserve the following
// flags in the pixel format descriptor. For example, PEX may use
// PFD_SUPPORT_OTHER1 on the system that supports PEX. Since we don't
// support these other systems in the generic implementation, they belong
// to the device pixel format descriptor.
ASSERTOPENGL(!(ppfd->dwFlags & (PFD_SUPPORT_OTHER1|PFD_SUPPORT_OTHER2|PFD_SUPPORT_OTHER3|PFD_SUPPORT_OTHER4)), "dwFlags reserved for device formats\n");
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
wglDescribePixelFormat_cleanup:
if (hdcTmp)
ReleaseDC((HWND) NULL, hdcTmp);
return iRet;
}
#ifdef _MCD_
/******************************Public*Routine******************************\
* GenMcdGenericCompatibleFormat
*
* Determines if pixelformat in gengc can be supported by generic code.
*
* Note:
* The implication of not being compatible is that generic cannot be
* used for driver kickbacks and MCD contexts cannot be converted.
*
* Returns:
* TRUE if compatible, FALSE otherwise.
*
* History:
* 04-Jun-1996 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL FASTCALL GenMcdGenericCompatibleFormat(__GLGENcontext *gengc)
{
PIXELFORMATDESCRIPTOR *ppfd;
// Software-only formats are definitely supported.
ppfd = &gengc->CurrentFormat;
if ((ppfd->dwFlags & (PFD_GENERIC_FORMAT|PFD_GENERIC_ACCELERATED))
== PFD_GENERIC_FORMAT)
return TRUE;
// Layer planes are not supported.
if (gengc->iLayerPlane)
return FALSE;
// Generic is PFD_SWAP_COPY only. There can't be many apps that rely
// on PFD_SWAP_EXCHANGE behavior (usually they look for PFD_SWAP_COPY
// so the back buffer can be used as backing store), but for now I think
// we should be conservative.
//
// Note: most MGA cards will set PFD_SWAP_COPY or neither (i.e., either
// style might be used depending on window size).
if (ppfd->dwFlags & PFD_SWAP_EXCHANGE)
return FALSE;
// Can only support 8bpp stencils.
if ((ppfd->cStencilBits != 0) && (ppfd->cStencilBits != 8))
return FALSE;
// No alpha support.
if (ppfd->cAlphaBits)
return FALSE;
// Passed all the checks, we're compatible.
return TRUE;
}
#endif
/******************************Public*Routine******************************\
* wglSwapBuffers
*
\**************************************************************************/
BOOL WINAPI wglSwapBuffers(HDC hdc)
{
int ipfd;
BOOL bRet = FALSE;
GLGENwindow *pwnd;
// Validate the DC.
switch ( GetObjectType(hdc) )
{
case OBJ_DC:
break;
case OBJ_MEMDC:
return(TRUE); // early out -- nothing to do if memory DC
default:
WARNING("wglSwapBuffers(): invalid hdc\n");
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
return(FALSE);
}
// Finish OpenGL calls in this thread before doing the swap.
// We use glFinish instead of glFlush to ensure that all OpenGL operations
// are completed.
glFinish();
// Validate pixel format.
pwnd = pwndGetFromDC(hdc);
if ( pwnd )
{
if (pwnd->ipfd > 0)
{
// Dispatch to driver or generic. Which one can be determined by
// the pixel format.
if ( pwnd->ipfd <= pwnd->ipfdDevMax )
{
bRet = __DrvSwapBuffers(hdc);
}
else
{
EnterCriticalSection(&pwnd->sem);
bRet = glsrvSwapBuffers(hdc, &pwnd->wo);
LeaveCriticalSection(&pwnd->sem);
}
}
pwndRelease(pwnd);
}
else
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
}
return bRet;
}