|
|
/**************************************************************************\
* * Copyright (c) 1998 Microsoft Corporation * * Abstract: * * Handle all the device associations. * * Revision History: * * 12/03/1998 andrewgo * Created it. * \**************************************************************************/
#include "precomp.hpp"
#include "compatibledib.hpp"
BOOL gbUseD3DHAL = TRUE; /**************************************************************************\
* * Function Description: * * Creates a GpDevice class that represents the (meta) desktop. * * Arguments: * * [IN] hdc - Owned DC representing the device. Note that this has to * live for the lifetime of this 'GpDevice' object. Caller * is responsible for deletion or management of the HDC. * * Return Value: * * IsValid() is FALSE in the event of failure. * * History: * * 12/04/1998 andrewgo * Created it. * \**************************************************************************/
GpDevice::GpDevice( HDC hdc ) { hMonitor = NULL; Buffers[0] = NULL;
__try { DeviceLock.Initialize(); } __except(EXCEPTION_EXECUTE_HANDLER) { // We couldn't allocate the criticalSection
// Return an error
WARNING(("Unable to allocate the DeviceLock")); SetValid(FALSE); return; }
DeviceHdc = hdc; BufferWidth = 0;
DIBSectionBitmap = NULL; DIBSection = NULL; ScanDci = NULL; pdd = NULL; pd3d = NULL; pdds = NULL; pd3dDevice = NULL;
DIBSectionHdc = CreateCompatibleDC(hdc);
if ((GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) && (GetDeviceCaps(hdc, BITSPIXEL) <= 8)) { // Query and cache color palette
// !!! [agodfrey] This is hard to maintain. We have much the same
// palette code spread all over the place. It should be abstracted
// into a single location. I've marked each instance with
// <SystemPalette>.
Palette = (ColorPalette*) GpMalloc(sizeof(ColorPalette) + sizeof(ARGB)*256); if (Palette == NULL) { WARNING(("Unable to allocate color palette")); SetValid(FALSE); return; }
INT i; INT numEntries; PALETTEENTRY palEntry[256];
// [agodfrey] On Win9x, GetSystemPaletteEntries(hdc, 0, 256, NULL)
// doesn't do what MSDN says it does. It seems to return the number
// of entries in the logical palette of the DC instead. So we have
// to make it up ourselves.
numEntries = (1 << (GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES)));
ASSERT(numEntries <= 256); GetSystemPaletteEntries(hdc, 0, numEntries, &palEntry[0]); Palette->Count = numEntries; for (i=0; i<numEntries; i++) { Palette->Entries[i] = Color::MakeARGB(0xFF, palEntry[i].peRed, palEntry[i].peGreen, palEntry[i].peBlue); } } else { Palette = NULL; }
ScreenOffsetX = 0; ScreenOffsetY = 0;
ScreenWidth = GetDeviceCaps(hdc, HORZRES); ScreenHeight = GetDeviceCaps(hdc, VERTRES);
ScanDci = new EpScanGdiDci(this, TRUE); ScanGdi = new EpScanGdiDci(this);
SetValid((ScanDci != NULL) && (ScanGdi != NULL) && (DIBSectionHdc != NULL)); }
/**************************************************************************\
* * Function Description: * * Creates a GpDevice class that represents a device associated with * a particular monitor on the desktop. * * Arguments: * * [IN] hMonitor - Identifies the monitor on the system. * * Return Value: * * IsValid() is FALSE in the event of failure. * * History: * * 10/13/1999 bhouse * Created it. * \**************************************************************************/
GpDevice::GpDevice( HMONITOR inMonitor ) { hMonitor = NULL; Buffers[0] = NULL; MONITORINFOEXA mi; mi.cbSize = sizeof(mi);
DIBSectionBitmap = NULL; DIBSection = NULL; ScanDci = NULL; ScanGdi = NULL;
pdd = NULL; pd3d = NULL; pdds = NULL; pd3dDevice = NULL;
DIBSectionHdc = NULL; Palette = NULL; __try { DeviceLock.Initialize(); } __except(EXCEPTION_EXECUTE_HANDLER) { // We couldn't allocate the criticalSection
// Return an error
WARNING(("Unable to allocate the DeviceLock")); SetValid(FALSE); return; } SetValid(FALSE);
if(Globals::GetMonitorInfoFunction == NULL) { WARNING(("GpDevice with HMONITOR called with no multi-monitor support")); } else if(Globals::GetMonitorInfoFunction(inMonitor, &mi)) { HDC hdc;
if (Globals::IsNt) { hdc = CreateDCA("Display", mi.szDevice, NULL, NULL); } else { hdc = CreateDCA(NULL, mi.szDevice, NULL, NULL); } // Note: because we created the hdc, the ~GpDevice destructor is
// responsible for for its deletion. We currently recognize this
// case by a non-NULL hMonitor.
if(hdc != NULL) { hMonitor = inMonitor;
DeviceHdc = hdc; BufferWidth = 0;
DIBSectionHdc = CreateCompatibleDC(hdc);
if ((GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) && (GetDeviceCaps(hdc, BITSPIXEL) <= 8)) { // Query and cache color palette
// <SystemPalette>
Palette = (ColorPalette*) GpMalloc(sizeof(ColorPalette) + sizeof(ARGB)*256); if (Palette == NULL) { WARNING(("Unable to allocate color palette")); return; } INT i; INT numEntries; PALETTEENTRY palEntry[256]; // [agodfrey] On Win9x, GetSystemPaletteEntries(hdc, 0, 256, NULL)
// doesn't do what MSDN says it does. It seems to return the number
// of entries in the logical palette of the DC instead. So we have
// to make it up ourselves.
numEntries = (1 << (GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES)));
ASSERT(numEntries <= 256); GetSystemPaletteEntries(hdc, 0, numEntries, &palEntry[0]); Palette->Count = numEntries; for (i=0; i<numEntries; i++) { Palette->Entries[i] = Color::MakeARGB(0xFF, palEntry[i].peRed, palEntry[i].peGreen, palEntry[i].peBlue); } }
ScreenOffsetX = mi.rcMonitor.left; ScreenOffsetY = mi.rcMonitor.top;
ScreenWidth = (mi.rcMonitor.right - mi.rcMonitor.left); ScreenHeight = (mi.rcMonitor.bottom - mi.rcMonitor.top);
ScanDci = new EpScanGdiDci(this, TRUE); ScanGdi = new EpScanGdiDci(this);
#if HW_ACCELERATION_SUPPORT
if(InitializeDirectDrawGlobals()) { HRESULT hr = Globals::DirectDrawEnumerateExFunction( GpDevice::EnumDirectDrawCallback, this, DDENUM_ATTACHEDSECONDARYDEVICES);
if(pdd == NULL) { // This could happen if this is a single monitor
// machine. Try again to create the DirectDraw Object.
hr = Globals::DirectDrawCreateExFunction(NULL, &pdd, IID_IDirectDraw7, NULL);
if(hr != DD_OK) { WARNING(("Unable to create monitor Direct Draw interface")); }
hr = pdd->SetCooperativeLevel(NULL, DDSCL_NORMAL);
if(hr != DD_OK) { WARNING(("Unable to set cooperative level for monitor device")); pdd->Release(); pdd = NULL; } }
if(pdd != NULL) { DDSURFACEDESC2 sd;
memset(&sd, 0, sizeof(sd)); sd.dwSize = sizeof(sd);
sd.dwFlags = DDSD_CAPS; sd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
hr = pdd->CreateSurface(&sd, &pdds, NULL);
if(hr != DD_OK) { WARNING(("Unable to create primary surface for monitor")); }
hr = pdd->QueryInterface(IID_IDirect3D7, (void **) &pd3d);
if(hr != DD_OK) { WARNING(("Unable to get monitor D3D interface")); }
if(pd3d != NULL && pdds != NULL) {
if(gbUseD3DHAL) hr = pd3d->CreateDevice(IID_IDirect3DHALDevice, pdds, &pd3dDevice); else hr = pd3d->CreateDevice(IID_IDirect3DRGBDevice, pdds, &pd3dDevice);
if(hr != DD_OK) { WARNING(("Unable to create D3D device")); }
if(pd3dDevice != NULL) { pddsRenderTarget = pdds;
hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, 0); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, 0); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, FALSE); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, FALSE); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); if(hr == DD_OK) hr = pd3dDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE); // Setup viewport
D3DVIEWPORT7 viewData; viewData.dwX = 0; viewData.dwY = 0; viewData.dwWidth = ScreenWidth; viewData.dwHeight = ScreenHeight; viewData.dvMinZ = 0.0f; viewData.dvMaxZ = 1.0f; if(hr == DD_OK) hr = pd3dDevice->SetViewport(&viewData); if(hr != DD_OK) { WARNING(("Failed setting default D3D state")); pd3d->Release(); pd3d = NULL; }
}
}
}
}
#endif // HW_ACCELERATION_SUPPORT
SetValid((ScanDci != NULL) && (ScanGdi != NULL) && (DIBSectionHdc != NULL)); } else { WARNING(("Failed creating HDC from HMONITOR")); } } }
/**************************************************************************\
* * Function Description: * * Callback function used to D3D Device Enumeration * * Arguments: * * See D3D SDK * * Return Value: * * See D3D SDK * * History: * * 10/11/1999 bhouse * Created it. * \**************************************************************************/
BOOL GpDevice::EnumDirectDrawCallback( GUID * lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hMonitor) { GpDevice * device = (GpDevice *) lpContext;
if(device->hMonitor == hMonitor && lpGUID) { HRESULT hr = Globals::DirectDrawCreateExFunction(lpGUID, &device->pdd, IID_IDirectDraw7, NULL);
if(hr != DD_OK) { WARNING(("Unable to create monitor Direct Draw interface")); }
hr = device->pdd->SetCooperativeLevel(NULL, DDSCL_NORMAL);
if(hr != DD_OK) { WARNING(("Unable to set cooperative level for monitor device")); device->pdd->Release(); device->pdd = NULL; }
return(FALSE); }
return(TRUE); }
/**************************************************************************\
* * Function Description: * * Destroys a GpDevice class. * * Arguments: * * None * * Return Value: * * NONE * * History: * * 12/04/1998 andrewgo * Created it. * \**************************************************************************/
GpDevice::~GpDevice( VOID ) { DeviceLock.Uninitialize();
#if 0
// !!!TODO: Find out why we are getting an access fault when we try and
// release the pd3d7 interface
if(pd3dDevice != NULL) pd3dDevice->Release();
if(pd3d != NULL) pd3d->Release(); #endif
if(pdds != NULL) pdds->Release();
if(pdd != NULL) pdd->Release();
DeleteObject(DIBSectionBitmap); DeleteDC(DIBSectionHdc);
if (hMonitor != NULL) { // If GpDevice was created by the GpDevice(HMONITOR) contructor,
// then the HDC was created by the object. Therefore, in that case
// the destructor is responsible for deletion.
if (DeviceHdc != NULL) { DeleteDC(DeviceHdc); } }
GpFree(Buffers[0]); GpFree(Palette); delete ScanDci; delete ScanGdi;
SetValid(FALSE); // so we don't use a deleted object
}
/**************************************************************************\
* * Function Description: * * Returns 5 scan buffers of a specified width, from a cache in * the device. * * One is a DIBSection which is compatible with the device (or 8bpp if * the device format is smaller than 8bpp.) * * Arguments: * * [IN] width - Specifies the requested width in pixels * [OUT] [OPTIONAL] dibSection - Returns the pointer to the DIBSection * [OUT] [OPTIONAL] hdcDibSection - Returns an HDC to the DIBSection * [OUT] [OPTIONAL] dstFormat - Returns the format of the DIBSection. * [OUT] [OPTIONAL] buffers - Returns an array of 5 pointers to * buffers, each big enough to hold <width> pixels in 64bpp. * * Return Value: * * FALSE if there was an allocation error. * * History: * * 12/04/1998 andrewgo * Created it. * 01/21/2000 agodfrey * Changed it to create just 1 DIBSection, and 4 memory buffers. * \**************************************************************************/
BOOL GpDevice::GetScanBuffers( INT width, VOID **dibSection, HDC *hdcDibSection, PixelFormatID *dstFormat, VOID *buffers[5] ) { // If BufferWidth is 0 this means that the DIBSectionBitmap should be
// recreated. This is used, for instance, when switching bit depths
// to a palettized format.
if (width > BufferWidth) { if (DIBSectionBitmap != NULL) { DeleteObject(DIBSectionBitmap); }
DIBSectionBitmap = CreateSemiCompatibleDIB( DeviceHdc, width, 1, Palette, &DIBSection, &BufferFormat);
if (DIBSectionBitmap) { BufferWidth = width; SelectObject(DIBSectionHdc, DIBSectionBitmap);
} else { BufferWidth = 0; } // Allocate the 5 memory buffers from one chunk.
if (Buffers[0]) { GpFree(Buffers[0]); } Buffers[0] = GpMalloc(sizeof(ARGB64) * width * 5); if (Buffers[0]) { int i; for (i=1;i<5;i++) { Buffers[i] = static_cast<BYTE *>(Buffers[i-1]) + sizeof(ARGB64) * width; } } else { BufferWidth = 0; } } if (dibSection != NULL) { *dibSection = DIBSection; } if (hdcDibSection != NULL) { *hdcDibSection = DIBSectionHdc; } if (buffers != NULL) { int i; for (i=0;i<5;i++) { buffers[i] = Buffers[i]; } } if (dstFormat != NULL) { *dstFormat = BufferFormat; }
return(BufferWidth != 0); }
/**************************************************************************\
* * Function Description: * * Constructor of GpDeviceList * * Arguments: * * NONE * * Return Value: * * NONE * * History: * * 10/08/1999 bhouse * Created it. * \**************************************************************************/
GpDeviceList::GpDeviceList() { mNumDevices = 0; mDevices = NULL; }
/**************************************************************************\
* * Function Description: * * Destructor of GpDeviceList * * Arguments: * * NONE * * Return Value: * * NONE * * History: * * 10/08/1999 bhouse * Created it. * \**************************************************************************/
GpDeviceList::~GpDeviceList() { GpFree(mDevices); }
/**************************************************************************\
* * Function Description: * * Add device to device list. * * Arguments: * * inDevice - device to add * * Return Value: * * Ok if device was successfully added otherwise OutOfMemory * * History: * * 10/08/1999 bhouse * Created it. * \**************************************************************************/
GpStatus GpDeviceList::AddDevice(GpDevice * inDevice) { GpDevice ** newList = (GpDevice **) GpMalloc((mNumDevices + 1) * sizeof(GpDevice *));
if(newList == NULL) return OutOfMemory;
memcpy(newList, mDevices, (mNumDevices * sizeof(GpDevice *))); newList[mNumDevices++] = inDevice;
GpFree(mDevices);
mDevices = newList;
return Ok; }
/**************************************************************************\
* * Function Description: * * Add device to device list. * * Arguments: * * inSurface - surface for which we need to find matching D3DDevice * * Return Value: * * GpDevice if found otherwise NULL * * History: * * 10/08/1999 bhouse * Created it. * \**************************************************************************/
GpDevice * GpDeviceList::FindD3DDevice(IDirectDrawSurface7 * inSurface) { HRESULT hr; IUnknown * unknown;
hr = inSurface->GetDDInterface((void **) &unknown);
if(hr != DD_OK) return NULL;
IDirectDraw7 * pddMatch;
hr = unknown->QueryInterface(IID_IDirectDraw7, (void **) &pddMatch);
if(hr != DD_OK) return NULL;
#if 0
IDirect3D7 * pd3dMatch;
hr = pddMatch->QueryInterface(IID_IDirect3D7, (void **) &pd3dMatch);
if(hr != DD_OK) { pddMatch->Release(); return NULL; }
GpDevice * device = NULL;
for(INT i = 0; i < mNumDevices; i++) { if(mDevices[i]->pd3d == pd3dMatch) { device = mDevices[i]; break; } }
pd3dMatch->Release(); #else
GpDevice * device = NULL;
for(INT i = 0; i < mNumDevices; i++) { if(mDevices[i]->pdd == pddMatch) { device = mDevices[i]; break; } } #endif
pddMatch->Release();
return device; }
#if 0
/**************************************************************************\
* * Function Description: * * Callback function used to D3D Device Enumeration * * Arguments: * * See D3D SDK * * Return Value: * * See D3D SDK * * History: * * 10/11/1999 bhouse * Created it. * \**************************************************************************/
HRESULT GpDeviceList::EnumD3DDevicesCallback( LPSTR lpDevDesc, LPSTR lpDevName, LPD3DDEVICEDESC7 * d3dDevDesc, LPVOID lpContext) { GpDeviceList * devList = (GpDeviceList *) lpContext;
}
/**************************************************************************\
* * Function Description: * * Build a device list. * * Arguments: * * NONE * * Return Value: * * NONE * * History: * * 10/08/1999 bhouse * Created it. * \**************************************************************************/
void GpDeviceList::Build(void) { if(!InitializeDirectDrawGlobals()) return;
HRESULT hr;
hr = Globals::Direct3D->EnumDevices(EnumD3DDevicesCallback, this);
}
#endif
|