WindowsXP-SP1/windows/advcore/gdiplus/engine/entry/device.cpp
2020-09-30 16:53:49 +02:00

891 lines
23 KiB
C++

/**************************************************************************\
*
* 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