/******************************Module*Header**********************************\ * * ******************* * * GDI SAMPLE CODE * * ******************* * * Module Name: pointer.c * * This module contains the hardware pointer support for the display driver. * We also have support for color space double buffering using the RAMDAC pixel * read mask. * * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved. \*****************************************************************************/ #include "precomp.h" #include "pointer.h" #include "tvp4020.h" #include "p2rd.h" #include "gdi.h" #include "heap.h" // // Look-up table for masking the right edge of the given pointer bitmap: // BYTE gajMask[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, }; UCHAR nibbleToByteP2RD[] = { 0x00, // 0000 --> 00000000 0x80, // 0001 --> 10000000 0x20, // 0010 --> 00100000 0xA0, // 0011 --> 10100000 0x08, // 0100 --> 00001000 0x88, // 0101 --> 10001000 0x28, // 0110 --> 00101000 0xA8, // 0111 --> 10101000 0x02, // 1000 --> 00000010 0x82, // 1001 --> 10000010 0x22, // 1010 --> 00100010 0xA2, // 1011 --> 10100010 0x0A, // 1100 --> 00001010 0x8A, // 1101 --> 10001010 0x2A, // 1110 --> 00101010 0xAA, // 1111 --> 10101010 }; //----------------------------------------------------------------------------- // // LONG HWPointerCacheInit() // // Initialise the hardware pointer cache. // //----------------------------------------------------------------------------- VOID HWPointerCacheInit(HWPointerCache* ptrCache) { ptrCache->cPtrCacheInUseCount = 0; ptrCache->ptrCacheCurTimeStamp = 0; }// HWPointerCacheInit() //----------------------------------------------------------------------------- // // 64 x 64 Hardware Pointer Caching // -------------------------------- // The code below implements hardware independent caching of pointers. It // maintains a cache big enough to store ONE 64x64 cursor or FOUR 32x32 // cursors. The code will work with all RAMDACs that support this form of // caching. // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // LONG HWPointerCacheCheckAndAdd() // // This function does a byte-by-byte comparison of the supplied pointer data // with each pointer that is in cache, if it finds a matching one then it // returns the index of the item in the cache (0 to 3) otherwise it adds it to // the cache and returns the index. // //----------------------------------------------------------------------------- LONG HWPointerCacheCheckAndAdd(HWPointerCache* ptrCache, HSURF hsurf, ULONG ulKey, BOOL* isCached) { BOOL pointerIsCached = FALSE; LONG i, j, z; LONG cacheItem; DBG_GDI((6, "HWPointerCacheCheckAndAdd called")); // // If there are entries in the cache and they are the same format as the // one that we are looking for then search the cache. // if ( ptrCache->cPtrCacheInUseCount ) { DBG_GDI((6, "Found entry in cache with the same format")); // // Search the cache // LONG lTotalcached = ptrCache->cPtrCacheInUseCount; // // Examine all valid entries in the cache to see if they are the same // as the pointer that we've been handed based on its unique key number // and the surface handle. // Note: the reason we check "hsurf" here is that it is possible that // two surfaces has the same iUniq number since Every time the surface // changes this value is incremented // for ( z = 0; !pointerIsCached && z < lTotalcached; z++ ) { if ( (ulKey == ptrCache->ptrCacheItemList[z].ulKey) &&(hsurf == ptrCache->ptrCacheItemList[z].hsurf) ) { cacheItem = z; pointerIsCached = TRUE; } }// loop through all the cached items }// Found entry in cache with the same format DBG_GDI((6, "Found an entry in cache (%s)", pointerIsCached?"YES":"NO")); // // If we couldn't find an entry in the pointer cache then add one to the // cache. // if ( !pointerIsCached ) { // // Add the pointer to the cache // LONG z2; // // If there are some spare entries then allocate a free entry, otherwise // find the least recently used entry and use that. // if ( ptrCache->cPtrCacheInUseCount < SMALL_POINTER_MAX ) { cacheItem = ptrCache->cPtrCacheInUseCount++; } else { ULONG oldestValue = 0xFFFFFFFF; // // Look for the LRU entry // for ( z2 = 0, cacheItem = 0; z2 < SMALL_POINTER_MAX; z2++ ) { if ( ptrCache->ptrCacheItemList[z2].ptrCacheTimeStamp < oldestValue ) { cacheItem = z2; oldestValue = ptrCache->ptrCacheItemList[z2].ptrCacheTimeStamp; } } }// Determine cacheItem ptrCache->ptrCacheItemList[cacheItem].ulKey = ulKey; ptrCache->ptrCacheItemList[cacheItem].hsurf = hsurf; }// If not found entry, add one // // Set the timestamp // ptrCache->ptrCacheItemList[cacheItem].ptrCacheTimeStamp = ptrCache->ptrCacheCurTimeStamp++; // // Set up the return value to say whether the pointer was cached and return // the number of the current cached position // *isCached = pointerIsCached; DBG_GDI((6, "HWPointerCacheCheckAndAdd finished and return item %d", cacheItem)); return(cacheItem); }// HWPointerCacheCheckAndAdd() //----------------------------------------------------------------------------- // // VOID vShowPointerP2RD() // // Show or hide the 3Dlabs P2RD hardware pointer. // //----------------------------------------------------------------------------- VOID vShowPointerP2RD(PDev* ppdev, BOOL bShow) { ULONG cmr; PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; P2RD_DECL_INIT; DBG_GDI((6, "vShowPointerP2RD (%s)", bShow ? "on" : "off")); if ( bShow ) { // // No need to sync since this case is called only if we've just // moved the cursor and that will already have done a sync. // P2RD_LOAD_INDEX_REG(P2RD_CURSOR_MODE, (pP2RDinfo->cursorModeCurrent | P2RD_CURSOR_MODE_ENABLED)); P2RD_MOVE_CURSOR (pP2RDinfo->x, pP2RDinfo->y); } else { // // move the cursor off screen // P2RD_LOAD_INDEX_REG(P2RD_CURSOR_Y_HIGH, 0xff); } }// vShowPointerP2RD() //----------------------------------------------------------------------------- // // VOID vMovePointerP2RD() // // Move the 3Dlabs P2RD hardware pointer. // //----------------------------------------------------------------------------- VOID vMovePointerP2RD(PDev* ppdev, LONG x, LONG y) { PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; P2RD_DECL_INIT; DBG_GDI((6, "vMovePointerP2RD to (%d, %d)", x, y)); pP2RDinfo->x = x; pP2RDinfo->y = y; P2RD_SYNC_WITH_PERMEDIA; P2RD_MOVE_CURSOR(x, y); }// vMovePointerP2RD() //----------------------------------------------------------------------------- // // BOOL bSet3ColorPointerShapeP2RD() // // Stores the 3-color cursor in the RAMDAC: currently only 32bpp and 15/16bpp // cursors are supported // //----------------------------------------------------------------------------- BOOL bSet3ColorPointerShapeP2RD(PDev* ppdev, SURFOBJ* psoMask, // defines AND and MASK bits // for cursor SURFOBJ* psoColor, // we may handle some color // cursors at some point LONG x, // If -1, pointer should be // created hidden LONG y, LONG xHot, LONG yHot) { LONG cx, cy; LONG cxcyCache; LONG cjCacheRow, cjCacheRemx, cjCacheRemy, cj; BYTE *pjAndMask, *pj; ULONG *pulColor, *pul; LONG cjAndDelta, cjColorDelta; LONG iRow, iCol; BYTE AndBit, AndByte; ULONG CI2ColorIndex, CI2ColorData; ULONG ulColor; ULONG aulColorsIndexed[3]; LONG Index, HighestIndex = 0; ULONG r, g, b; PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; P2RD_DECL_INIT; DBG_GDI((6, "bSet3ColorPointerShapeP2RD started")); cx = psoColor->sizlBitmap.cx; cy = psoColor->sizlBitmap.cy; if ( cx <= 32 && cy <= 32 ) { // // 32x32 cursor : we'll cache it in cursor partition 0 and scrub the // old cache // cxcyCache = 32; pP2RDinfo->cursorSize = P2RD_CURSOR_SIZE_32_3COLOR; pP2RDinfo->cursorModeCurrent = pP2RDinfo->cursorModeOff | P2RD_CURSOR_SEL(pP2RDinfo->cursorSize, 0) | P2RD_CURSOR_MODE_3COLOR; // // We don't cache color cursors // HWPointerCacheInvalidate (&(ppdev->HWPtrCache)); } else if ( cx <= 64 && cy <= 64 ) { // // 64x64 cursor : we'll cache it in cursor partition 0 and scrub the // old cache // cxcyCache = 64; pP2RDinfo->cursorSize = P2RD_CURSOR_SIZE_64_3COLOR; pP2RDinfo->cursorModeCurrent = pP2RDinfo->cursorModeOff | P2RD_CURSOR_SEL(pP2RDinfo->cursorSize, 0) | P2RD_CURSOR_MODE_3COLOR; // // We don't cache color cursors // HWPointerCacheInvalidate (&(ppdev->HWPtrCache)); } else { DBG_GDI((6, "declining cursor: %d x %d is too big", cx, cy)); return(FALSE); // cursor is too big to fit in the hardware } // // work out the remaining bytes in the cache (in x and y) that will need // clearing // cjCacheRow = 2 * cxcyCache / 8; cjCacheRemx = cjCacheRow - 2 * ((cx+7) / 8); cjCacheRemy = (cxcyCache - cy) * cjCacheRow; // // Set-up a pointer to the 1bpp AND mask bitmap // pjAndMask = (UCHAR*)psoMask->pvScan0; cjAndDelta = psoMask->lDelta; // // Set-up a pointer to the 32bpp color bitmap // pulColor = (ULONG*)psoColor->pvScan0; cjColorDelta = psoColor->lDelta; // // Hide the pointer // vShowPointerP2RD(ppdev, FALSE); // // Load the cursor array (we have auto-increment turned on so initialize // to entry 0 here) // P2RD_CURSOR_ARRAY_START(0); for ( iRow = 0; iRow < cy; ++iRow, pjAndMask += cjAndDelta, pulColor = (ULONG*)((BYTE*)pulColor+cjColorDelta) ) { DBG_GDI((7, "bSet3ColorPointerShapeP2RD: Row %d (of %d): pjAndMask(%p) pulColor(%p)", iRow, cy, pjAndMask, pulColor)); pj = pjAndMask; pul = pulColor; CI2ColorIndex = CI2ColorData = 0; for ( iCol = 0; iCol < cx; ++iCol, CI2ColorIndex += 2 ) { AndBit = (BYTE)(7 - (iCol & 7)); if ( AndBit == 7 ) { // // We're onto the next byte of the and mask // AndByte = *pj++; } if ( CI2ColorIndex == 8 ) { // // We've filled a byte with 4 CI2 colors // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: writing cursor data %xh", CI2ColorData)); P2RD_LOAD_CURSOR_ARRAY(CI2ColorData); CI2ColorData = 0; CI2ColorIndex = 0; } // // Get the source pixel // if ( ppdev->cPelSize == P2DEPTH32 ) { ulColor = *pul++; } else { ulColor = *(USHORT*)pul; pul = (ULONG*)((USHORT*)pul + 1); } DBG_GDI((7, "bSet3ColorPointerShapeP2RD: Column %d (of %d) AndByte(%08xh) AndBit(%d) ulColor(%08xh)", iCol, cx, AndByte, AndBit, ulColor)); // // Figure out what to do with it:- // AND Color Result // 0 X color // 1 0 transparent // 1 1 inverse // if ( AndByte & (1 << AndBit) ) { // // Transparent or inverse // if ( ulColor == 0 ) { // // color == black: // transparent and seeing as the CI2ColorData is // initialized to 0 we don't have to explicitly clear these // bits - go on to the next pixel // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: transparent - ignore")); continue; } if ( ulColor == ppdev->ulWhite ) { // // color == white: // inverse, but we don't support this. We've destroyed the // cache for nothing // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: failed - inverted colors aren't supported")); return(FALSE); } } // // Get the index for this color: first see if we've already indexed // it // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: looking up color %08xh", ulColor)); for ( Index = 0; Index < HighestIndex && aulColorsIndexed[Index] != ulColor; ++Index ); if ( Index == 3 ) { // // Too many colors in this cursor // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: failed - cursor has more than 3 colors")); return(FALSE); } else if ( Index == HighestIndex ) { // // We've found another color: add it to the color index // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: adding %08xh to cursor palette", ulColor)); aulColorsIndexed[HighestIndex++] = ulColor; } // // Add this pixel's index to the CI2 cursor data. NB. Need Index+1 // as 0 == transparent // CI2ColorData |= (Index + 1) << CI2ColorIndex; } // // End of the cursor row: save the remaining indexed pixels then blank // any unused columns // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: writing remaining data for this row (%08xh) and %d trailing bytes", CI2ColorData, cjCacheRemx)); P2RD_LOAD_CURSOR_ARRAY(CI2ColorData); if ( cjCacheRemx ) { for ( cj = cjCacheRemx; --cj >=0; ) { P2RD_LOAD_CURSOR_ARRAY(P2RD_CURSOR_3_COLOR_TRANSPARENT); } } } // // End of cursor: blank any unused rows Nb. cjCacheRemy == cy blank // rows * cj bytes per row // DBG_GDI((7, "bSet3ColorPointerShapeP2RD: writing %d trailing bytes for this cursor", cjCacheRemy)); for ( cj = cjCacheRemy; --cj >= 0; ) { // // 0 == transparent // P2RD_LOAD_CURSOR_ARRAY(P2RD_CURSOR_3_COLOR_TRANSPARENT); } DBG_GDI((7, "bSet3ColorPointerShapeP2RD: setting up the cursor palette")); // // Now set-up the cursor palette // for ( iCol = 0; iCol < HighestIndex; ++iCol ) { // // The cursor colors are at native depth, convert them to 24bpp // if ( ppdev->cPelSize == P2DEPTH32 ) { // // 32bpp // b = 0xff & aulColorsIndexed[iCol]; g = 0xff & (aulColorsIndexed[iCol] >> 8); r = 0xff & (aulColorsIndexed[iCol] >> 16); } else { // // (ppdev->cPelSize == P2DEPTH16) // if ( ppdev->ulWhite == 0xffff ) { // // 16bpp // b = (0x1f & aulColorsIndexed[iCol]) << 3; g = (0x3f & (aulColorsIndexed[iCol] >> 5)) << 2; r = (0x1f & (aulColorsIndexed[iCol] >> 11)) << 3; } else { // // 15bpp // b = (0x1f & aulColorsIndexed[iCol]) << 3; g = (0x1f & (aulColorsIndexed[iCol] >> 5)) << 3; r = (0x1f & (aulColorsIndexed[iCol] >> 10)) << 3; } } P2RD_CURSOR_PALETTE_CURSOR_RGB(iCol, r, g, b); } // // Enable the cursor // P2RD_CURSOR_HOTSPOT(xHot, yHot); if ( x != -1 ) { vMovePointerP2RD (ppdev, x, y); // // Need to explicitly show the pointer if not using interrupts // vShowPointerP2RD(ppdev, TRUE); } DBG_GDI((6, "b3ColorSetPointerShapeP2RD done")); return(TRUE); }// bSet3ColorPointerShapeP2RD() //----------------------------------------------------------------------------- // // BOOL bSet15ColorPointerShapeP2RD // // Stores the 15-color cursor in the RAMDAC: currently only 32bpp and 15/16bpp // cursors are supported // //----------------------------------------------------------------------------- BOOL bSet15ColorPointerShapeP2RD(PDev* ppdev, SURFOBJ* psoMask, // defines AND and MASK // bits for cursor SURFOBJ* psoColor, // we may handle some color // cursors at some point LONG x, // If -1, pointer should be // created hidden LONG y, LONG xHot, LONG yHot) { LONG cx, cy; LONG cxcyCache; LONG cjCacheRow, cjCacheRemx, cjCacheRemy, cj; BYTE* pjAndMask; BYTE* pj; ULONG* pulColor; ULONG* pul; LONG cjAndDelta; LONG cjColorDelta; LONG iRow; LONG iCol; BYTE AndBit; BYTE AndByte; ULONG CI4ColorIndex; ULONG CI4ColorData; ULONG ulColor; ULONG aulColorsIndexed[15]; LONG Index; LONG HighestIndex = 0; ULONG r; ULONG g; ULONG b; PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; P2RD_DECL_INIT; DBG_GDI((6, "bSet15ColorPointerShapeP2RD started")); cx = psoColor->sizlBitmap.cx; cy = psoColor->sizlBitmap.cy; if ( cx <= 32 && cy <= 32 ) { // // 32x32 cursor : we'll cache it in cursor partition 0 and scrub the // old cache // cxcyCache = 32; pP2RDinfo->cursorSize = P2RD_CURSOR_SIZE_32_15COLOR; pP2RDinfo->cursorModeCurrent = pP2RDinfo->cursorModeOff | P2RD_CURSOR_SEL(pP2RDinfo->cursorSize, 0) | P2RD_CURSOR_MODE_15COLOR; // // We don't cache color cursors // HWPointerCacheInvalidate (&(ppdev->HWPtrCache)); } else if ( cx <= 64 && cy <= 64 ) { // // It's too big to cache as a fifteen color cursor, but we might just // be able to cache it if it has 3 or fewer colors // BOOL bRet; bRet = bSet3ColorPointerShapeP2RD(ppdev, psoMask, psoColor, x, y, xHot, yHot); return(bRet); } else { DBG_GDI((6, "declining cursor: %d x %d is too big", cx, cy)); return(FALSE); // cursor is too big to fit in the hardware } // // Work out the remaining bytes in the cache (in x and y) that will need // clearing // cjCacheRow = 2 * cxcyCache / 8; cjCacheRemx = cjCacheRow - 2 * ((cx+7) / 8); cjCacheRemy = (cxcyCache - cy) * cjCacheRow; // // Set-up a pointer to the 1bpp AND mask bitmap // pjAndMask = (UCHAR*)psoMask->pvScan0; cjAndDelta = psoMask->lDelta; // // Set-up a pointer to the 32bpp color bitmap // pulColor = (ULONG*)psoColor->pvScan0; cjColorDelta = psoColor->lDelta; // // Hide the pointer // vShowPointerP2RD(ppdev, FALSE); // // Load the cursor array (we have auto-increment turned on so initialize to // entry 0 here) // P2RD_CURSOR_ARRAY_START(0); for ( iRow = 0; iRow < cy; ++iRow, pjAndMask += cjAndDelta, pulColor = (ULONG*)((BYTE*)pulColor + cjColorDelta) ) { DBG_GDI((7, "bSet15ColorPointerShapeP2RD: Row %d (of %d): pjAndMask(%p) pulColor(%p)", iRow, cy, pjAndMask, pulColor)); pj = pjAndMask; pul = pulColor; CI4ColorIndex = CI4ColorData = 0; for ( iCol = 0; iCol < cx; ++iCol, CI4ColorIndex += 4 ) { AndBit = (BYTE)(7 - (iCol & 7)); if ( AndBit == 7 ) { // // We're onto the next byte of the and mask // AndByte = *pj++; } if ( CI4ColorIndex == 8 ) { // // We've filled a byte with 2 CI4 colors // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: writing cursor data %xh", CI4ColorData)); P2RD_LOAD_CURSOR_ARRAY(CI4ColorData); CI4ColorData = 0; CI4ColorIndex = 0; } // // Get the source pixel // if ( ppdev->cPelSize == P2DEPTH32 ) { ulColor = *pul++; } else { ulColor = *(USHORT *)pul; pul = (ULONG *)((USHORT *)pul + 1); } DBG_GDI((7, "bSet15ColorPointerShapeP2RD: Column %d (of %d) AndByte(%08xh) AndBit(%d) ulColor(%08xh)", iCol, cx, AndByte, AndBit, ulColor)); // // figure out what to do with it:- // AND Color Result // 0 X color // 1 0 transparent // 1 1 inverse if ( AndByte & (1 << AndBit) ) { // // Transparent or inverse // if ( ulColor == 0 ) { // // color == black: // Transparent and seeing as the CI2ColorData is initialized // to 0 we don't have to explicitly clear these bits - go on // to the next pixel // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: transparent - ignore")); continue; } if ( ulColor == ppdev->ulWhite ) { // // color == white: // Inverse, but we don't support this. We've destroyed the // cache for nothing // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: failed - inverted colors aren't supported")); return(FALSE); } } // // Get the index for this color: first see if we've already indexed // it // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: looking up color %08xh", ulColor)); for ( Index = 0; Index < HighestIndex && aulColorsIndexed[Index] != ulColor; ++Index ); if ( Index == 15 ) { // // Too many colors in this cursor // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: failed - cursor has more than 15 colors")); return(FALSE); } else if ( Index == HighestIndex ) { // // We've found another color: add it to the color index // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: adding %08xh to cursor palette", ulColor)); aulColorsIndexed[HighestIndex++] = ulColor; } // // Add this pixel's index to the CI4 cursor data. // Note: Need Index+1 as 0 == transparent // CI4ColorData |= (Index + 1) << CI4ColorIndex; } // // End of the cursor row: save the remaining indexed pixels then blank // any unused columns // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: writing remaining data for this row (%08xh) and %d trailing bytes", CI4ColorData, cjCacheRemx)); P2RD_LOAD_CURSOR_ARRAY(CI4ColorData); if ( cjCacheRemx ) { for ( cj = cjCacheRemx; --cj >=0; ) { P2RD_LOAD_CURSOR_ARRAY(P2RD_CURSOR_15_COLOR_TRANSPARENT); } } } // // End of cursor: blank any unused rows Nb. cjCacheRemy == cy blank // rows * cj bytes per row // DBG_GDI((7, "bSet15ColorPointerShapeP2RD: writing %d trailing bytes for this cursor", cjCacheRemy)); for ( cj = cjCacheRemy; --cj >= 0; ) { // // 0 == transparent // P2RD_LOAD_CURSOR_ARRAY(P2RD_CURSOR_15_COLOR_TRANSPARENT); } DBG_GDI((7, "bSet15ColorPointerShapeP2RD: setting up the cursor palette")); // now set-up the cursor palette for ( iCol = 0; iCol < HighestIndex; ++iCol ) { // // The cursor colors are at native depth, convert them to 24bpp // if ( ppdev->cPelSize == P2DEPTH32 ) { // // 32bpp // b = 0xff & aulColorsIndexed[iCol]; g = 0xff & (aulColorsIndexed[iCol] >> 8); r = 0xff & (aulColorsIndexed[iCol] >> 16); } else { // // (ppdev->cPelSize == P2DEPTH16) // if ( ppdev->ulWhite == 0xffff ) { // // 16bpp // b = (0x1f & aulColorsIndexed[iCol]) << 3; g = (0x3f & (aulColorsIndexed[iCol] >> 5)) << 2; r = (0x1f & (aulColorsIndexed[iCol] >> 11)) << 3; } else { // // 15bpp // b = (0x1f & aulColorsIndexed[iCol]) << 3; g = (0x1f & (aulColorsIndexed[iCol] >> 5)) << 3; r = (0x1f & (aulColorsIndexed[iCol] >> 10)) << 3; } } P2RD_CURSOR_PALETTE_CURSOR_RGB(iCol, r, g, b); } // // Enable the cursor // P2RD_CURSOR_HOTSPOT(xHot, yHot); if ( x != -1 ) { vMovePointerP2RD (ppdev, x, y); // // need to explicitly show the pointer if not using interrupts // vShowPointerP2RD(ppdev, TRUE); } DBG_GDI((6, "b3ColorSetPointerShapeP2RD done")); return(TRUE); }// bSet15ColorPointerShapeP2RD() //----------------------------------------------------------------------------- // // VOID vShowPointerTVP4020 // // Show or hide the TI TVP4020 hardware pointer. // //----------------------------------------------------------------------------- VOID vShowPointerTVP4020(PDev* ppdev, BOOL bShow) { ULONG ccr; PERMEDIA_DECL_VARS; TVP4020_DECL_VARS; PERMEDIA_DECL_INIT; TVP4020_DECL_INIT; DBG_GDI((6, "vShowPointerTVP4020 (%s)", bShow ? "on" : "off")); if ( bShow ) { // // No need to sync since this case is called only if we've just moved // the cursor and that will already have done a sync. // ccr = (pTVP4020info->cursorControlCurrent | TVP4020_CURSOR_XGA); } else { ccr = pTVP4020info->cursorControlOff & ~TVP4020_CURSOR_XGA; } TVP4020_WRITE_INDEX_REG(__TVP4020_CURSOR_CONTROL, ccr); }// vShowPointerTVP4020() //----------------------------------------------------------------------------- // // VOID vMovePointerTVP4020 // // Move the TI TVP4020 hardware pointer. // //----------------------------------------------------------------------------- VOID vMovePointerTVP4020(PDev* ppdev, LONG x, LONG y) { PERMEDIA_DECL_VARS; TVP4020_DECL_VARS; PERMEDIA_DECL_INIT; TVP4020_DECL_INIT; DBG_GDI((6, "vMovePointerTVP4020 to (%d, %d)", x, y)); TVP4020_MOVE_CURSOR(x + ppdev->xPointerHot , y + ppdev->yPointerHot); }// vMovePointerTVP4020() //----------------------------------------------------------------------------- // // BOOL bSetPointerShapeTVP4020 // // Set the TI TVP4020 hardware pointer shape. // // Parameters: // psoMask-----defines AND and MASK bits for cursor // psoColor----we may handle some color cursors at some point // x-----------If -1, pointer should be created hidden // //----------------------------------------------------------------------------- BOOL bSetPointerShapeTVP4020(PDev* ppdev, SURFOBJ* psoMask, SURFOBJ* psoColor, LONG x, LONG y, LONG xHot, LONG yHot) { ULONG cx; ULONG cy; ULONG i, iMax; ULONG j, jMax; BYTE bValue; BYTE* pjScan; LONG lDelta; ULONG cValid; ULONG ulMask; ULONG cursorRAMxOff; ULONG cursorRAMyOff; BOOL pointerIsCached; LONG cacheItem; PERMEDIA_DECL_VARS; TVP4020_DECL_VARS; PERMEDIA_DECL_INIT; TVP4020_DECL_INIT; DBG_GDI((6, "bSetPointerShapeTVP4020 started")); cx = psoMask->sizlBitmap.cx; // Note that 'sizlBitmap.cy' accounts cy = psoMask->sizlBitmap.cy >> 1; // for the double height due to the // inclusion of both the AND masks // and the XOR masks. We're // only interested in the true // pointer dimensions, so we divide // by 2. // // We currently don't handle colored cursors. Later, we could handle // cursors up to 64x64 with <= 3 colors. Checking this and setting it up // may be more trouble than it's worth. // if ( psoColor != NULL ) { DBG_GDI((6, "bSetPointerShapeTVP4020: declining colored cursor")); return FALSE; } // // We only handle 32x32. // if ( (cx > 32) || (cy > 32) ) { DBG_GDI((6, "declining cursor: %d x %d is too big", cx, cy)); return(FALSE); // cursor is too big to fit in the hardware } // // Check to see if the pointer is cached, add it to the cache if it isn't // DBG_GDI((6, "iUniq =%ld hsurf=0x%x", psoMask->iUniq, psoMask->hsurf)); cacheItem = HWPointerCacheCheckAndAdd(&(ppdev->HWPtrCache), psoMask->hsurf, psoMask->iUniq, &pointerIsCached); DBG_GDI((7, "bSetPointerShapeTVP4020: Add Cache iscac %d item %d", (int)pointerIsCached, cacheItem)); vMovePointerTVP4020(ppdev, 0, ppdev->cyScreen + 64); pTVP4020info->cursorControlCurrent = pTVP4020info->cursorControlOff | TVP4020_CURSOR_SIZE_32 | TVP4020_CURSOR_32_SEL(cacheItem); // // Cursor slots 1 & 3 have an x offset of 8 bytes, cursor slots 2 & 3 have // a y offset of 256 bytes // cursorRAMxOff = (cacheItem & 1) << 2; cursorRAMyOff = (cacheItem & 2) << 7; // // If the pointer is not cached, then download the pointer data to the DAC // if ( !pointerIsCached ) { // // Disable the pointer // TVP4020_WRITE_INDEX_REG(__TVP4020_CURSOR_CONTROL, pTVP4020info->cursorControlCurrent); cValid = (cx + 7) / 8; ulMask = gajMask[cx & 0x07]; if ( ulMask == 0 ) { ulMask = 0xFF; } pjScan = (UCHAR*)psoMask->pvScan0; lDelta = psoMask->lDelta; iMax = 32; // max rows for 32 x 32 cursor jMax = 4; // max column bytes // // Send cursor plane 0 - in our case XOR // for ( i = 0; i < iMax; ++i ) { TVP4020_CURSOR_ARRAY_START(CURSOR_PLANE0_OFFSET + cursorRAMyOff + (i * 8) + cursorRAMxOff); for ( j = 0; j < jMax; ++j ) { if ( (j < cValid) && ( i < cy ) ) { bValue = *(pjScan + j + (i + cy) * lDelta); } else { bValue = 0; } TVP4020_LOAD_CURSOR_ARRAY((ULONG)bValue); } } // // Send cursor plane 1 - in our case AND // for ( i = 0; i < iMax; ++i ) { TVP4020_CURSOR_ARRAY_START(CURSOR_PLANE1_OFFSET + cursorRAMyOff + (i * 8) + cursorRAMxOff); for ( j = 0; j < jMax; ++j ) { if ( (j < cValid) && ( i < cy ) ) { bValue = *(pjScan + j + i * lDelta); } else { bValue = 0xFF; } TVP4020_LOAD_CURSOR_ARRAY((ULONG)bValue); } } }// If pointer is not cached // // If the new cursor is different to the last cursor then set up the hot // spot and other bits'n'pieces. // if ( ppdev->HWPtrLastCursor != cacheItem || !pointerIsCached ) { // // Make this item the last item // ppdev->HWPtrLastCursor = cacheItem; ppdev->xPointerHot = 32 - xHot; ppdev->yPointerHot = 32 - yHot; } if ( x != -1 ) { vShowPointerTVP4020(ppdev, TRUE); vMovePointerTVP4020(ppdev, x, y); // Enable the cursor: } DBG_GDI((6, "bSetPointerShapeTVP4020 done")); return(TRUE); }// bSetPointerShapeTVP4020() //----------------------------------------------------------------------------- // // VOID vEnablePointerTVP4020 // // Get the hardware ready to use the TI TVP4020 hardware pointer. // //----------------------------------------------------------------------------- VOID vEnablePointerTVP4020(PDev* ppdev) { pTVP4020RAMDAC pRamdac; ULONG ulMask; PERMEDIA_DECL_VARS; TVP4020_DECL_VARS; PERMEDIA_DECL_INIT; DBG_GDI((6, "vEnablePointerTVP4020 called")); ppdev->pvPointerData = &ppdev->ajPointerData[0]; TVP4020_DECL_INIT; // // Get a pointer to the RAMDAC registers from the memory mapped // control register space. // pRamdac = (pTVP4020RAMDAC)(ppdev->pulRamdacBase); // // set up memory mapping for the control registers and save in the pointer // specific area provided in ppdev. // __TVP4020_PAL_WR_ADDR = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->pciAddrWr)); __TVP4020_PAL_RD_ADDR = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->pciAddrRd)); __TVP4020_PAL_DATA = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->palData)); __TVP4020_PIXEL_MASK = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->pixelMask)); __TVP4020_INDEX_DATA = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->indexData)); __TVP4020_CUR_RAM_DATA = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->curRAMData)); __TVP4020_CUR_RAM_WR_ADDR = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->pciAddrWr)); __TVP4020_CUR_RAM_RD_ADDR = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->pciAddrRd)); __TVP4020_CUR_COL_ADDR = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->curColAddr)); __TVP4020_CUR_COL_DATA = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->curColData)); __TVP4020_CUR_X_LSB = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->cursorXLow)); __TVP4020_CUR_X_MSB = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->cursorXHigh)); __TVP4020_CUR_Y_LSB = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->cursorYLow)); __TVP4020_CUR_Y_MSB = (UINT_PTR) TRANSLATE_ADDR_ULONG(&(pRamdac->cursorYHigh)); // // Initialize Cursor Control register. disables cursor. save a copy for // enabling/disabling and setting the size. Then reset the cursor position, // hot spot and colors. // // ulMask is used to prepare initial cursor control register // ulMask = TVP4020_CURSOR_RAM_MASK | TVP4020_CURSOR_MASK | TVP4020_CURSOR_SIZE_MASK; // // Set the cursor control to default values. // TVP4020_READ_INDEX_REG(__TVP4020_CURSOR_CONTROL, pTVP4020info->cursorControlOff); pTVP4020info->cursorControlOff &= ~ulMask; pTVP4020info->cursorControlOff |= TVP4020_CURSOR_OFF; TVP4020_WRITE_INDEX_REG(__TVP4020_CURSOR_CONTROL, pTVP4020info->cursorControlOff); pTVP4020info->cursorControlCurrent = pTVP4020info->cursorControlOff; ppdev->xPointerHot = 0; ppdev->yPointerHot = 0; // // Zero the RGB colors for foreground and background. The mono cursor is // always black and white so we don't have to reload these values again. // TVP4020_SET_CURSOR_COLOR0(0, 0, 0); TVP4020_SET_CURSOR_COLOR1(0xFF, 0xFF, 0xFF); }// vEnablePointerTVP4020() //----------------------------------------------------------------------------- // // BOOL bTVP4020CheckCSBuffering // // Determine whether we can do color space double buffering in the current // mode. // // Returns // TRUE if we can do the color space double buffering, FALSE otherwise. // //----------------------------------------------------------------------------- BOOL bTVP4020CheckCSBuffering(PDev* ppdev) { return FALSE; } //----------------------------------------------------------------------------- // // BOOL bSetPointerShapeP2RD // // Set the P2RD hardware pointer shape. // //----------------------------------------------------------------------------- BOOL bSetPointerShapeP2RD(PDev* ppdev, SURFOBJ* pso, // defines AND and MASK bits for cursor SURFOBJ* psoColor, // we may handle some color cursors at some point XLATEOBJ* pxlo, LONG x, // If -1, pointer should be created hidden LONG y, LONG xHot, LONG yHot) { ULONG cx; ULONG cy; LONG i; LONG j; ULONG ulValue; BYTE* pjAndScan; BYTE* pjXorScan; BYTE* pjAnd; BYTE* pjXor; BYTE andByte; BYTE xorByte; BYTE jMask; LONG lDelta; LONG cpelFraction; LONG cjWhole; LONG cClear; LONG cRemPels; BOOL pointerIsCached; LONG cacheItem; LONG cursorBytes; LONG cursorRAMOff; PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; P2RD_DECL_INIT; DBG_GDI((6, "bSetPointerShapeP2RD called")); if ( psoColor != NULL ) { Surf* psurfSrc = (Surf*)psoColor->dhsurf; // // It's a colored cursor // if ( (psoColor->dhsurf != NULL) ||(!(psoColor->iBitmapFormat == BMF_16BPP)) ||(psoColor->iBitmapFormat == BMF_32BPP) ) { // // Currently we only handle DIB cursors at 32bpp // DBG_GDI((2, "declining colored cursor - iType(%d) iBMPFormat(%d)", psoColor->iType, psoColor->iBitmapFormat)); return FALSE; } if ( pxlo != NULL ) { if ( pxlo->flXlate != XO_TRIVIAL ) { DBG_GDI((2, "declining colored cursor - flXlate(%xh)", pxlo->flXlate)); return FALSE; } } if ( !bSet15ColorPointerShapeP2RD(ppdev, pso, psoColor, x, y, xHot, yHot) ) { DBG_GDI((2, "declining colored cursor")); return FALSE; } DBG_GDI((6, "bSetPointerShapeP2RD done")); return(TRUE); }// if ( psoColor != NULL ) // // Note that 'sizlBitmap.cy' accounts for the double height due to the // inclusion of both the AND masks and the XOR masks. We're only // interested in the true pointer dimensions, so we divide by 2. // cx = pso->sizlBitmap.cx; cy = pso->sizlBitmap.cy >> 1; // // We can handle up to 64x64. cValid indicates the number of bytes // occupied by cursor on one line // if ( cx <= 32 && cy <= 32 ) { // // 32 horiz pixels: 2 bits per pixel, 1 horiz line per 8 bytes // pP2RDinfo->cursorSize = P2RD_CURSOR_SIZE_32_MONO; cursorBytes = 32 * 32 * 2 / 8; cClear = 8 - 2 * ((cx+7) / 8); cRemPels = (32 - cy) << 3; } else { DBG_GDI((6, "declining cursor: %d x %d is too big", cx, cy)); return(FALSE); // cursor is too big to fit in the hardware } // // Check to see if the pointer is cached, add it to the cache if it isn't // cacheItem = HWPointerCacheCheckAndAdd(&(ppdev->HWPtrCache), pso->hsurf, pso->iUniq, &pointerIsCached); DBG_GDI((7, "bSetPointerShapeP2RD: Add Cache iscac %d item %d", (int)pointerIsCached, cacheItem)); pP2RDinfo->cursorModeCurrent = pP2RDinfo->cursorModeOff | P2RD_CURSOR_SEL(pP2RDinfo->cursorSize, cacheItem); // // Hide the pointer // vShowPointerP2RD(ppdev, FALSE); if ( !pointerIsCached ) { // // Now we're going to take the requested pointer AND masks and XOR // masks and interleave them by taking a nibble at a time from each, // expanding each out and or'ing together. Use the nibbleToByteP2RD // array to help this. // // 'psoMsk' is actually cy * 2 scans high; the first 'cy' scans // define the AND mask. // pjAndScan = (UCHAR*)pso->pvScan0; lDelta = pso->lDelta; pjXorScan = pjAndScan + (cy * lDelta); cjWhole = cx >> 3; // Each byte accounts for 8 pels cpelFraction = cx & 0x7; // Number of fractional pels jMask = gajMask[cpelFraction]; // // We've got auto-increment turned on so just point to the first entry // to write to in the array then write repeatedly until the cursor // pattern has been transferred // cursorRAMOff = cacheItem * cursorBytes; P2RD_CURSOR_ARRAY_START(cursorRAMOff); for ( i = cy; --i >= 0; pjXorScan += lDelta, pjAndScan += lDelta ) { pjAnd = pjAndScan; pjXor = pjXorScan; // // Interleave nibbles from whole words. We are using Windows cursor // mode. // Note, the AND bit occupies the higher bit position for each // 2bpp cursor pel; the XOR bit is in the lower bit position. // The nibbleToByteP2RD array expands each nibble to occupy the bit // positions for the AND bytes. So when we use it to calculate the // XOR bits we shift the result right by 1. // for ( j = cjWhole; --j >= 0; ++pjAnd, ++pjXor ) { andByte = *pjAnd; xorByte = *pjXor; ulValue = nibbleToByteP2RD[andByte >> 4] | (nibbleToByteP2RD[xorByte >> 4] >> 1); P2RD_LOAD_CURSOR_ARRAY (ulValue); andByte &= 0xf; xorByte &= 0xf; ulValue = nibbleToByteP2RD[andByte] | (nibbleToByteP2RD[xorByte] >> 1); P2RD_LOAD_CURSOR_ARRAY (ulValue); } if ( cpelFraction ) { andByte = *pjAnd & jMask; xorByte = *pjXor & jMask; ulValue = nibbleToByteP2RD[andByte >> 4] | (nibbleToByteP2RD[xorByte >> 4] >> 1); P2RD_LOAD_CURSOR_ARRAY (ulValue); andByte &= 0xf; xorByte &= 0xf; ulValue = nibbleToByteP2RD[andByte] | (nibbleToByteP2RD[xorByte] >> 1); P2RD_LOAD_CURSOR_ARRAY (ulValue); } // // Finally clear out any remaining cursor pels on this line. // if ( cClear ) { for ( j = 0; j < cClear; ++j ) { P2RD_LOAD_CURSOR_ARRAY (P2RD_CURSOR_2_COLOR_TRANSPARENT); } } } // // If we've loaded fewer than the full number of lines configured in // the cursor RAM, clear out the remaining lines. cRemPels is // precalculated to be the number of lines * number of pels per line. // if ( cRemPels > 0 ) { do { P2RD_LOAD_CURSOR_ARRAY (P2RD_CURSOR_2_COLOR_TRANSPARENT); } while ( --cRemPels > 0 ); } }// if ( !pointerIsCached ) // // Now set-up the cursor colors // P2RD_CURSOR_PALETTE_CURSOR_RGB(0, 0x00, 0x00, 0x00); P2RD_CURSOR_PALETTE_CURSOR_RGB(1, 0xFF, 0xFF, 0xFF); // // If the new cursor is different to the last cursor then set up // the hot spot and other bits'n'pieces. As we currently only support // mono cursors we don't need to reload the cursor palette // if ( ppdev->HWPtrLastCursor != cacheItem || !pointerIsCached ) { // // Make this item the last item // ppdev->HWPtrLastCursor = cacheItem; P2RD_CURSOR_HOTSPOT(xHot, yHot); } if ( x != -1 ) { vMovePointerP2RD (ppdev, x, y); // // Need to explicitly show the pointer if not using interrupts // vShowPointerP2RD(ppdev, TRUE); } DBG_GDI((6, "bSetPointerShapeP2RD done")); return(TRUE); }// bSetPointerShapeP2RD() //----------------------------------------------------------------------------- // // VOID vEnablePointerP2RD // // Get the hardware ready to use the 3Dlabs P2RD hardware pointer. // //----------------------------------------------------------------------------- VOID vEnablePointerP2RD(PDev* ppdev) { pP2RDRAMDAC pRamdac; ULONG ul; PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; DBG_GDI((6, "vEnablePointerP2RD called")); ppdev->pvPointerData = &ppdev->ajPointerData[0]; P2RD_DECL_INIT; // // get a pointer to the RAMDAC registers from the memory mapped // control register space. // pRamdac = (pP2RDRAMDAC)(ppdev->pulRamdacBase); // // set up memory mapping for the control registers and save in the pointer // specific area provided in ppdev. // P2RD_PAL_WR_ADDR = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDPaletteWriteAddress)); P2RD_PAL_RD_ADDR = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDPaletteAddressRead)); P2RD_PAL_DATA = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDPaletteData)); P2RD_PIXEL_MASK = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDPixelMask)); P2RD_INDEX_ADDR_HI = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDIndexHigh)); P2RD_INDEX_ADDR_LO = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDIndexLow)); P2RD_INDEX_DATA = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDIndexedData)); P2RD_INDEX_CONTROL = (ULONG_PTR)TRANSLATE_ADDR_ULONG(&(pRamdac->RDIndexControl)); // // Not used, but set-up zero anyway // ppdev->xPointerHot = 0; ppdev->yPointerHot = 0; // // Enable auto-increment // ul = READ_P2RDREG_ULONG(P2RD_INDEX_CONTROL); ul |= P2RD_IDX_CTL_AUTOINCREMENT_ENABLED; WRITE_P2RDREG_ULONG(P2RD_INDEX_CONTROL, ul); P2RD_READ_INDEX_REG(P2RD_CURSOR_CONTROL, pP2RDinfo->cursorControl); pP2RDinfo->cursorModeCurrent = pP2RDinfo->cursorModeOff = 0; P2RD_LOAD_INDEX_REG(P2RD_CURSOR_MODE, pP2RDinfo->cursorModeOff); P2RD_INDEX_REG(P2RD_CURSOR_X_LOW); P2RD_LOAD_DATA(0); // cursor x low P2RD_LOAD_DATA(0); // cursor x high P2RD_LOAD_DATA(0); // cursor y low P2RD_LOAD_DATA(0xff); // cursor y high P2RD_LOAD_DATA(0); // cursor x hotspot P2RD_LOAD_DATA(0); // cursor y hotspot }// vEnablePointerP2RD() //----------------------------------------------------------------------------- // // BOOL bP2RDCheckCSBuffering // // Determine whether we can do color space double buffering in the current mode // // Returns // TRUE if we can do the color space double buffering, FALSE otherwise. // //----------------------------------------------------------------------------- BOOL bP2RDCheckCSBuffering(PDev* ppdev) { return (FALSE); }// bP2RDCheckCSBuffering() //----------------------------------------------------------------------------- // // BOOL bP2RDSwapCSBuffers // // Use the pixel read mask to perform color space double buffering. This is // only called when we have 12bpp with interleaved nibbles. We do a polled // wait for VBLANK before the swap. In the future we may do all this in the // miniport via interrupts. // // Returns // We should never be called if this is inappropriate so return TRUE. // //----------------------------------------------------------------------------- BOOL bP2RDSwapCSBuffers(PDev* ppdev, LONG bufNo) { ULONG index; ULONG color; PERMEDIA_DECL_VARS; P2RD_DECL_VARS; PERMEDIA_DECL_INIT; P2RD_DECL_INIT; // // Work out the RAMDAC read pixel mask for the buffer // DBG_GDI((6, "loading the palette to swap to buffer %d", bufNo)); P2RD_PALETTE_START_WR (0); if ( bufNo == 0 ) { for ( index = 0; index < 16; ++index ) for ( color = 0; color <= 0xff; color += 0x11 ) P2RD_LOAD_PALETTE (color, color, color); } else { for ( color = 0; color <= 0xff; color += 0x11 ) for ( index = 0; index < 16; ++index ) P2RD_LOAD_PALETTE (color, color, color); } return(TRUE); }// bP2RDSwapCSBuffers() //-------------------------------Public*Routine------------------------------- // // VOID DrvMovePointer // // This function moves the pointer to a new position and ensures that GDI does // not interfere with the display of the pointer. // // Parameters: // pso-------Points to a SURFOBJ structure that describes the surface of a // display device. // x,y-------Specify the x and y coordinates on the display where the hot spot // of the pointer should be positioned. // A negative x value indicates that the pointer should be removed // from the display because drawing is about to occur where it is // presently located. If the pointer has been removed from the display // and the x value is nonnegative, the pointer should be restored. // // A negative y value indicates that GDI is calling this function only // to notify the driver of the cursor's current position. The current // position can be computed as (x, y+pso->sizlBitmap.cy). // prcl------Points to a RECTL structure defining an area that bounds all pixels // affected by the pointer on the display. GDI will not draw in this // rectangle without first removing the pointer from the screen. This // parameter can be null. // // NOTE: Because we have set GCAPS_ASYNCMOVE, this call may occur at any // time, even while we're executing another drawing call! // //----------------------------------------------------------------------------- VOID DrvMovePointer(SURFOBJ* pso, LONG x, LONG y, RECTL* prcl) { PDev* ppdev = (PDev*)pso->dhpdev; DBG_GDI((6, "DrvMovePointer called, dhpdev(%xh), to pos(%ld, %ld)", ppdev, x, y)); // // A negative y value indicates that GDI is calling this function only to // notify the driver of the cursor's current position. So, at least, for // HW cursor, we don't need to move this pointer. Just return // if ( ( y < 0 ) && ( x > 0 ) ) { DBG_GDI((6, "DrvMovePointer return because x and y both < 0")); return; } DBG_GDI((6, "DrvMovePointer really moves HW pointer")); // // Negative X indicates that the pointer should be removed from the display // because drawing is about to occur where it is presently located. // if ( x > -1 ) { // // If we're doing any hardware zooming then the cusor position will // have to be doubled. // if ( (ppdev->flCaps & CAPS_P2RD_POINTER) == 0 ) { if ( ppdev->flCaps & CAPS_ZOOM_Y_BY2 ) { DBG_GDI((6,"HW zooming Y_BY2")); y *= 2; } if ( ppdev->flCaps & CAPS_ZOOM_X_BY2 ) { DBG_GDI((6,"HW zooming X_BY2")); x *= 2; } } // // If they have genuinely moved the cursor, then move it // if ( (x != ppdev->HWPtrPos_X) || (y != ppdev->HWPtrPos_Y) ) { if ( ppdev->flCaps & CAPS_TVP4020_POINTER ) { vMovePointerTVP4020(ppdev, x, y); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { vMovePointerP2RD(ppdev, x, y); } ppdev->HWPtrPos_X = x; ppdev->HWPtrPos_Y = y; } // // We may have to make the pointer visible: // if ( !(ppdev->flPointer & PTR_HW_ACTIVE) ) { DBG_GDI((6, "Showing hardware pointer")); ppdev->flPointer |= PTR_HW_ACTIVE; if ( ppdev->flCaps & CAPS_TVP4020_POINTER ) { vShowPointerTVP4020(ppdev, TRUE); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { vShowPointerP2RD(ppdev, TRUE); } } }// if ( x > -1 ) else if ( ppdev->flPointer & PTR_HW_ACTIVE ) { // // The pointer is visible, and we've been asked to hide it // DBG_GDI((6, "Hiding hardware pointer")); ppdev->flPointer &= ~PTR_HW_ACTIVE; if ( ppdev->flCaps & CAPS_TVP4020_POINTER ) { DBG_GDI((7, "Showing hardware pointer")); vShowPointerTVP4020(ppdev, FALSE); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { vShowPointerP2RD(ppdev, FALSE); } } // // Note that we don't have to modify 'prcl', since we have a // NOEXCLUDE pointer... // DBG_GDI((6, "DrvMovePointer exited, dhpdev(%xh)", ppdev)); }// DrvMovePointer() //---------------------------Public*Routine------------------------------------ // // VOID DrvSetPointerShape // // This function is used to request the driver to: // // 1) Take the pointer off the display, if the driver has drawn it there. // 2) Attempt to set a new pointer shape. // 3) Put the new pointer on the display at a specified position. // // Parameters: // psO-------Points to a SURFOBJ structure that describes the surface on which // TO draw. // psoMask---Points to a SURFOBJ structure that defines the AND-XOR mask. (The // AND-XOR mask is described in Drawing Monochrome Pointers.) The // dimensions of this bitmap determine the size of the pointer. There // are no implicit constraints on pointer sizes, but optimal pointer // sizes are 32 x 32, 48 x 48, and 64 x 64 pixels. If this parameter // IS NULL, the pointer is transparent. // psoColor--Points to a SURFOBJ structure that defines the colors for a color // pointer. If this parameter is NULL, the pointer is monochrome. The // pointer bitmap has the same width as psoMask and half the height. // pxlo------Points to a XLATEOBJ structure that defines the colors in psoColor. // xHot,yHot-Specify the x and y positions of the pointer's hot spot relative // to its upper-left pixel. The pixel indicated by the hot spot should // be positioned at the new pointer position. // x, y------Specify the new pointer position. // prcl------Is the location in which the driver should write a rectangle that // specifies a tight bound for the visible portion of the pointer. // fl--------Specifies an extensible set of flags. The driver should decline the // call if any flags are set that it does not understand. This // parameter can be one or more of the following predefined values, // and one or more driver-defined values: // Flag Meaning // SPS_CHANGE----------The driver is requested to change the pointer shape. // SPS_ASYNCCHANGE-----This flag is obsolete. For legacy drivers, the driver // should accept the change only if it is capable of // changing the pointer shape in the hardware while other // drawing is underway on the device. GDI uses this option // only if the now obsolete GCAPS_ASYNCCHANGE flag is set // in the flGraphicsCaps member of the DEVINFO structure. // SPS_ANIMATESTART----The driver should be prepared to receive a series of // similarly-sized pointer shapes that will comprise an // animated pointer effect. // SPS_ANIMATEUPDATE---The driver should draw the next pointer shape in the // animated series. // SPS_ALPHA-----------The pointer has per-pixel alpha values. // // Return Value // The return value can be one of the following values: // // Value Meaning // SPS_ERROR-----------The driver normally supports this shape, but failed for // unusual reasons. // SPS_DECLINE---------The driver does not support the shape, so GDI must // simulate it. // SPS_ACCEPT_NOEXCLUDE-The driver accepts the shape. The shape is supported // in hardware and GDI is not concerned about other // drawings overwriting the pointer. // SPS_ACCEPT_EXCLUDE--Is obsolete. GDI will disable the driver's pointer and // revert to software simulation if the driver returns // this value. // //----------------------------------------------------------------------------- ULONG DrvSetPointerShape(SURFOBJ* pso, SURFOBJ* psoMsk, SURFOBJ* psoColor, XLATEOBJ* pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL* prcl, FLONG fl) { PDev* ppdev; BOOL bAccept = FALSE; ppdev = (PDev*)pso->dhpdev; DBG_GDI((6, "DrvSetPointerShape called, dhpdev(%x)", ppdev)); DBG_GDI((6, "DrvSetPointerShape psocolor (0x%x)", psoColor)); // // When CAPS_SW_POINTER is set, we have no hardware pointer available, // so we always ask GDI to simulate the pointer for us, using // DrvCopyBits calls: // if ( ppdev->flCaps & CAPS_SW_POINTER ) { DBG_GDI((6, "SetPtrShape: CAPS_SW_POINTER not set, rtn SPS_DECLINE")); return (SPS_DECLINE); } // // We're not going to handle flags that we don't understand. // if ( !(fl & SPS_CHANGE) ) { DBG_GDI((6, "DrvSetPointerShape decline: Unknown flag =%x", fl)); goto HideAndDecline; } // // Remove any pointer first. // We have a special x value for the software cursor to indicate that // it should be removed immediatly, not delayed. DrvMovePointer needs to // recognise it as remove for any pointers though. // Note: CAPS_{P2RD, TVP4020, SW}_POINTER should be set in miniport after // it detects the DAC type // if ( x != -1 ) { if ( (ppdev->flCaps & CAPS_P2RD_POINTER) == 0 ) { // // If we're doing any hardware zooming then the cusor position will // have to be doubled. // if ( ppdev->flCaps & CAPS_ZOOM_Y_BY2 ) { y *= 2; } if ( ppdev->flCaps & CAPS_ZOOM_X_BY2 ) { x *= 2; } } } DBG_GDI((6, "iUniq is %ld", psoMsk->iUniq)); if ( ppdev->flCaps & CAPS_TVP4020_POINTER ) { DBG_GDI((6, "DrvSetPointerShape tring to set TVP4020 pointer")); bAccept = bSetPointerShapeTVP4020(ppdev, psoMsk, psoColor, x, y, xHot, yHot); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { bAccept = bSetPointerShapeP2RD(ppdev, psoMsk, psoColor, pxlo, x, y, xHot, yHot); } // // If we failed setup the hardware pointer shape, then return SPS_DECLINE // and let GDI handles it // if ( !bAccept ) { DBG_GDI((6, "set hardware pointer shape failed")); return (SPS_DECLINE); } // // Set flag to indicate that we have initialized hardware pointer shape // so that in vAssertModePointer, we can do some clean up // ppdev->bPointerInitialized = TRUE; if ( x != -1 ) { // // Save the X and Y values // ppdev->HWPtrPos_X = x; ppdev->HWPtrPos_Y = y; ppdev->flPointer |= PTR_HW_ACTIVE; } else { ppdev->flPointer &= ~PTR_HW_ACTIVE; } // // Since it's a hardware pointer, GDI doesn't have to worry about // overwriting the pointer on drawing operations (meaning that it // doesn't have to exclude the pointer), so we return 'NOEXCLUDE'. // Since we're returning 'NOEXCLUDE', we also don't have to update // the 'prcl' that GDI passed us. // DBG_GDI((6, "DrvSetPointerShape return SPS_ACCEPT_NOEXCLUDE")); return (SPS_ACCEPT_NOEXCLUDE); HideAndDecline: // // Remove whatever pointer is installed. // DrvMovePointer(pso, -2, -1, NULL); ppdev->flPointer &= ~PTR_SW_ACTIVE; DBG_GDI((6, "Cursor declined")); DBG_GDI((6, "DrvSetPointerShape exited (cursor declined)")); return (SPS_DECLINE); }// DrvSetPointerShape() //----------------------------------------------------------------------------- // // VOID vAssertModePointer // // Do whatever has to be done to enable everything but hide the pointer. // //----------------------------------------------------------------------------- VOID vAssertModePointer(PDev* ppdev, BOOL bEnable) { DBG_GDI((6, "vAssertModePointer called")); if ( (ppdev->bPointerInitialized == FALSE) ||(ppdev->flCaps & CAPS_SW_POINTER) ) { // // With a software pointer, or the pointer hasn't been initialized, // we don't have to do anything. // return; } // // Invalidate the hardware pointer cache // HWPointerCacheInvalidate(&(ppdev->HWPtrCache)); if ( ppdev->flCaps & CAPS_TVP4020_POINTER ) { vShowPointerTVP4020(ppdev, FALSE); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { vShowPointerP2RD(ppdev, FALSE); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { vEnablePointerP2RD(ppdev); } ppdev->flPointer &= ~(PTR_HW_ACTIVE | PTR_SW_ACTIVE); }// vAssertModePointer() //----------------------------------------------------------------------------- // // BOOL bEnablePointer(PDev* ppdev) // // This function initializes hardware pointer or software pointer depends on // on the CAPS settinsg in ppdev->flCaps // // This function always returns TRUE // //----------------------------------------------------------------------------- BOOL bEnablePointer(PDev* ppdev) { DBG_GDI((6, "bEnablePointer called")); // // Initialise the pointer cache. // HWPointerCacheInit(&(ppdev->HWPtrCache)); // // Set the last cursor to something invalid // ppdev->HWPtrLastCursor = HWPTRCACHE_INVALIDENTRY; // // Initialise the X and Y values to something silly // ppdev->HWPtrPos_X = 1000000000; ppdev->HWPtrPos_Y = 1000000000; if ( ppdev->flCaps & CAPS_SW_POINTER ) { // With a software pointer, we don't have to do anything. } else if ( ppdev->flCaps & CAPS_TVP4020_POINTER ) { vEnablePointerTVP4020(ppdev); } else if ( ppdev->flCaps & CAPS_P2RD_POINTER ) { vEnablePointerP2RD(ppdev); } return (TRUE); }// bEnablePointer()