From 313051f9d6e443bdd394a178c30fda122d39614c Mon Sep 17 00:00:00 2001 From: Ove Kaaven Date: Tue, 20 Mar 2001 01:24:08 +0000 Subject: [PATCH] Added gamma ramp code to the XVidMode interface. --- dlls/x11drv/x11ddraw.c | 200 ++++++++++++++++++++++++++++++++++++++++++++----- dlls/x11drv/x11ddraw.h | 21 ++++++ dlls/x11drv/xvidmode.c | 192 ++++++++++++++++++++++++++++++++++++++++++++--- dlls/x11drv/xvidmode.h | 4 + include/x11drv.h | 4 + 5 files changed, 395 insertions(+), 26 deletions(-) create mode 100644 dlls/x11drv/x11ddraw.h diff --git a/dlls/x11drv/x11ddraw.c b/dlls/x11drv/x11ddraw.c index 386da95ea89..47e887651d0 100644 --- a/dlls/x11drv/x11ddraw.c +++ b/dlls/x11drv/x11ddraw.c @@ -4,56 +4,180 @@ * Copyright 2001 TransGaming Technologies, Inc. */ +#include "ts_xlib.h" +#include "x11drv.h" +#include "x11ddraw.h" +#include "xvidmode.h" + #include "windef.h" #include "wingdi.h" #include "ddrawi.h" -#include "xvidmode.h" +#include "bitmap.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(x11drv); +LPDDRAWI_DDRAWSURFACE_LCL X11DRV_DD_Primary; +LPDDRAWI_DDRAWSURFACE_GBL X11DRV_DD_PrimaryGbl; +HBITMAP X11DRV_DD_PrimaryDIB; +Drawable X11DRV_DD_PrimaryDrawable; +ATOM X11DRV_DD_UserClass; +BOOL X11DRV_DD_IsDirect; + +static void SetPrimaryDIB(HBITMAP hBmp) +{ + X11DRV_DD_PrimaryDIB = hBmp; + if (hBmp) { + BITMAPOBJ *bmp; + bmp = (BITMAPOBJ *)GDI_GetObjPtr( hBmp, BITMAP_MAGIC ); + X11DRV_DD_PrimaryDrawable = (Pixmap)bmp->physBitmap; + GDI_ReleaseObj( hBmp ); + } else { + X11DRV_DD_PrimaryDrawable = 0; + } +} + static DWORD PASCAL X11DRV_DDHAL_DestroyDriver(LPDDHAL_DESTROYDRIVERDATA data) { data->ddRVal = DD_OK; return DDHAL_DRIVER_HANDLED; } -static DWORD PASCAL X11DRV_DDHAL_SetMode(LPDDHAL_SETMODEDATA data) +static DWORD PASCAL X11DRV_DDHAL_CreateSurface(LPDDHAL_CREATESURFACEDATA data) { -#ifdef HAVE_LIBXXF86VM - if (xf86vm_mode_count) { - X11DRV_XF86VM_SetCurrentMode(data->dwModeIndex); - data->ddRVal = DD_OK; - return DDHAL_DRIVER_HANDLED; + if (data->lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { + X11DRV_DD_Primary = *data->lplpSList; + X11DRV_DD_PrimaryGbl = X11DRV_DD_Primary->lpGbl; + SetPrimaryDIB(GET_LPDDRAWSURFACE_GBL_MORE(X11DRV_DD_PrimaryGbl)->hKernelSurface); + X11DRV_DD_UserClass = GlobalFindAtomA("WINE_DDRAW"); } -#endif + data->ddRVal = DD_OK; return DDHAL_DRIVER_NOTHANDLED; } +static DWORD PASCAL X11DRV_DDHAL_CreatePalette(LPDDHAL_CREATEPALETTEDATA data) +{ + FIXME("stub\n"); + /* only makes sense to do anything if the X server is running at 8bpp, + * which few people do nowadays */ + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + static DDHAL_DDCALLBACKS hal_ddcallbacks = { sizeof(DDHAL_DDCALLBACKS), 0x3ff, /* all callbacks are 32-bit */ X11DRV_DDHAL_DestroyDriver, - NULL, /* CreateSurface */ + X11DRV_DDHAL_CreateSurface, NULL, /* SetColorKey */ - X11DRV_DDHAL_SetMode, + NULL, /* SetMode */ NULL, /* WaitForVerticalBlank */ NULL, /* CanCreateSurface */ - NULL, /* CreatePalette */ + X11DRV_DDHAL_CreatePalette, NULL, /* GetScanLine */ NULL, /* SetExclusiveMode */ NULL /* FlipToGDISurface */ }; +static DWORD PASCAL X11DRV_DDHAL_DestroySurface(LPDDHAL_DESTROYSURFACEDATA data) +{ + if (data->lpDDSurface == X11DRV_DD_Primary) { + X11DRV_DD_Primary = NULL; + X11DRV_DD_PrimaryGbl = NULL; + SetPrimaryDIB(0); + X11DRV_DD_UserClass = 0; + } + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + +static DWORD PASCAL X11DRV_DDHAL_SetPalette(LPDDHAL_SETPALETTEDATA data) +{ + Colormap pal = data->lpDDPalette->u1.dwReserved1; + if (pal) { + if (data->lpDDSurface == X11DRV_DD_Primary) { + FIXME("stub\n"); + /* we should probably find the ddraw window (maybe data->lpDD->lpExclusiveOwner->hWnd), + * and attach the palette to it */ + } + } + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + +static DDHAL_DDSURFACECALLBACKS hal_ddsurfcallbacks = { + sizeof(DDHAL_DDSURFACECALLBACKS), + 0x3fff, /* all callbacks are 32-bit */ + X11DRV_DDHAL_DestroySurface, + NULL, /* Flip */ + NULL, /* SetClipList */ + NULL, /* Lock */ + NULL, /* Unlock */ + NULL, /* Blt */ + NULL, /* SetColorKey */ + NULL, /* AddAttachedSurface */ + NULL, /* GetBltStatus */ + NULL, /* GetFlipStatus */ + NULL, /* UpdateOverlay */ + NULL, /* SetOverlayPosition */ + NULL, /* reserved4 */ + X11DRV_DDHAL_SetPalette +}; + +static DWORD PASCAL X11DRV_DDHAL_DestroyPalette(LPDDHAL_DESTROYPALETTEDATA data) +{ + Colormap pal = data->lpDDPalette->u1.dwReserved1; + if (pal) TSXFreeColormap(display, pal); + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + +static DWORD PASCAL X11DRV_DDHAL_SetPaletteEntries(LPDDHAL_SETENTRIESDATA data) +{ + X11DRV_DDHAL_SetPalEntries(data->lpDDPalette->u1.dwReserved1, + data->dwBase, data->dwNumEntries, + data->lpEntries); + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + +static DDHAL_DDPALETTECALLBACKS hal_ddpalcallbacks = { + sizeof(DDHAL_DDPALETTECALLBACKS), + 0x3, /* all callbacks are 32-bit */ + X11DRV_DDHAL_DestroyPalette, + X11DRV_DDHAL_SetPaletteEntries +}; + static DDHALINFO hal_info = { sizeof(DDHALINFO), &hal_ddcallbacks, - /* more stuff */ + &hal_ddsurfcallbacks, + &hal_ddpalcallbacks, + { /* vmiData */ + 0 /* fpPrimary */ + }, + { /* ddCaps */ + sizeof(DDCORECAPS) + }, + 0, /* dwMonitorFrequency */ + NULL, /* GetDriverInfo */ + 0, /* dwModeIndex */ + NULL, /* lpdwFourCC */ + 0, /* dwNumModes */ + NULL, /* lpModeInfo */ + DDHALINFO_ISPRIMARYDISPLAY | DDHALINFO_MODEXILLEGAL, /* dwFlags */ + NULL, /* lpPDevice */ + 0 /* hInstance */ }; static LPDDHALDDRAWFNS ddraw_fns; static DWORD ddraw_ver; +static void X11DRV_DDHAL_SetInfo(void) +{ + (ddraw_fns->lpSetInfo)(&hal_info, FALSE); +} + INT X11DRV_DCICommand(INT cbInput, LPVOID lpInData, LPVOID lpOutData) { LPDCICMD lpCmd = (LPDCICMD)lpInData; @@ -81,7 +205,7 @@ INT X11DRV_DCICommand(INT cbInput, LPVOID lpInData, LPVOID lpOutData) * would contain the 32-bit ddraw HAL */ strcpy(lpData->szName,"x11drv"); /* the entry point named here should initialize our hal_info - * with 32-bit entry points */ + * with 32-bit entry points (ignored for now) */ strcpy(lpData->szEntryPoint,"DriverInit"); lpData->dwContext = 0; } @@ -90,12 +214,15 @@ INT X11DRV_DCICommand(INT cbInput, LPVOID lpInData, LPVOID lpOutData) { LPDWORD lpInstance = (LPDWORD)lpOutData; + /* FIXME: get x11drv's hInstance */ +#ifdef HAVE_LIBXXF86DGA2 + /*if (!X11DRV_XF86DGA2_CreateDriver(&hal_info))*/ +#endif + { #ifdef HAVE_LIBXXF86VM - hal_info.dwNumModes = xf86vm_mode_count; - hal_info.lpModeInfo = xf86vm_modes; - hal_info.dwModeIndex = X11DRV_XF86VM_GetCurrentMode(); + X11DRV_XF86VM_CreateDriver(&hal_info); #endif - /* FIXME: get x11drv's hInstance */ + } (ddraw_fns->lpSetInfo)(&hal_info, FALSE); *lpInstance = hal_info.hInstance; @@ -104,3 +231,42 @@ INT X11DRV_DCICommand(INT cbInput, LPVOID lpInData, LPVOID lpOutData) } return 0; } + +void X11DRV_DDHAL_SwitchMode(DWORD dwModeIndex, LPVOID fb_addr) +{ + LPDDHALMODEINFO info = &hal_info.lpModeInfo[dwModeIndex]; + + hal_info.dwModeIndex = dwModeIndex; + hal_info.dwMonitorFrequency = info->wRefreshRate; + hal_info.vmiData.fpPrimary = (FLATPTR)fb_addr; + hal_info.vmiData.dwDisplayWidth = info->dwWidth; + hal_info.vmiData.dwDisplayHeight = info->dwHeight; + hal_info.vmiData.lDisplayPitch = info->lPitch; + hal_info.vmiData.ddpfDisplay.dwSize = info->dwBPP ? sizeof(hal_info.vmiData.ddpfDisplay) : 0; + hal_info.vmiData.ddpfDisplay.dwFlags = (info->wFlags & DDMODEINFO_PALETTIZED) ? DDPF_PALETTEINDEXED8 : 0; + hal_info.vmiData.ddpfDisplay.u1.dwRGBBitCount = (info->dwBPP > 24) ? 24 : info->dwBPP; + hal_info.vmiData.ddpfDisplay.u2.dwRBitMask = info->dwRBitMask; + hal_info.vmiData.ddpfDisplay.u3.dwGBitMask = info->dwGBitMask; + hal_info.vmiData.ddpfDisplay.u4.dwBBitMask = info->dwBBitMask; + + X11DRV_DDHAL_SetInfo(); +} + +void X11DRV_DDHAL_SetPalEntries(Colormap pal, DWORD dwBase, DWORD dwNumEntries, + LPPALETTEENTRY lpEntries) +{ + XColor c; + int n; + + if (pal) { + c.flags = DoRed|DoGreen|DoBlue; + c.pixel = dwBase; + for (n=0; ndwModeIndex); + X11DRV_DDHAL_SwitchMode(data->dwModeIndex, NULL); + data->ddRVal = DD_OK; + return DDHAL_DRIVER_HANDLED; +} + +int X11DRV_XF86VM_CreateDriver(LPDDHALINFO info) +{ + if (!xf86vm_mode_count) return 0; /* no XVidMode */ + + info->dwNumModes = xf86vm_mode_count; + info->lpModeInfo = xf86vm_modes; + X11DRV_DDHAL_SwitchMode(X11DRV_XF86VM_GetCurrentMode(), NULL); + info->lpDDCallbacks->SetMode = X11DRV_XF86VM_SetMode; + return TRUE; +} + + +/***** GAMMA CONTROL *****/ +/* (only available in XF86VidMode 2.x) */ + +#ifdef X_XF86VidModeSetGamma + +static void GenerateRampFromGamma(WORD ramp[256], float gamma) +{ + float r_gamma = 1/gamma; + unsigned i; + TRACE("gamma is %f\n", r_gamma); + for (i=0; i<256; i++) + ramp[i] = pow(i/255.0, r_gamma) * 65535.0; +} + +static BOOL ComputeGammaFromRamp(WORD ramp[256], float *gamma) +{ + float r_x, r_y, r_lx, r_ly, r_d, r_v, r_e, g_avg, g_min, g_max; + unsigned i, f, l, g_n, c; + f = ramp[0]; + l = ramp[255]; + if (f >= l) { + ERR("inverted or flat gamma ramp (%d->%d), rejected\n", f, l); + return FALSE; + } + r_d = l - f; + g_min = g_max = g_avg = 0.0; + /* check gamma ramp entries to estimate the gamma */ + TRACE("analyzing gamma ramp (%d->%d)\n", f, l); + for (i=1, g_n=0; i<255; i++) { + if (ramp[i] < f || ramp[i] > l) { + ERR("strange gamma ramp ([%d]=%d for %d->%d), rejected\n", i, ramp[i], f, l); + return FALSE; + } + c = ramp[i] - f; + if (!c) continue; /* avoid log(0) */ + + /* normalize entry values into 0..1 range */ + r_x = i/255.0; r_y = c / r_d; + /* compute logarithms of values */ + r_lx = log(r_x); r_ly = log(r_y); + /* compute gamma for this entry */ + r_v = r_ly / r_lx; + /* compute differential (error estimate) for this entry */ + /* some games use table-based logarithms that magnifies the error by 128 */ + r_e = -r_lx * 128 / (c * r_lx * r_lx); + + /* compute min & max while compensating for estimated error */ + if (!g_n || g_min > (r_v + r_e)) g_min = r_v + r_e; + if (!g_n || g_max < (r_v - r_e)) g_max = r_v - r_e; + + /* add to average */ + g_avg += r_v; + g_n++; + /* TRACE("[%d]=%d, gamma=%f, error=%f\n", i, ramp[i], r_v, r_e); */ + } + if (!g_n) { + ERR("no gamma data, shouldn't happen\n"); + return FALSE; + } + g_avg /= g_n; + TRACE("low bias is %d, high is %d, gamma is %5.3f\n", f, 65535-l, g_avg); + /* the bias could be because the app wanted something like a "red shift" + * like when you're hit in Quake, but XVidMode doesn't support it, + * so we have to reject a significant bias */ + if (f && f > (pow(1/255.0, g_avg) * 65536.0)) { + ERR("low-biased gamma ramp (%d), rejected\n", f); + return FALSE; + } + /* check that the gamma is reasonably uniform across the ramp */ + if (g_max - g_min > 0.1) { + ERR("ramp not uniform (max=%f, min=%f, avg=%f), rejected\n", g_max, g_min, g_avg); + return FALSE; + } + /* ok, now we're pretty sure we can set the desired gamma ramp, + * so go for it */ + *gamma = 1/g_avg; + return TRUE; +} + +#endif /* X_XF86VidModeSetGamma */ + +/* Hmm... should gamma control be available in desktop mode or not? + * I'll assume that it should */ + +BOOL X11DRV_XF86VM_GetGammaRamp(LPDDGAMMARAMP ramp) +{ +#ifdef X_XF86VidModeSetGamma + XF86VidModeGamma gamma; + Bool ret; + + if (xf86vm_major < 2) return FALSE; /* no gamma control */ + wine_tsx11_lock(); + ret = XF86VidModeGetGamma(display, DefaultScreen(display), &gamma); + wine_tsx11_unlock(); + if (ret) { + GenerateRampFromGamma(ramp->red, gamma.red); + GenerateRampFromGamma(ramp->green, gamma.green); + GenerateRampFromGamma(ramp->blue, gamma.blue); + return TRUE; + } +#endif /* X_XF86VidModeSetGamma */ + return FALSE; +} + +BOOL X11DRV_XF86VM_SetGammaRamp(LPDDGAMMARAMP ramp) +{ +#ifdef X_XF86VidModeSetGamma + XF86VidModeGamma gamma; + + if (xf86vm_major < 2) return FALSE; /* no gamma control */ + if (ComputeGammaFromRamp(ramp->red, &gamma.red) && + ComputeGammaFromRamp(ramp->green, &gamma.green) && + ComputeGammaFromRamp(ramp->blue, &gamma.blue)) { + Bool ret; + wine_tsx11_lock(); + ret = XF86VidModeSetGamma(display, DefaultScreen(display), &gamma); + wine_tsx11_unlock(); + return ret; + } +#endif /* X_XF86VidModeSetGamma */ + return FALSE; +} + #endif /* HAVE_LIBXXF86VM */ + +/* FIXME: should move these somewhere appropriate, but probably not before + * the stuff in graphics/x11drv/ has been moved to dlls/x11drv, so that + * they can include xvidmode.h directly */ +BOOL X11DRV_GetDeviceGammaRamp(DC *dc, LPVOID ramp) +{ +#ifdef HAVE_LIBXXF86VM + return X11DRV_XF86VM_GetGammaRamp(ramp); +#else + return FALSE; +#endif +} + +BOOL X11DRV_SetDeviceGammaRamp(DC *dc, LPVOID ramp) +{ +#ifdef HAVE_LIBXXF86VM + return X11DRV_XF86VM_SetGammaRamp(ramp); +#else + return FALSE; +#endif +} diff --git a/dlls/x11drv/xvidmode.h b/dlls/x11drv/xvidmode.h index 1927d13c933..992cf3e4603 100644 --- a/dlls/x11drv/xvidmode.h +++ b/dlls/x11drv/xvidmode.h @@ -17,6 +17,10 @@ void X11DRV_XF86VM_Cleanup(void); int X11DRV_XF86VM_GetCurrentMode(void); void X11DRV_XF86VM_SetCurrentMode(int mode); void X11DRV_XF86VM_SetExclusiveMode(int lock); +int X11DRV_XF86VM_CreateDriver(LPDDHALINFO info); + +BOOL X11DRV_XF86VM_GetGammaRamp(LPDDGAMMARAMP ramp); +BOOL X11DRV_XF86VM_SetGammaRamp(LPDDGAMMARAMP ramp); #endif /* HAVE_LIBXXF86VM */ #endif /* __WINE_XVIDMODE_H */ diff --git a/include/x11drv.h b/include/x11drv.h index 8d84f90beca..e230ebcbe65 100644 --- a/include/x11drv.h +++ b/include/x11drv.h @@ -158,6 +158,8 @@ extern INT X11DRV_DeviceBitmapBits( struct tagDC *dc, HBITMAP hbitmap, WORD fGet, UINT startscan, UINT lines, LPSTR bits, LPBITMAPINFO info, UINT coloruse ); +extern BOOL X11DRV_GetDeviceGammaRamp( struct tagDC *dc, LPVOID ramp ); +extern BOOL X11DRV_SetDeviceGammaRamp( struct tagDC *dc, LPVOID ramp ); /* OpenGL / X11 driver functions */ extern int X11DRV_ChoosePixelFormat(DC *dc, const PIXELFORMATDESCRIPTOR *pppfd) ; @@ -269,6 +271,8 @@ void X11DRV_DIB_CopyDIBSection(DC *dcSrc, DC *dcDst, DWORD xDest, DWORD yDest, DWORD width, DWORD height); +extern INT X11DRV_DCICommand(INT cbInput, LPVOID lpInData, LPVOID lpOutData); + /************************************************************************** * X11 GDI driver */ -- 2.11.4.GIT