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.
499 lines
15 KiB
499 lines
15 KiB
/*==========================================================================
|
|
* Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: ddgamma.c
|
|
* Content: Implements the DirectDrawGammaControl interface, which
|
|
* allows controlling the gamma for the primary surface.
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 05-mar-98 smac created
|
|
*
|
|
***************************************************************************/
|
|
#include "ddrawpr.h"
|
|
#ifdef WINNT
|
|
#include "ddrawgdi.h"
|
|
#endif
|
|
#define DPF_MODNAME "DirectDrawGammaControl"
|
|
|
|
#define DISPLAY_STR "display"
|
|
|
|
|
|
/*
|
|
* InitGamma
|
|
*
|
|
* Called while initializing the DDraw object. It determines whether the
|
|
* driver can support loadable gamma ramps and if so, it sets the
|
|
* DDCAPS2_PRIMARYGAMMA cap bit.
|
|
*/
|
|
VOID InitGamma( LPDDRAWI_DIRECTDRAW_GBL pdrv, LPSTR szDrvName )
|
|
{
|
|
/*
|
|
* In NT, we set the DDCAPS2_PRIMARYGAMMA cap in kernel mode, but on Win9X
|
|
* we just call GetDeviceGammaRamp and if it works, we assume that the device
|
|
* supports gamma. However, GetDeviceGammaRamp was obviously not well tested
|
|
* in Win9X because GDI calls a NULL pointer in some instances where the driver
|
|
* doesn't support downloadable gamma ramps. The only way to work around
|
|
* this is to look at the HDC and detect the situations that crash
|
|
* and then know not to attemp gamma in those situations. We have to do
|
|
* this in DDRAW16.
|
|
*/
|
|
#ifdef WIN95
|
|
LPWORD lpGammaRamp;
|
|
HDC hdc;
|
|
|
|
pdrv->ddCaps.dwCaps2 &= ~DDCAPS2_PRIMARYGAMMA;
|
|
lpGammaRamp = (LPWORD) LocalAlloc( LMEM_FIXED, sizeof( DDGAMMARAMP ) );
|
|
if( NULL != lpGammaRamp )
|
|
{
|
|
hdc = DD_CreateDC( szDrvName );
|
|
if( DD16_AttemptGamma(hdc) &&
|
|
GetDeviceGammaRamp( hdc, lpGammaRamp ) )
|
|
{
|
|
pdrv->ddCaps.dwCaps2 |= DDCAPS2_PRIMARYGAMMA;
|
|
}
|
|
DD_DoneDC( hdc );
|
|
LocalFree( (HLOCAL) lpGammaRamp );
|
|
}
|
|
#endif
|
|
if( bGammaCalibratorExists &&
|
|
( pdrv->ddCaps.dwCaps2 & DDCAPS2_PRIMARYGAMMA ) )
|
|
{
|
|
pdrv->ddCaps.dwCaps2 |= DDCAPS2_CANCALIBRATEGAMMA;
|
|
}
|
|
else
|
|
{
|
|
pdrv->ddCaps.dwCaps2 &= ~DDCAPS2_CANCALIBRATEGAMMA;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* SetGamma
|
|
*
|
|
* Sets the new GammaRamp. If it is being set for the first time, we will
|
|
* save the old gamma ramp so we can restore it later.
|
|
*/
|
|
BOOL SetGamma( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
if( !( this_lcl->dwFlags & DDRAWISURF_SETGAMMA ) )
|
|
{
|
|
bRet = GetDeviceGammaRamp( (HDC) pdrv_lcl->hDC,
|
|
this_lcl->lpSurfMore->lpOriginalGammaRamp );
|
|
}
|
|
if( bRet )
|
|
{
|
|
#ifdef WINNT
|
|
bRet = DdSetGammaRamp( pdrv_lcl, (HDC) pdrv_lcl->hDC,
|
|
this_lcl->lpSurfMore->lpGammaRamp);
|
|
#else
|
|
bRet = SetDeviceGammaRamp( (HDC) pdrv_lcl->hDC,
|
|
this_lcl->lpSurfMore->lpGammaRamp );
|
|
#endif
|
|
this_lcl->dwFlags |= DDRAWISURF_SETGAMMA;
|
|
}
|
|
if( !bRet )
|
|
{
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
return DD_OK;
|
|
}
|
|
|
|
/*
|
|
* RestoreGamma
|
|
*
|
|
* Restores the old GammaRamp.
|
|
*/
|
|
VOID RestoreGamma( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
|
|
{
|
|
BOOL bRet;
|
|
HDC hdcTemp = NULL;
|
|
|
|
/*
|
|
* If we are on DDHELP's thread cleaning up, then pdrv_lcl->hDC
|
|
* will be invalid. In this case, we need to temporarily create
|
|
* a new DC to use.
|
|
*/
|
|
if( ( pdrv_lcl->dwProcessId != GetCurrentProcessId() ) &&
|
|
( this_lcl->dwFlags & DDRAWISURF_SETGAMMA ) )
|
|
{
|
|
hdcTemp = (HDC) pdrv_lcl->hDC;
|
|
if( _stricmp( pdrv_lcl->lpGbl->cDriverName, DISPLAY_STR ) == 0 )
|
|
{
|
|
(HDC) pdrv_lcl->hDC = DD_CreateDC( g_szPrimaryDisplay );
|
|
}
|
|
else
|
|
{
|
|
(HDC) pdrv_lcl->hDC = DD_CreateDC( pdrv_lcl->lpGbl->cDriverName );
|
|
}
|
|
}
|
|
|
|
if( ( this_lcl->dwFlags & DDRAWISURF_SETGAMMA ) &&
|
|
( this_lcl->lpSurfMore->lpOriginalGammaRamp != NULL ))
|
|
{
|
|
#ifdef WINNT
|
|
bRet = DdSetGammaRamp( pdrv_lcl, (HDC) pdrv_lcl->hDC,
|
|
this_lcl->lpSurfMore->lpOriginalGammaRamp);
|
|
#else
|
|
bRet = SetDeviceGammaRamp( (HDC) pdrv_lcl->hDC,
|
|
this_lcl->lpSurfMore->lpOriginalGammaRamp );
|
|
#endif
|
|
}
|
|
this_lcl->dwFlags &= ~DDRAWISURF_SETGAMMA;
|
|
|
|
if( hdcTemp != NULL )
|
|
{
|
|
DD_DoneDC( (HDC) pdrv_lcl->hDC );
|
|
(HDC) pdrv_lcl->hDC = hdcTemp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ReleaseGammaControl
|
|
*/
|
|
VOID ReleaseGammaControl( LPDDRAWI_DDRAWSURFACE_LCL lpSurface )
|
|
{
|
|
RestoreGamma( lpSurface, lpSurface->lpSurfMore->lpDD_lcl );
|
|
if( lpSurface->lpSurfMore->lpGammaRamp != NULL )
|
|
{
|
|
MemFree( lpSurface->lpSurfMore->lpGammaRamp );
|
|
lpSurface->lpSurfMore->lpGammaRamp = NULL;
|
|
}
|
|
if( lpSurface->lpSurfMore->lpOriginalGammaRamp != NULL )
|
|
{
|
|
MemFree( lpSurface->lpSurfMore->lpOriginalGammaRamp );
|
|
lpSurface->lpSurfMore->lpOriginalGammaRamp = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* DD_Gamma_GetGammaControls
|
|
*/
|
|
HRESULT DDAPI DD_Gamma_GetGammaRamp(LPDIRECTDRAWGAMMACONTROL lpDDGC,
|
|
DWORD dwFlags, LPDDGAMMARAMP lpGammaRamp)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT this_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_MORE lpSurfMore;
|
|
BOOL bRet;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_Gamma_GetGammaRamp");
|
|
|
|
/*
|
|
* Validate parameters
|
|
*/
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDGC;
|
|
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
|
|
lpSurfMore = this_lcl->lpSurfMore;
|
|
|
|
if( (lpGammaRamp == NULL) || !VALID_BYTE_ARRAY( lpGammaRamp,
|
|
sizeof( DDGAMMARAMP ) ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_GetGammaRamp: Invalid gamma table specified");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if( dwFlags )
|
|
{
|
|
DPF_ERR("DD_Gamma_GetGammaRamp: Invalid flags specified");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* For now, only support setting the gamma for the primary surface
|
|
*/
|
|
if( !( this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_GetGammaRamp: Must specify primary surface");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if( !( pdrv_lcl->lpGbl->ddCaps.dwCaps2 & DDCAPS2_PRIMARYGAMMA ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_GetGammaRamp: Device deos not support gamma ramps");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if( SURFACE_LOST( this_lcl ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_GetGammaRamp: Secified surface has been lost");
|
|
LEAVE_DDRAW();
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_EXCEPTION;
|
|
}
|
|
|
|
/*
|
|
* If a gamma table has been set, return it; otherwise, get it from
|
|
* the driver.
|
|
*/
|
|
if( lpSurfMore->lpGammaRamp != NULL )
|
|
{
|
|
memcpy( lpGammaRamp, lpSurfMore->lpGammaRamp, sizeof( DDGAMMARAMP ) );
|
|
}
|
|
else
|
|
{
|
|
bRet = GetDeviceGammaRamp( (HDC) pdrv_lcl->hDC, (LPVOID) lpGammaRamp );
|
|
if( bRet == FALSE )
|
|
{
|
|
DPF_ERR("DD_Gamma_GetGammaRamp: GetDeviceGammaRamp failed");
|
|
LEAVE_DDRAW();
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return DD_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* LoadGammaCalibrator
|
|
*/
|
|
VOID LoadGammaCalibrator( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
|
|
{
|
|
DDASSERT( pdrv_lcl->hGammaCalibrator == (ULONG_PTR) INVALID_HANDLE_VALUE );
|
|
|
|
pdrv_lcl->hGammaCalibrator = (ULONG_PTR) LoadLibrary( szGammaCalibrator );
|
|
if( pdrv_lcl->hGammaCalibrator != (ULONG_PTR) NULL )
|
|
{
|
|
pdrv_lcl->lpGammaCalibrator = (LPDDGAMMACALIBRATORPROC)
|
|
GetProcAddress( (HANDLE)(pdrv_lcl->hGammaCalibrator), "CalibrateGammaRamp" );
|
|
if( pdrv_lcl->lpGammaCalibrator == (ULONG_PTR) NULL )
|
|
{
|
|
FreeLibrary( (HMODULE) pdrv_lcl->hGammaCalibrator );
|
|
pdrv_lcl->hGammaCalibrator = (ULONG_PTR) INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pdrv_lcl->hGammaCalibrator = (ULONG_PTR) INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* DD_Gamma_SetGammaRamp
|
|
*/
|
|
HRESULT DDAPI DD_Gamma_SetGammaRamp(LPDIRECTDRAWGAMMACONTROL lpDDGC,
|
|
DWORD dwFlags, LPDDGAMMARAMP lpGammaRamp)
|
|
{
|
|
LPDDRAWI_DDRAWSURFACE_INT this_int;
|
|
LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
|
|
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
|
|
LPDDRAWI_DDRAWSURFACE_MORE lpSurfMore;
|
|
LPDDGAMMARAMP lpTempRamp=NULL;
|
|
HRESULT ddRVal;
|
|
DWORD rc;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_Gamma_SetGammaRamp");
|
|
|
|
/*
|
|
* Validate parameters
|
|
*/
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDGC;
|
|
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
|
|
lpSurfMore = this_lcl->lpSurfMore;
|
|
|
|
if( (lpGammaRamp != NULL) && !VALID_BYTE_ARRAY( lpGammaRamp,
|
|
sizeof( DDGAMMARAMP ) ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Invalid gamma table specified");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
if( dwFlags & ~DDSGR_VALID )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Invalid flag specified");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if( ( dwFlags & DDSGR_CALIBRATE ) && !bGammaCalibratorExists )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: DDSGR_CALIBRATE unsupported - Gamma calibrator not installed");
|
|
LEAVE_DDRAW();
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
/*
|
|
* For now, only support setting the gamma for the primary surface
|
|
*/
|
|
if( !( this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Must specify primary surface");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if( !( pdrv_lcl->lpGbl->ddCaps.dwCaps2 & DDCAPS2_PRIMARYGAMMA ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Device deos not support gamma ramps");
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if( SURFACE_LOST( this_lcl ) )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Secified surface has been lost");
|
|
LEAVE_DDRAW();
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_EXCEPTION;
|
|
}
|
|
|
|
/*
|
|
* lpGammaRamp is NULL, they are trying to restore the gamma.
|
|
*/
|
|
if( lpGammaRamp == NULL )
|
|
{
|
|
ReleaseGammaControl( this_lcl );
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If they want to calibrate the gamma, we will do that now. We will
|
|
* copy this to a different buffer so that we don't mess up the one
|
|
* passed in to us.
|
|
*/
|
|
if( dwFlags & DDSGR_CALIBRATE )
|
|
{
|
|
/*
|
|
* If the calibrator isn't loaded, do so now.
|
|
*/
|
|
if( pdrv_lcl->hGammaCalibrator == (ULONG_PTR) INVALID_HANDLE_VALUE )
|
|
{
|
|
LoadGammaCalibrator( pdrv_lcl );
|
|
}
|
|
if( ( pdrv_lcl->hGammaCalibrator == (ULONG_PTR) INVALID_HANDLE_VALUE ) ||
|
|
( pdrv_lcl->lpGammaCalibrator == (ULONG_PTR) NULL ) )
|
|
{
|
|
/*
|
|
* If we were unable to load the library correctly,
|
|
* we shouldn't try again later.
|
|
*/
|
|
bGammaCalibratorExists = FALSE;
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Unable to load gamma calibrator");
|
|
LEAVE_DDRAW();
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Call the calibrator to let it do it's thing. First
|
|
* need to copy the buffer over so we don't mess with
|
|
* the one passed in.
|
|
*/
|
|
lpTempRamp = (LPDDGAMMARAMP) LocalAlloc( LMEM_FIXED,
|
|
sizeof( DDGAMMARAMP ) );
|
|
if( lpTempRamp == NULL )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Insuficient memory for gamma ramps");
|
|
LEAVE_DDRAW();
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
memcpy( lpTempRamp, lpGammaRamp, sizeof( DDGAMMARAMP ) );
|
|
lpGammaRamp = lpTempRamp;
|
|
|
|
ddRVal = pdrv_lcl->lpGammaCalibrator( lpGammaRamp, pdrv_lcl->lpGbl->cDriverName );
|
|
if( ddRVal != DD_OK )
|
|
{
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Calibrator failed the call");
|
|
LocalFree( (HLOCAL) lpTempRamp );
|
|
LEAVE_DDRAW();
|
|
return ddRVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we are setting this for the first time, allocate memory to hold
|
|
* the gamma ramps
|
|
*/
|
|
if( lpSurfMore->lpOriginalGammaRamp == NULL )
|
|
{
|
|
lpSurfMore->lpOriginalGammaRamp = MemAlloc( sizeof( DDGAMMARAMP ) );
|
|
}
|
|
if( lpSurfMore->lpGammaRamp == NULL )
|
|
{
|
|
lpSurfMore->lpGammaRamp = MemAlloc( sizeof( DDGAMMARAMP ) );
|
|
}
|
|
|
|
/*
|
|
* If we are in exlusive mode now, set the gamma ramp now; otherwise,
|
|
* we'll let it get set when we enter excluisve mode.
|
|
*/
|
|
if( lpSurfMore->lpGammaRamp && lpSurfMore->lpOriginalGammaRamp )
|
|
{
|
|
memcpy( lpSurfMore->lpGammaRamp, lpGammaRamp, sizeof( DDGAMMARAMP ) );
|
|
if( pdrv_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE )
|
|
{
|
|
SetGamma( this_lcl, pdrv_lcl );
|
|
}
|
|
if( lpTempRamp != NULL )
|
|
{
|
|
LocalFree( (HLOCAL) lpTempRamp );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Out of memory condition. Release the two ramps
|
|
*/
|
|
if( lpTempRamp != NULL )
|
|
{
|
|
LocalFree( (HLOCAL) lpTempRamp );
|
|
}
|
|
if( lpSurfMore->lpGammaRamp != NULL )
|
|
{
|
|
MemFree( lpSurfMore->lpGammaRamp );
|
|
lpSurfMore->lpGammaRamp = NULL;
|
|
}
|
|
if( lpSurfMore->lpOriginalGammaRamp != NULL )
|
|
{
|
|
MemFree( lpSurfMore->lpOriginalGammaRamp );
|
|
lpSurfMore->lpOriginalGammaRamp = NULL;
|
|
}
|
|
DPF_ERR("DD_Gamma_SetGammaRamp: Insuficient memory for gamma ramps");
|
|
LEAVE_DDRAW();
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return DD_OK;
|
|
}
|
|
|
|
|