/* *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. * *Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the *"Software"), to deal in the Software without restriction, including *without limitation the rights to use, copy, modify, merge, publish, *distribute, sublicense, and/or sell copies of the Software, and to *permit persons to whom the Software is furnished to do so, subject to *the following conditions: * *The above copyright notice and this permission notice shall be *included in all copies or substantial portions of the Software. * *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *Except as contained in this notice, the name of the XFree86 Project *shall not be used in advertising or otherwise to promote the sale, use *or other dealings in this Software without prior written authorization *from the XFree86 Project. * * Authors: Dakshinamurthy Karra * Suhaib M Siddiqi * Peter Busch * Harold L Hunt II */ /* $XFree86: xc/programs/Xserver/hw/xwin/winpfbdd.c,v 1.18 2003/07/29 21:25:18 dawes Exp $ */ #include "win.h" /* * External global variables */ extern const GUID _IID_IDirectDraw2; /* * Create a DirectDraw primary surface */ Bool winAllocateFBPrimaryDD (ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; HRESULT ddrval = DD_OK; DDSURFACEDESC ddsd; DDSURFACEDESC *pddsdPrimary = NULL; DDSURFACEDESC *pddsdOffscreen = NULL; RECT rcClient; ErrorF ("winAllocateFBPrimaryDD\n"); /* Get client area location in screen coords */ GetClientRect (pScreenPriv->hwndScreen, &rcClient); MapWindowPoints (pScreenPriv->hwndScreen, HWND_DESKTOP, (LPPOINT)&rcClient, 2); /* Create a DirectDraw object, store the address at lpdd */ ddrval = (*g_fpDirectDrawCreate) (NULL, &pScreenPriv->pdd, NULL); if (ddrval != DD_OK) FatalError ("winAllocateFBPrimaryDD - Could not start DirectDraw\n"); /* Get a DirectDraw2 interface pointer */ ddrval = IDirectDraw_QueryInterface (pScreenPriv->pdd, &IID_IDirectDraw2, (LPVOID*) &pScreenPriv->pdd2); if (FAILED (ddrval)) { ErrorF ("winAllocateFBShadowDD - Failed DD2 query: %08x\n", ddrval); return FALSE; } ErrorF ("winAllocateFBPrimaryDD - Created and initialized DD\n"); /* Are we windowed or fullscreen? */ if (pScreenInfo->fFullScreen) { /* Full screen mode */ ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, pScreenPriv->hwndScreen, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); if (FAILED (ddrval)) FatalError ("winAllocateFBPrimaryDD - Could not set " "cooperative level\n"); /* Change the video mode to the mode requested */ ddrval = IDirectDraw2_SetDisplayMode (pScreenPriv->pdd2, pScreenInfo->dwWidth, pScreenInfo->dwHeight, pScreenInfo->dwBPP, pScreenInfo->dwRefreshRate, 0); if (FAILED (ddrval)) FatalError ("winAllocateFBPrimaryDD - Could not set " "full screen display mode\n"); } else { /* Windowed mode */ ddrval = IDirectDraw2_SetCooperativeLevel (pScreenPriv->pdd2, pScreenPriv->hwndScreen, DDSCL_NORMAL); if (FAILED (ddrval)) FatalError ("winAllocateFBPrimaryDD - Could not set " "cooperative level\n"); } /* Describe the primary surface */ ZeroMemory (&ddsd, sizeof (ddsd)); ddsd.dwSize = sizeof (ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; /* Create the primary surface */ ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, &ddsd, &pScreenPriv->pddsPrimary, NULL); if (FAILED (ddrval)) FatalError ("winAllocateFBPrimaryDD - Could not create primary " "surface %08x\n", ddrval); ErrorF ("winAllocateFBPrimaryDD - Created primary\n"); /* Allocate a DD surface description for our screen privates */ pddsdPrimary = pScreenPriv->pddsdPrimary = malloc (sizeof (DDSURFACEDESC)); if (pddsdPrimary == NULL) FatalError ("winAllocateFBPrimaryDD - Could not allocate surface " "description memory\n"); ZeroMemory (pddsdPrimary, sizeof (*pddsdPrimary)); pddsdPrimary->dwSize = sizeof (*pddsdPrimary); /* Describe the offscreen surface to be created */ /* * NOTE: Do not use a DDSCAPS_VIDEOMEMORY surface, * as drawing, locking, and unlocking take forever * with video memory surfaces. In addition, * video memory is a somewhat scarce resource, * so you shouldn't be allocating video memory when * you have the option of using system memory instead. */ ZeroMemory (&ddsd, sizeof (ddsd)); ddsd.dwSize = sizeof (ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwHeight = pScreenInfo->dwHeight; ddsd.dwWidth = pScreenInfo->dwWidth; /* Create the shadow surface */ ddrval = IDirectDraw2_CreateSurface (pScreenPriv->pdd2, &ddsd, &pScreenPriv->pddsOffscreen, NULL); if (ddrval != DD_OK) FatalError ("winAllocateFBPrimaryDD - Could not create shadow " "surface\n"); ErrorF ("winAllocateFBPrimaryDD - Created offscreen\n"); /* Allocate a DD surface description for our screen privates */ pddsdOffscreen = pScreenPriv->pddsdOffscreen = malloc (sizeof (DDSURFACEDESC)); if (pddsdOffscreen == NULL) FatalError ("winAllocateFBPrimaryDD - Could not allocate surface " "description memory\n"); ZeroMemory (pddsdOffscreen, sizeof (*pddsdOffscreen)); pddsdOffscreen->dwSize = sizeof (*pddsdOffscreen); ErrorF ("winAllocateFBPrimaryDD - Locking primary\n"); /* Lock the primary surface */ ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsPrimary, pScreenInfo->fFullScreen ? NULL:&rcClient, pddsdPrimary, DDLOCK_WAIT, NULL); if (ddrval != DD_OK || pddsdPrimary->lpSurface == NULL) FatalError ("winAllocateFBPrimaryDD - Could not lock " "primary surface\n"); ErrorF ("winAllocateFBPrimaryDD - Locked primary\n"); /* We don't know how to deal with anything other than RGB */ if (!(pddsdPrimary->ddpfPixelFormat.dwFlags & DDPF_RGB)) FatalError ("winAllocateFBPrimaryDD - Color format other than RGB\n"); /* Grab the pitch from the surface desc */ pScreenInfo->dwStride = (pddsdPrimary->u1.lPitch * 8) / pScreenInfo->dwBPP; /* Save the pointer to our surface memory */ pScreenInfo->pfb = pddsdPrimary->lpSurface; /* Grab the color depth and masks from the surface description */ pScreenPriv->dwRedMask = pddsdPrimary->ddpfPixelFormat.u2.dwRBitMask; pScreenPriv->dwGreenMask = pddsdPrimary->ddpfPixelFormat.u3.dwGBitMask; pScreenPriv->dwBlueMask = pddsdPrimary->ddpfPixelFormat.u4.dwBBitMask; ErrorF ("winAllocateFBPrimaryDD - Returning\n"); return TRUE; } /* * Call the wrapped CloseScreen function. * * Free our resources and private structures. */ Bool winCloseScreenPrimaryDD (int nIndex, ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; Bool fReturn; ErrorF ("winCloseScreenPrimaryDD - Freeing screen resources\n"); /* Flag that the screen is closed */ pScreenPriv->fClosed = TRUE; pScreenPriv->fActive = FALSE; /* Call the wrapped CloseScreen procedure */ pScreen->CloseScreen = pScreenPriv->CloseScreen; fReturn = (*pScreen->CloseScreen) (nIndex, pScreen); /* Delete the window property */ RemoveProp (pScreenPriv->hwndScreen, WIN_SCR_PROP); /* Free the offscreen surface, if there is one */ if (pScreenPriv->pddsOffscreen) { IDirectDrawSurface2_Unlock (pScreenPriv->pddsOffscreen, NULL); IDirectDrawSurface2_Release (pScreenPriv->pddsOffscreen); pScreenPriv->pddsOffscreen = NULL; } /* Release the primary surface, if there is one */ if (pScreenPriv->pddsPrimary) { IDirectDrawSurface2_Unlock (pScreenPriv->pddsPrimary, NULL); IDirectDrawSurface2_Release (pScreenPriv->pddsPrimary); pScreenPriv->pddsPrimary = NULL; } /* Free the DirectDraw object, if there is one */ if (pScreenPriv->pdd) { IDirectDraw2_RestoreDisplayMode (pScreenPriv->pdd); IDirectDraw2_Release (pScreenPriv->pdd); pScreenPriv->pdd = NULL; } /* Delete tray icon, if we have one */ if (!pScreenInfo->fNoTrayIcon) winDeleteNotifyIcon (pScreenPriv); /* Free the exit confirmation dialog box, if it exists */ if (g_hDlgExit != NULL) { DestroyWindow (g_hDlgExit); g_hDlgExit = NULL; } /* Kill our window */ if (pScreenPriv->hwndScreen) { DestroyWindow (pScreenPriv->hwndScreen); pScreenPriv->hwndScreen = NULL; } /* Kill our screeninfo's pointer to the screen */ pScreenInfo->pScreen = NULL; /* Invalidate the ScreenInfo's fb pointer */ pScreenInfo->pfb = NULL; /* Free the screen privates for this screen */ free ((pointer) pScreenPriv); return fReturn; } /* * Tell mi what sort of visuals we need. * * Generally we only need one visual, as our screen can only * handle one format at a time, I believe. You may want * to verify that last sentence. */ Bool winInitVisualsPrimaryDD (ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; DWORD dwRedBits, dwGreenBits, dwBlueBits; /* Count the number of ones in each color mask */ dwRedBits = winCountBits (pScreenPriv->dwRedMask); dwGreenBits = winCountBits (pScreenPriv->dwGreenMask); dwBlueBits = winCountBits (pScreenPriv->dwBlueMask); /* Store the maximum number of ones in a color mask as the bitsPerRGB */ if (dwRedBits > dwGreenBits && dwRedBits > dwBlueBits) pScreenPriv->dwBitsPerRGB = dwRedBits; else if (dwGreenBits > dwRedBits && dwGreenBits > dwBlueBits) pScreenPriv->dwBitsPerRGB = dwGreenBits; else pScreenPriv->dwBitsPerRGB = dwBlueBits; ErrorF ("winInitVisualsPrimaryDD - Masks: %08x %08x %08x bpRGB: %d\n", pScreenPriv->dwRedMask, pScreenPriv->dwGreenMask, pScreenPriv->dwBlueMask, pScreenPriv->dwBitsPerRGB); /* Create a single visual according to the Windows screen depth */ switch (pScreenInfo->dwDepth) { case 24: case 16: case 15: if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, TrueColorMask, pScreenPriv->dwBitsPerRGB, TrueColor, pScreenPriv->dwRedMask, pScreenPriv->dwGreenMask, pScreenPriv->dwBlueMask)) { ErrorF ("winInitVisualsPrimaryDD - " "miSetVisualTypesAndMasks failed\n"); return FALSE; } break; case 8: #if CYGDEBUG ErrorF ("winInitVisuals - Calling miSetVisualTypesAndMasks\n"); #endif /* CYGDEBUG */ if (!miSetVisualTypesAndMasks (pScreenInfo->dwDepth, PseudoColorMask, pScreenPriv->dwBitsPerRGB, PseudoColor, pScreenPriv->dwRedMask, pScreenPriv->dwGreenMask, pScreenPriv->dwBlueMask)) { ErrorF ("winInitVisualsPrimaryDD - " "miSetVisualTypesAndMasks failed\n"); return FALSE; } #if CYGDEBUG ErrorF ("winInitVisualsPrimaryDD - Returned from " "miSetVisualTypesAndMasks\n"); #endif /* CYGDEBUG */ break; default: ErrorF ("winInitVisualsPrimaryDD - Unknown screen depth\n"); return FALSE; } ErrorF ("winInitVisualsPrimaryDD - Returning\n"); return TRUE; } Bool winAdjustVideoModePrimaryDD (ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; HDC hdc = NULL; DWORD dwBPP; /* We're in serious trouble if we can't get a DC */ hdc = GetDC (NULL); if (hdc == NULL) { ErrorF ("winAdjustVideoModePrimaryDD - GetDC failed\n"); return FALSE; } /* Query GDI for current display depth */ dwBPP = GetDeviceCaps (hdc, BITSPIXEL); /* DirectDraw can only change the depth in fullscreen mode */ if (pScreenInfo->dwBPP == WIN_DEFAULT_BPP) { /* No -depth parameter passed, let the user know the depth being used */ ErrorF ("winAdjustVideoModePrimaryDD - Using Windows display " "depth of %d bits per pixel\n", dwBPP); /* Use GDI's depth */ pScreenInfo->dwBPP = dwBPP; } else if (pScreenInfo->fFullScreen && pScreenInfo->dwBPP != dwBPP) { /* FullScreen, and GDI depth differs from -depth parameter */ ErrorF ("winAdjustVideoModePrimaryDD - FullScreen, using command " "line depth: %d\n", pScreenInfo->dwBPP); } else if (dwBPP != pScreenInfo->dwBPP) { /* Windowed, and GDI depth differs from -depth parameter */ ErrorF ("winAdjustVideoModePrimaryDD - Windowed, command line " "depth: %d, using depth: %d\n", pScreenInfo->dwBPP, dwBPP); /* We'll use GDI's depth */ pScreenInfo->dwBPP = dwBPP; } /* Release our DC */ ReleaseDC (NULL, hdc); return TRUE; } /* * We need to blit our offscreen fb to * the screen when we are activated, and we need to point * the fb code back to the primary surface memory. */ Bool winActivateAppPrimaryDD (ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; RECT rcSrc, rcClient; HRESULT ddrval = DD_OK; /* Check for errors */ if (pScreenPriv == NULL || pScreenPriv->pddsPrimary == NULL || pScreenPriv->pddsOffscreen == NULL) return FALSE; /* Check for do-nothing */ if (!pScreenPriv->fActive) return TRUE; /* We are activating */ ddrval = IDirectDrawSurface2_IsLost (pScreenPriv->pddsOffscreen); if (ddrval == DD_OK) { IDirectDrawSurface2_Unlock (pScreenPriv->pddsOffscreen, NULL); /* * We don't check for an error from Unlock, because it * doesn't matter if the Unlock failed. */ } /* Restore both surfaces, just cause I like it that way */ IDirectDrawSurface2_Restore (pScreenPriv->pddsOffscreen); IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); /* Get client area in screen coords */ GetClientRect (pScreenPriv->hwndScreen, &rcClient); MapWindowPoints (pScreenPriv->hwndScreen, HWND_DESKTOP, (LPPOINT)&rcClient, 2); /* Setup a source rectangle */ rcSrc.left = 0; rcSrc.top = 0; rcSrc.right = pScreenInfo->dwWidth; rcSrc.bottom = pScreenInfo->dwHeight; ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsPrimary, &rcClient, pScreenPriv->pddsOffscreen, &rcSrc, DDBLT_WAIT, NULL); if (ddrval != DD_OK) FatalError ("winActivateAppPrimaryDD () - Failed blitting offscreen " "surface to primary surface %08x\n", ddrval); /* Lock the primary surface */ ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsPrimary, &rcClient, pScreenPriv->pddsdPrimary, DDLOCK_WAIT, NULL); if (ddrval != DD_OK || pScreenPriv->pddsdPrimary->lpSurface == NULL) FatalError ("winActivateAppPrimaryDD () - Could not lock " "primary surface\n"); /* Notify FB of the new memory pointer */ winUpdateFBPointer (pScreen, pScreenPriv->pddsdPrimary->lpSurface); /* * Register the Alt-Tab combo as a hotkey so we can copy * the primary framebuffer before the display mode changes */ RegisterHotKey (pScreenPriv->hwndScreen, 1, MOD_ALT, 9); return TRUE; } /* * Handle the Alt+Tab hotkey. * * We need to save the primary fb to an offscreen fb when * we get deactivated, and point the fb code at the offscreen * fb for the duration of the deactivation. */ Bool winHotKeyAltTabPrimaryDD (ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; RECT rcClient, rcSrc; HRESULT ddrval = DD_OK; ErrorF ("\nwinHotKeyAltTabPrimaryDD\n\n"); /* Alt+Tab was pressed, we will lose focus very soon */ pScreenPriv->fActive = FALSE; /* Check for error conditions */ if (pScreenPriv->pddsPrimary == NULL || pScreenPriv->pddsOffscreen == NULL) return FALSE; /* Get client area in screen coords */ GetClientRect (pScreenPriv->hwndScreen, &rcClient); MapWindowPoints (pScreenPriv->hwndScreen, HWND_DESKTOP, (LPPOINT)&rcClient, 2); /* Did we loose the primary surface? */ ddrval = IDirectDrawSurface2_IsLost (pScreenPriv->pddsPrimary); if (ddrval == DD_OK) { ddrval = IDirectDrawSurface2_Unlock (pScreenPriv->pddsPrimary, NULL); if (FAILED (ddrval)) FatalError ("winHotKeyAltTabPrimaryDD - Failed unlocking primary " "surface\n"); } /* Setup a source rectangle */ rcSrc.left = 0; rcSrc.top = 0; rcSrc.right = pScreenInfo->dwWidth; rcSrc.bottom = pScreenInfo->dwHeight; /* Blit the primary surface to the offscreen surface */ ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsOffscreen, NULL, /* should be rcDest */ pScreenPriv->pddsPrimary, NULL, DDBLT_WAIT, NULL); if (ddrval == DDERR_SURFACELOST) { IDirectDrawSurface2_Restore (pScreenPriv->pddsOffscreen); IDirectDrawSurface2_Restore (pScreenPriv->pddsPrimary); /* Blit the primary surface to the offscreen surface */ ddrval = IDirectDrawSurface2_Blt (pScreenPriv->pddsOffscreen, NULL, pScreenPriv->pddsPrimary, NULL, DDBLT_WAIT, NULL); if (FAILED (ddrval)) FatalError ("winHotKeyAltTabPrimaryDD - Failed blitting primary " "surface to offscreen surface: %08x\n", ddrval); } else { FatalError ("winHotKeyAltTabPrimaryDD - Unknown error from " "Blt: %08dx\n", ddrval); } /* Lock the offscreen surface */ ddrval = IDirectDrawSurface2_Lock (pScreenPriv->pddsOffscreen, NULL, pScreenPriv->pddsdOffscreen, DDLOCK_WAIT, NULL); if (ddrval != DD_OK || pScreenPriv->pddsdPrimary->lpSurface == NULL) FatalError ("winHotKeyAltTabPrimaryDD - Could not lock " "offscreen surface\n"); /* Notify FB of the new memory pointer */ winUpdateFBPointer (pScreen, pScreenPriv->pddsdOffscreen->lpSurface); /* Unregister our hotkey */ UnregisterHotKey (pScreenPriv->hwndScreen, 1); return TRUE; } /* Set engine specific functions */ Bool winSetEngineFunctionsPrimaryDD (ScreenPtr pScreen) { winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; /* Set our pointers */ pScreenPriv->pwinAllocateFB = winAllocateFBPrimaryDD; pScreenPriv->pwinShadowUpdate = (winShadowUpdateProcPtr) (void (*)())NoopDDA; pScreenPriv->pwinCloseScreen = winCloseScreenPrimaryDD; pScreenPriv->pwinInitVisuals = winInitVisualsPrimaryDD; pScreenPriv->pwinAdjustVideoMode = winAdjustVideoModePrimaryDD; if (pScreenInfo->fFullScreen) pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowFullScreen; else pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; pScreenPriv->pwinBltExposedRegions = (winBltExposedRegionsProcPtr) (void (*)())NoopDDA; pScreenPriv->pwinActivateApp = winActivateAppPrimaryDD; pScreenPriv->pwinHotKeyAltTab = winHotKeyAltTabPrimaryDD; return TRUE; }