|
|
/******************************Module*Header**********************************\
* * ******************* * * GDI SAMPLE CODE * * ******************* * * Module Name: pointer.c * * Content: * * This module contains the hardware pointer support for the display * driver. This supports the IBM RGB525 RAMDAC pointer. We also have * support for color space double buffering using the RAMDAC pixel * read mask. * * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved. * Copyright (c) 1995-2003 Microsoft Corporation. All rights reserved. \*****************************************************************************/
#include "precomp.h"
#include "glint.h"
#include "p3rd.h"
BOOL bSet3ColorPointerShapeP3RD(PPDEV ppdev, SURFOBJ *psoMask, SURFOBJ *psoColor, LONG x, LONG y, LONG xHot, LONG yHot); BOOL bSet15ColorPointerShapeP3RD(PPDEV ppdev, SURFOBJ *psoMask, SURFOBJ *psoColor, LONG x, LONG y, LONG xHot, LONG yHot);
/******************************Public*Routine******************************\
* VOID DrvMovePointer * * 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) { OH* poh; PDEV* ppdev = (PDEV*) pso->dhpdev;
DISPDBG((DBGLVL, "DrvMovePointer called"));
if (x > -1) { // Convert the pointer's position from relative to absolute
// coordinates (this is only significant for multiple board
// support):
poh = ((DSURF*) pso->dhsurf)->poh; x += poh->x; y += poh->y;
// 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;
// If they have genuinely moved the cursor, then
// move it
if (x != ppdev->HWPtrPos_X || y != ppdev->HWPtrPos_Y) { vMovePointerP3RD(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)) { DISPDBG((DBGLVL, "Showing hardware pointer")); ppdev->flPointer |= PTR_HW_ACTIVE; vShowPointerP3RD(ppdev, TRUE); } } else if (ppdev->flPointer & PTR_HW_ACTIVE) { // The pointer is visible, and we've been asked to hide it:
DISPDBG((DBGLVL, "Hiding hardware pointer")); ppdev->flPointer &= ~PTR_HW_ACTIVE; vShowPointerP3RD(ppdev, FALSE); } #if DBG
else { DISPDBG((DBGLVL, "DrvMovePointer: x == -1 but not PTR_HW_ACTIVE")); } #endif
// Note that we don't have to modify 'prcl', since we have a
// NOEXCLUDE pointer...
DISPDBG((DBGLVL, "DrvMovePointer exited")); }
/******************************Public*Routine******************************\
* VOID DrvSetPointerShape * * Sets the new pointer shape. * \**************************************************************************/
ULONG DrvSetPointerShape( SURFOBJ* pso, SURFOBJ* psoMsk, SURFOBJ* psoColor, XLATEOBJ* pxlo, LONG xHot, LONG yHot, LONG x, LONG y, RECTL* prcl, FLONG fl) { PDEV* ppdev; OH *poh; BOOL bAccept; DISPDBG((DBGLVL, "DrvSetPointerShape called"));
ppdev = (PDEV*) pso->dhpdev;
if (!(fl & SPS_CHANGE)) { goto HideAndDecline; }
ASSERTDD(psoMsk != NULL, "GDI gave us a NULL psoMsk. It can't do that!"); ASSERTDD(pso->iType == STYPE_DEVICE, "GDI gave us a weird surface");
if (x != -1) { // Convert the pointer's position from relative to absolute
// coordinates (this is only significant for multiple board
// support):
if (pso->dhsurf != NULL) { poh = ((DSURF*) pso->dhsurf)->poh; x += poh->x; y += poh->y; }
// 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; }
// See if our hardware cursor can handle this.
bAccept = bSetPointerShapeP3RD(ppdev, psoMsk, psoColor, pxlo, x, y, xHot, yHot);
if (bAccept) { 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.
return(SPS_ACCEPT_NOEXCLUDE); } HideAndDecline:
// Remove whatever pointer is installed.
DrvMovePointer(pso, -2, -1, NULL);
DISPDBG((DBGLVL, "Cursor declined"));
return(SPS_DECLINE); }
/******************************Public*Routine******************************\
* VOID vDisablePointer * \**************************************************************************/
VOID vDisablePointer( PDEV* ppdev) { if(ppdev->bPointerEnabled) { vDisablePointerP3RD(ppdev); } }
/******************************Public*Routine******************************\
* VOID vAssertModePointer * * Do whatever has to be done to enable everything but hide the pointer. * \**************************************************************************/
VOID vAssertModePointer( PDEV* ppdev, BOOL bEnable) { // Invalidate the hardware pointer cache
HWPointerCacheInvalidate (&(ppdev->HWPtrCache));
// Remove the hardware pointer
vShowPointerP3RD(ppdev, FALSE);
ppdev->flPointer &= ~PTR_HW_ACTIVE; }
/******************************Public*Routine******************************\
* BOOL bEnablePointer * \**************************************************************************/
BOOL bEnablePointer( PDEV* ppdev) { // 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 invalid.
ppdev->HWPtrPos_X = 1000000000; ppdev->HWPtrPos_Y = 1000000000;
// Call the enable function
vEnablePointerP3RD(ppdev);
// Mark the pointer as enabled for this PDEV
ppdev->bPointerEnabled = TRUE;
return(TRUE); }
/****************************************************************************************
* * * 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 (i.e. the RGB525 and TVP3033)* * however the TVP3026 supports a 64x64 cursor but this can't be broken down into 4 * * smaller ones. * * * ****************************************************************************************/
/******************************Public*Routine******************************\
* LONG HWPointerCacheInit * * Initialise the hardware pointer cache. \**************************************************************************/
VOID HWPointerCacheInit (HWPointerCache * ptrCache) { ptrCache->ptrCacheInUseCount = 0; ptrCache->ptrCacheCurTimeStamp = 0; }
/******************************Public*Routine******************************\
* 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, ULONG cx, ULONG cy, LONG lDelta, BYTE * scan0, BOOL * isCached) { BOOL pointerIsCached = FALSE; BOOL isLargePtr = (cx > 32) || (cy > 32); LONG i, j, z; LONG cacheItem;
#if !defined(_WIN64)
//@@BEGIN_DDKSPLIT
// Quick Fix IA64 AV
//@@END_DDKSPLIT
// 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->ptrCacheInUseCount && ptrCache->ptrCacheIsLargePtr == isLargePtr) { // *** SEARCH THE CACHE ***
LONG xInBytes = (cx >> 3); LONG yInLines = (cy << 1); // The AND plane and the XOR plane
BYTE jMask = gajMask [cx & 0x7]; LONG cacheCnt = ptrCache->ptrCacheInUseCount;
// Examine all valid entries in the cache to see if they are the same as the
// pointer that we've been handed.
for (z = 0; !pointerIsCached && z < cacheCnt; z++) { BYTE * cacheLinePtr = ((BYTE *) ptrCache->ptrCacheData) + (z * SMALL_POINTER_MEM); BYTE * cachePtr; LONG cacheLDelta = ptrCache->ptrCacheItemList [z].ptrCacheLDelta; BYTE * scanLinePtr = (BYTE *) scan0; BYTE * scanPtr;
// Compare the data
for (i = 0, pointerIsCached = TRUE; pointerIsCached && i < yInLines; i++) { cachePtr = cacheLinePtr; scanPtr = scanLinePtr;
// Compare each byte - could do a series of long comparisons here.
for (j = 0; (j < xInBytes) && (*scanPtr == *cachePtr); j++, scanPtr++, cachePtr++) ; pointerIsCached = (j == xInBytes) && ((*scanPtr & jMask) == (*cachePtr & jMask));
cacheLinePtr += cacheLDelta; scanLinePtr += lDelta; } cacheItem = z; } } #endif // !defined(_WIN64)
// If we couldn't find an entry in the pointer cache then add one to the cache.
if (!pointerIsCached) { /* **** ADD POINTER TO THE CACHE ****** */
LONG xInBytes = ((cx + 7) >> 3); LONG yInLines = (cy << 1); // The AND plane and the XOR plane
BYTE * scanLinePtr = (BYTE *) scan0; BYTE * scanPtr; BYTE * cacheLinePtr; BYTE * cachePtr; LONG cacheLDelta = (cx <= 32) ? 4 : 8; BYTE jMask = gajMask [cx & 0x7];
// If the new pointer is a big one then re-use item 0, else if
// the pointer is small and there are some spare entries then allocate
// a free entry, otherwise find the least recently used entry and use
// that.
if (isLargePtr) { cacheItem = 0; } else if (ptrCache->ptrCacheInUseCount < SMALL_POINTER_MAX) { cacheItem = ptrCache->ptrCacheInUseCount++; } else { ULONG oldestValue = 0xFFFFFFFF;
// look for the LRU entry
for (z = 0, cacheItem = 0; z < SMALL_POINTER_MAX; z++) { if (ptrCache->ptrCacheItemList [z].ptrCacheTimeStamp < oldestValue) { cacheItem = z; oldestValue = ptrCache->ptrCacheItemList [z].ptrCacheTimeStamp; } } } // Get a pointer to the first line in the cache
cacheLinePtr = ((BYTE *) ptrCache->ptrCacheData) + (cacheItem * SMALL_POINTER_MEM);
// Add the pointer to the cache
for (i = 0; i < yInLines; i++) { cachePtr = cacheLinePtr; scanPtr = scanLinePtr;
for (j = 0; (j < xInBytes); j++, scanPtr++, cachePtr++) *cachePtr = *scanPtr; cacheLinePtr += cacheLDelta; scanLinePtr += lDelta; }
// If the pointer type is different then reset the whole
// cache
if (ptrCache->ptrCacheIsLargePtr != isLargePtr) { ptrCache->ptrCacheInUseCount = 1; ptrCache->ptrCacheIsLargePtr = (BYTE)isLargePtr; }
// Set up the cache entry
ptrCache->ptrCacheItemList [cacheItem].ptrCacheLDelta = cacheLDelta; ptrCache->ptrCacheItemList [cacheItem].ptrCacheCX = cx; ptrCache->ptrCacheItemList [cacheItem].ptrCacheCY = cy; }
// Set the timestamp
ptrCache->ptrCacheItemList [cacheItem].ptrCacheTimeStamp = ptrCache->ptrCacheCurTimeStamp++;
// Set up the return value to say whether the pointer was cached
*isCached = pointerIsCached;
return (cacheItem); }
//@@BEGIN_DDKSPLIT
// NickM says we have to disable the cursor to stop nasty flashing occurring,
// however there is a potential exploding flashing cursor syndrome that this may
// cause.
// Note that this problem only seems to cause us problems when switching between
// mono and colour cursors.
//@@END_DDKSPLIT
#define DISABLE_CURSOR_MODE(){ \
ULONG curCurMode, curLine; \ ULONG start = (pP3RDinfo->y > 8) ? (pP3RDinfo->y - 8) : 0; \ ULONG end = pP3RDinfo->y + 64; \ do { \ READ_GLINT_CTRL_REG (LineCount, curLine); \ } while ((curLine >= start) && (curLine <= end)); \ P3RD_READ_INDEX_REG(P3RD_CURSOR_MODE, curCurMode); \ P3RD_LOAD_INDEX_REG(P3RD_CURSOR_MODE, (curCurMode & (~P3RD_CURSOR_MODE_ENABLED))); \ }
// Look-up table for masking the right edge of the given pointer bitmap:
//
BYTE gajMask[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, };
/******************************Public*Routine******************************\
* VOID vShowPointerP3RD * * Show or hide the 3Dlabs P3RD hardware pointer. * \**************************************************************************/
VOID vShowPointerP3RD( PPDEV ppdev, BOOL bShow) { ULONG cmr; GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
DISPDBG((DBGLVL, "vShowPointerP3RD (%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.
P3RD_LOAD_INDEX_REG(P3RD_CURSOR_MODE, (pP3RDinfo->cursorModeCurrent | P3RD_CURSOR_MODE_ENABLED)); P3RD_MOVE_CURSOR (pP3RDinfo->x, pP3RDinfo->y); } else { // move the cursor off screen
P3RD_LOAD_INDEX_REG(P3RD_CURSOR_Y_HIGH, 0xff); } }
/******************************Public*Routine******************************\
* VOID vMovePointerP3RD * * Move the 3Dlabs P3RD hardware pointer. * \**************************************************************************/
VOID vMovePointerP3RD( PPDEV ppdev, LONG x, LONG y) { GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
DISPDBG((DBGLVL, "vMovePointerP3RD to (%d, %d)", x, y));
pP3RDinfo->x = x; pP3RDinfo->y = y;
P3RD_SYNC_WITH_GLINT;
P3RD_MOVE_CURSOR (x, y); }
/******************************Public*Routine******************************\
* BOOL bSetPointerShapeP3RD * * Set the 3Dlabs hardware pointer shape. * \**************************************************************************/
UCHAR nibbleToByteP3RD[] = {
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
};
BOOL bSetPointerShapeP3RD( PPDEV 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; ULONG lutIndex0, lutIndex1; GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
DISPDBG((DBGLVL, "bSetPointerShapeP3RD started"));
// Do we have a colour cursor ?
if (psoColor != NULL) { HSURF hsurfDst = NULL; // We'll use these later.
SURFOBJ * psoDst = NULL;
if (psoColor->iType == STYPE_DEVBITMAP) { // it's an offscreen bitmap: we'll use its DIB
DSURF *pdsurfSrc = (DSURF *)psoColor->dhsurf; psoColor = pdsurfSrc->pso;
// If we have patching enabled then it could be that we aren't allowed
// to directly access framebuffer memory, if that is the case then
// we have to fall-back to software. Note that when running 3D apps there
// won't be any off-screen memory so cursors will be hardware ones.
// Note that bitmaps that were in off-screen and have been kicked back
// into host memory will have pdsurfSrc->dt set to DT_DIB.
if (glintInfo->GdiCantAccessFramebuffer && ((pdsurfSrc->dt & DT_DIB) == 0)) { DISPDBG((DBGLVL, "declining off-screen cursor in a patched framebuffer")); return (FALSE); } }
// Is it 15,16 or 32BPP.
if(!(ppdev->iBitmapFormat == BMF_16BPP || ppdev->iBitmapFormat == BMF_32BPP)) { // currently we only handle DIB cursors at 32bpp, 16bpp & 15bpp.
DISPDBG((DBGLVL, "declining non-32bpp, non-16bpp colored cursor - iType(%d) iBitmapFormat(%d)", psoColor->iType, psoColor->iBitmapFormat)); return FALSE; }
// If we have a bitmap which we don't understand then we have to convert it using
// the EngCopyBits() function.
if ((pxlo != NULL && pxlo->flXlate != XO_TRIVIAL) || (psoColor->iType != STYPE_BITMAP) ) { RECTL rclDst; SIZEL sizlDst; ULONG DstPixelOrigin; POINTL ptlSrc;
#if DBG
if(pxlo != NULL && pxlo->flXlate != XO_TRIVIAL) { DISPDBG((DBGLVL, "colored cursor - nontrivial xlate: flXlate(%xh)", pxlo->flXlate)); } #endif // DBG
// Firstly we need to create a bitmap (hsurfDst) and a surface (psoDst)
// which we can translate the cursor data in psoColor into.
sizlDst.cy = pso->sizlBitmap.cy >> 1; // divide by 2 'cos cy includes AND and XOR masks
sizlDst.cx = pso->sizlBitmap.cx;
DISPDBG((DBGLVL, "Creating bitmap for destination: dimension %dx%d", sizlDst.cx, sizlDst.cy)); hsurfDst = (HSURF) EngCreateBitmap(sizlDst, BMF_TOPDOWN, ppdev->iBitmapFormat, 0, NULL); if (hsurfDst == NULL) { DISPDBG((DBGLVL, "bSetPointerShapeP3RD: EngCreateBitmap failed")); return FALSE; }
// Now we lock the bitmap to get ourselves a surface object.
psoDst = EngLockSurface(hsurfDst); if (psoDst == NULL) { DISPDBG((DBGLVL, "bSetPointerShapeP3RD: EngLockSurface failed")); } else { // Now do the bitmap conversion using EngCopyBits(). The
// destination rectangle is the minimum size and the source starts
// from (0,0) into pso->pvScan0.
rclDst.left = 0; rclDst.top = 0; rclDst.right = sizlDst.cx; rclDst.bottom = sizlDst.cy; ptlSrc.x = 0; ptlSrc.y = 0; DISPDBG((DBGLVL, "bSetPointerShapeP3RD: copying to bitmap"));
if (!EngCopyBits(psoDst, psoColor, NULL, pxlo, &rclDst, &ptlSrc)) { // Oh no copybits failed, free up the the surfaces & bitmaps.
DISPDBG((DBGLVL, "bSetPointerShapeP3RD: EngLockSurface failed"));
EngUnlockSurface(psoDst); EngDeleteSurface(hsurfDst); return FALSE; } else { // Copybits suceeded, set psoColor to point at the translated
// data.
DISPDBG((DBGLVL, "bSetPointerShapeP3RD: EngLockSurface OK"));
psoColor = psoDst; } } }
// Draw the cursor, this function will return an error if there are
// too many colours in the pointer.
if(!bSet15ColorPointerShapeP3RD(ppdev, pso, psoColor, x, y, xHot, yHot)) { DISPDBG((DBGLVL, "declining colored cursor")); return FALSE; }
// If we, earlier, translated psoColor into the framebuffer pixel format then
// we now need to free the intermediate surfaces and bitmaps.
if (psoDst) { EngUnlockSurface(psoDst); } if (hsurfDst) { EngDeleteSurface(hsurfDst); } DISPDBG((DBGLVL, "bSetPointerShapeP3RD done")); return(TRUE); }
// If we are switching from a colour cursor to a mono one then disable
// the cursor in the cursor mode. Note that this is potentially dangerous
// and we are seeing screen flashes on occasions.
if (pP3RDinfo->cursorSize != P3RD_CURSOR_SIZE_32_MONO && pP3RDinfo->cursorSize != P3RD_CURSOR_SIZE_64_MONO) { DISABLE_CURSOR_MODE(); }
// 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
pP3RDinfo->cursorSize = P3RD_CURSOR_SIZE_32_MONO; cursorBytes = 32 * 32 * 2 / 8; cClear = 8 - 2 * ((cx+7) / 8); cRemPels = (32 - cy) << 3; } else if (cx <= 64 && cy <= 64) { // 64 horiz pixels: 2 bits per pixel, 1 horiz line per 16 bytes
pP3RDinfo->cursorSize = P3RD_CURSOR_SIZE_64_MONO; cursorBytes = 64 * 64 * 2 / 8; cClear = 16 - 2 * ((cx+7) / 8); cRemPels = (64 - cy) << 4; } else { DISPDBG((DBGLVL, "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), cx, cy, pso->lDelta, pso->pvScan0, &pointerIsCached); DISPDBG((DBGLVL, "bSetPointerShapeP3RD: Add Cache iscac %d item %d", (int) pointerIsCached, cacheItem));
pP3RDinfo->cursorModeCurrent = pP3RDinfo->cursorModeOff | P3RD_CURSOR_SEL(pP3RDinfo->cursorSize, cacheItem);
// hide the pointer
vShowPointerP3RD(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 nibbleToByteP3RD array
// to help this.
//
// 'psoMsk' is actually cy * 2 scans high; the first 'cy' scans
// define the AND mask.
pjAndScan = 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; P3RD_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 nibbleToByteP3RD 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 = nibbleToByteP3RD[andByte >> 4] | (nibbleToByteP3RD[xorByte >> 4] >> 1); P3RD_LOAD_CURSOR_ARRAY (ulValue);
andByte &= 0xf; xorByte &= 0xf; ulValue = nibbleToByteP3RD[andByte] | (nibbleToByteP3RD[xorByte] >> 1); P3RD_LOAD_CURSOR_ARRAY (ulValue); }
if (cpelFraction) { andByte = *pjAnd & jMask; xorByte = *pjXor & jMask; ulValue = nibbleToByteP3RD[andByte >> 4] | (nibbleToByteP3RD[xorByte >> 4] >> 1); P3RD_LOAD_CURSOR_ARRAY (ulValue);
andByte &= 0xf; xorByte &= 0xf; ulValue = nibbleToByteP3RD[andByte] | (nibbleToByteP3RD[xorByte] >> 1); P3RD_LOAD_CURSOR_ARRAY (ulValue); }
// finally clear out any remaining cursor pels on this line.
//
if (cClear) { for (j = 0; j < cClear; ++j) { P3RD_LOAD_CURSOR_ARRAY (P3RD_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 { P3RD_LOAD_CURSOR_ARRAY (P3RD_CURSOR_2_COLOR_TRANSPARENT); } while (--cRemPels > 0); } }
// now set-up the cursor colors
// Norte that the P3 cursor has the color LUT upside down.
lutIndex0 = P3RD_CALCULATE_LUT_INDEX (0); lutIndex1 = P3RD_CALCULATE_LUT_INDEX (1);
P3RD_CURSOR_PALETTE_CURSOR_RGB(lutIndex0, 0x00, 0x00, 0x00); P3RD_CURSOR_PALETTE_CURSOR_RGB(lutIndex1, 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;
P3RD_CURSOR_HOTSPOT(xHot, yHot); }
if (x != -1) { vMovePointerP3RD (ppdev, x, y);
// need to explicitly show the pointer
vShowPointerP3RD(ppdev, TRUE); }
DISPDBG((DBGLVL, "bSetPointerShapeP3RD done")); return(TRUE); }
/******************************Public*Routine******************************\
* BOOL bSet3ColorPointerShapeP3RD * * stores the 3-color cursor in the RAMDAC: currently only 32bpp and 15/16bpp * cursors are supported * \**************************************************************************/
BOOL bSet3ColorPointerShapeP3RD( PPDEV 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; ULONG whichOne = 0; GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD started"));
cx = psoColor->sizlBitmap.cx; cy = psoColor->sizlBitmap.cy;
if (cx <= 32 && cy <= 32) { ULONG curItem; cxcyCache = 32;
// If we are using a mono/3-colour cursor in the first or second entry then
// download to the third entry, otherwise use the first entry.
curItem = (pP3RDinfo->cursorModeCurrent >> 1) & 0x7; if (curItem == 1 || curItem == 2) whichOne = 2;
pP3RDinfo->cursorSize = P3RD_CURSOR_SIZE_32_3COLOR; pP3RDinfo->cursorModeCurrent = pP3RDinfo->cursorModeOff | P3RD_CURSOR_SEL(pP3RDinfo->cursorSize, whichOne) | P3RD_CURSOR_MODE_3COLOR;
// We don't cache color cursors, because we want to force the mono cursor to use the
// either the first or third entries we can't just do a HWPointerCacheInvalidate(), because
// the mono cursor code will use the first entry or the time. So, if we want the
// mono code to use the 3rd entry we say that first 2 cache entries are valid but mess them
// up by incrementing the first byte, so that the cache check will always fail.
ppdev->HWPtrCache.ptrCacheInUseCount = (BYTE) whichOne; for (iCol = 0; iCol < ppdev->HWPtrCache.ptrCacheInUseCount; iCol++) (*(((BYTE *) ppdev->HWPtrCache.ptrCacheData) + (iCol * SMALL_POINTER_MEM)))++;
} else if (cx <= 64 && cy <= 64) { // 64x64 cursor : we'll cache it in cursor partition 0 and scrub the old cache
cxcyCache = 64;
pP3RDinfo->cursorSize = P3RD_CURSOR_SIZE_64_3COLOR; pP3RDinfo->cursorModeCurrent = pP3RDinfo->cursorModeOff | P3RD_CURSOR_SEL(pP3RDinfo->cursorSize, 0) | P3RD_CURSOR_MODE_3COLOR;
// we don't cache color cursors
HWPointerCacheInvalidate (&(ppdev->HWPtrCache)); } else { DISPDBG((DBGLVL, "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 = psoMask->pvScan0; cjAndDelta = psoMask->lDelta;
// set-up a pointer to the 32bpp color bitmap
pulColor = psoColor->pvScan0; cjColorDelta = psoColor->lDelta;
// Hide the pointer
vShowPointerP3RD(ppdev, FALSE);
// load the cursor array (we have auto-increment turned on so initialize to entry 0 here)
P3RD_CURSOR_ARRAY_START(whichOne * (32 * 32 * 2 / 8)); for (iRow = 0; iRow < cy; ++iRow, pjAndMask += cjAndDelta, (BYTE *)pulColor += cjColorDelta) { DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: 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
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: writing cursor data %xh", CI2ColorData)); P3RD_LOAD_CURSOR_ARRAY(CI2ColorData); CI2ColorData = 0; CI2ColorIndex = 0; }
// get the source pixel
if (ppdev->cPelSize == GLINTDEPTH32) { ulColor = *pul++; } else { ulColor = *(USHORT *)pul; (USHORT *)pul += 1; }
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: Column %d (of %d) AndByte(%08xh) AndBit(%d) ulColor(%08xh)", iCol, cx, AndByte, AndBit, ulColor));
//@@BEGIN_DDKSPLIT
#if 0
// TMM: We only used to assume a pixel was transparent if the
// AND mask bit was set and the pixel was zero, I am pretty sure
// that this is wrong. We also used to do some stuff with
// inverse pixels but that was wrong as well.
if(AndByte & (1 << AndBit)) { // 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
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: transparent - ignore")); continue; } #else
//@@END_DDKSPLIT
// 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 == ppdev->ulWhite) { // color == white: inverse, but we don't support this. We've destroyed the cache for nothing
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: failed - inverted colors aren't supported")); return(FALSE); }
//@@BEGIN_DDKSPLIT
// if we get here the color should be black. However, if the pointer surface has been translated it
// might not be exactly black (e.g. as for the pointer at the start of Riven), so we don't do the test
//if(ulColor == 0)
//@@END_DDKSPLIT
{ // 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
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: transparent - ignore")); continue; } } //@@BEGIN_DDKSPLIT
#endif
//@@END_DDKSPLIT
// get the index for this color: first see if we've already indexed it
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: looking up color %08xh", ulColor));
for(Index = 0; Index < HighestIndex && aulColorsIndexed[Index] != ulColor; ++Index);
if (Index == 3) { // too many colors in this cursor
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: failed - cursor has more than 3 colors")); return(FALSE); } else if (Index == HighestIndex) { // we've found another color: add it to the color index
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: 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
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: writing remaining data for this row (%08xh) and %d trailing bytes", CI2ColorData, cjCacheRemx));
P3RD_LOAD_CURSOR_ARRAY(CI2ColorData);
if (cjCacheRemx) { for (cj = cjCacheRemx; --cj >=0;) { P3RD_LOAD_CURSOR_ARRAY(P3RD_CURSOR_3_COLOR_TRANSPARENT); } } }
// end of cursor: blank any unused rows Nb. cjCacheRemy == cy blank rows * cj bytes per row
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: writing %d trailing bytes for this cursor", cjCacheRemy));
for (cj = cjCacheRemy; --cj >= 0;) { // 0 == transparent
P3RD_LOAD_CURSOR_ARRAY(P3RD_CURSOR_3_COLOR_TRANSPARENT); }
DISPDBG((DBGLVL, "bSet3ColorPointerShapeP3RD: setting up the cursor palette"));
// now set-up the cursor palette
for (iCol = 0; iCol < HighestIndex; ++iCol) { ULONG lutIndex;
// the cursor colors are at native depth, convert them to 24bpp
if (ppdev->cPelSize == GLINTDEPTH32) { // 32bpp
b = 0xff & aulColorsIndexed[iCol]; g = 0xff & (aulColorsIndexed[iCol] >> 8); r = 0xff & (aulColorsIndexed[iCol] >> 16); } else //(ppdev->cPelSize == GLINTDEPTH16)
{ 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; } } // The P3 cursor has the color LUT upside down.
lutIndex = P3RD_CALCULATE_LUT_INDEX (iCol); P3RD_CURSOR_PALETTE_CURSOR_RGB(lutIndex, r, g, b); }
// enable the cursor
P3RD_CURSOR_HOTSPOT(xHot, yHot); if (x != -1) { vMovePointerP3RD (ppdev, x, y);
// need to explicitly show the pointer
vShowPointerP3RD(ppdev, TRUE); }
DISPDBG((DBGLVL, "b3ColorSetPointerShapeP3RD done")); return(TRUE); }
/******************************Public*Routine******************************\
* BOOL bSet15ColorPointerShapeP3RD * * stores the 15-color cursor in the RAMDAC: currently only 32bpp and 15/16bpp * cursors are supported * \**************************************************************************/
BOOL bSet15ColorPointerShapeP3RD( PPDEV 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 CI4ColorIndex, CI4ColorData; ULONG ulColor; ULONG aulColorsIndexed[15]; LONG Index, HighestIndex = 0; ULONG r, g, b; ULONG whichOne = 0; GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD started"));
// If we are switching from a mono cursor to a colour one then disable
// the cursor in the cursor mode. Note that this is potentially dangerous
// and we are seeing screen flashes on occasions.
if (pP3RDinfo->cursorSize == P3RD_CURSOR_SIZE_32_MONO || pP3RDinfo->cursorSize == P3RD_CURSOR_SIZE_64_MONO) { DISABLE_CURSOR_MODE(); }
cx = psoColor->sizlBitmap.cx; cy = psoColor->sizlBitmap.cy;
if (cx <= 32 && cy <= 32) { ULONG curItem; cxcyCache = 32;
// If we are using a mono cursor in the first or second entry, or we have a
// 15 colour cursor in the top half of cursor memory then download
// this colour cursor to the download to the 2nd half of cursor memory, otherwise
// download to the top half.
curItem = (pP3RDinfo->cursorModeCurrent >> 1) & 0x7; if (curItem == 1 || curItem == 2 || curItem == 5) whichOne = 1; pP3RDinfo->cursorSize = P3RD_CURSOR_SIZE_32_15COLOR; pP3RDinfo->cursorModeCurrent = pP3RDinfo->cursorModeOff | P3RD_CURSOR_SEL(pP3RDinfo->cursorSize, whichOne) | P3RD_CURSOR_MODE_15COLOR;
// We don't cache color cursors, because we want to force the mono cursor to use the
// either the first or third entries we can't just do a HWPointerCacheInvalidate(), because
// the mono cursor code will use the first entry or the time. So, if we want the
// mono code to use the 3rd entry we say that first 2 cache entries are valid but mess them
// up by incrementing the first byte, so that the cache check will always fail.
ppdev->HWPtrCache.ptrCacheInUseCount = (whichOne == 0) ? 2 : 0; for (iCol = 0; iCol < ppdev->HWPtrCache.ptrCacheInUseCount; iCol++) (*(((BYTE *) ppdev->HWPtrCache.ptrCacheData) + (iCol * SMALL_POINTER_MEM)))++; } 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 = bSet3ColorPointerShapeP3RD(ppdev, psoMask, psoColor, x, y, xHot, yHot); return(bRet); } else { DISPDBG((DBGLVL, "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 = psoMask->pvScan0; cjAndDelta = psoMask->lDelta;
// set-up a pointer to the 32bpp color bitmap
pulColor = psoColor->pvScan0; cjColorDelta = psoColor->lDelta;
// hide the pointer
vShowPointerP3RD(ppdev, FALSE);
// load the cursor array (we have auto-increment turned on so initialize to entry 0 here)
P3RD_CURSOR_ARRAY_START(whichOne * (32 * 32 * 4 / 8)); for (iRow = 0; iRow < cy; ++iRow, pjAndMask += cjAndDelta, (BYTE *)pulColor += cjColorDelta) { DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: 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
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: writing cursor data %xh", CI4ColorData)); P3RD_LOAD_CURSOR_ARRAY(CI4ColorData); CI4ColorData = 0; CI4ColorIndex = 0; }
// get the source pixel
if (ppdev->cPelSize == GLINTDEPTH32) { ulColor = *pul++; } else { ulColor = *(USHORT *)pul; (USHORT *)pul += 1; }
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: Column %d (of %d) AndByte(%08xh) AndBit(%d) ulColor(%08xh)", iCol, cx, AndByte, AndBit, ulColor));
//@@BEGIN_DDKSPLIT
#if 0
// TMM: We only used to assume a pixel was transparent if the
// AND mask bit was set and the pixel was zero, I am pretty sure
// that this is wrong. We also used to do some stuff with
// inverse pixels but that was wrong as well.
if(AndByte & (1 << AndBit)) { // 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
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: transparent - ignore")); continue; } #else
//@@END_DDKSPLIT
// 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 == ppdev->ulWhite) { // color == white: inverse, but we don't support this. We've destroyed the cache for nothing
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: failed - inverted colors aren't supported")); return(FALSE); }
// if we get here the color should be black. However, if the pointer surface has been translated it
// might not be exactly black (e.g. as for the pointer at the start of Riven), so we don't do the test
//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
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: transparent - ignore")); continue; } } //@@BEGIN_DDKSPLIT
#endif
//@@END_DDKSPLIT
// get the index for this color: first see if we've already indexed it
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: looking up color %08xh", ulColor));
for (Index = 0; Index < HighestIndex && aulColorsIndexed[Index] != ulColor; ++Index);
if (Index == 15) { // too many colors in this cursor
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: failed - cursor has more than 15 colors")); return(FALSE); } else if (Index == HighestIndex) { // we've found another color: add it to the color index
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: adding %08xh to cursor palette", ulColor)); aulColorsIndexed[HighestIndex++] = ulColor; } // add this pixel's index to the CI4 cursor data. NB. 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
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: writing remaining data for this row (%08xh) and %d trailing bytes", CI4ColorData, cjCacheRemx));
P3RD_LOAD_CURSOR_ARRAY(CI4ColorData);
if (cjCacheRemx) { for (cj = cjCacheRemx; --cj >=0;) { P3RD_LOAD_CURSOR_ARRAY(P3RD_CURSOR_15_COLOR_TRANSPARENT); } } }
// end of cursor: blank any unused rows Nb. cjCacheRemy == cy blank rows * cj bytes per row
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: writing %d trailing bytes for this cursor", cjCacheRemy));
for (cj = cjCacheRemy; --cj >= 0;) { // 0 == transparent
P3RD_LOAD_CURSOR_ARRAY(P3RD_CURSOR_15_COLOR_TRANSPARENT); }
DISPDBG((DBGLVL, "bSet15ColorPointerShapeP3RD: setting up the cursor palette"));
// now set-up the cursor palette
for (iCol = 0; iCol < HighestIndex; ++iCol) { ULONG lutIndex;
// the cursor colors are at native depth, convert them to 24bpp
if (ppdev->cPelSize == GLINTDEPTH32) { // 32bpp
b = 0xff & aulColorsIndexed[iCol]; g = 0xff & (aulColorsIndexed[iCol] >> 8); r = 0xff & (aulColorsIndexed[iCol] >> 16); } else //(ppdev->cPelSize == GLINTDEPTH16)
{ 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; } } // The P3 cursor has the color LUT upside down.
lutIndex = P3RD_CALCULATE_LUT_INDEX (iCol); P3RD_CURSOR_PALETTE_CURSOR_RGB(lutIndex, r, g, b); }
// enable the cursor
P3RD_CURSOR_HOTSPOT(xHot, yHot); if (x != -1) { vMovePointerP3RD (ppdev, x, y); // need to explicitly show the pointer
vShowPointerP3RD(ppdev, TRUE); }
DISPDBG((DBGLVL, "b3ColorSetPointerShapeP3RD done")); return(TRUE); }
/******************************Public*Routine******************************\
* VOID vEnablePointerP3RD * * Get the hardware ready to use the 3Dlabs P3RD hardware pointer. * \**************************************************************************/
VOID vEnablePointerP3RD( PPDEV ppdev) { pP3RDRAMDAC pRamdac; ULONG ul;
GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT;
DISPDBG((DBGLVL, "vEnablePointerP3RD called"));
ppdev->pvPointerData = &ppdev->ajPointerData[0]; P3RD_DECL_INIT; // get a pointer to the RAMDAC registers from the memory mapped
// control register space.
//
pRamdac = (pP3RDRAMDAC)(ppdev->pulRamdacBase);
// set up memory mapping for the control registers and save in the pointer
// specific area provided in ppdev.
//
P3RD_PAL_WR_ADDR = TRANSLATE_ADDR(&(pRamdac->RDPaletteWriteAddress)); P3RD_PAL_RD_ADDR = TRANSLATE_ADDR(&(pRamdac->RDPaletteAddressRead)); P3RD_PAL_DATA = TRANSLATE_ADDR(&(pRamdac->RDPaletteData)); P3RD_PIXEL_MASK = TRANSLATE_ADDR(&(pRamdac->RDPixelMask)); P3RD_INDEX_ADDR_HI = TRANSLATE_ADDR(&(pRamdac->RDIndexHigh)); P3RD_INDEX_ADDR_LO = TRANSLATE_ADDR(&(pRamdac->RDIndexLow)); P3RD_INDEX_DATA = TRANSLATE_ADDR(&(pRamdac->RDIndexedData)); P3RD_INDEX_CONTROL = TRANSLATE_ADDR(&(pRamdac->RDIndexControl));
// not used, but set-up zero anyway
ppdev->xPointerHot = 0; ppdev->yPointerHot = 0;
// enable auto-increment
ul = READ_P3RDREG_ULONG(P3RD_INDEX_CONTROL); ul |= P3RD_IDX_CTL_AUTOINCREMENT_ENABLED; WRITE_P3RDREG_ULONG(P3RD_INDEX_CONTROL, ul);
P3RD_READ_INDEX_REG(P3RD_CURSOR_CONTROL, pP3RDinfo->cursorControl);
pP3RDinfo->cursorModeCurrent = pP3RDinfo->cursorModeOff = 0; P3RD_LOAD_INDEX_REG(P3RD_CURSOR_MODE, pP3RDinfo->cursorModeOff);
P3RD_INDEX_REG(P3RD_CURSOR_X_LOW); P3RD_LOAD_DATA(0); // cursor x low
P3RD_LOAD_DATA(0); // cursor x high
P3RD_LOAD_DATA(0); // cursor y low
P3RD_LOAD_DATA(0xff); // cursor y high
P3RD_LOAD_DATA(0); // cursor x hotspot
P3RD_LOAD_DATA(0); // cursor y hotspot
}
/******************************Public*Routine******************************\
* BOOL vDisablePointerP3RD * * Does basic pointer tidying up. \**************************************************************************/
VOID vDisablePointerP3RD(PDEV * ppdev) { // Undraw the pointer, may not be necessary on P3, but we do it
// on P2.
vShowPointerP3RD(ppdev, FALSE); }
//@@BEGIN_DDKSPLIT
#if 0
/******************************Public*Routine******************************\
* VOID vSetOverlayModeP3RD * * Enable or disable RAMDAC overlays for the P3RD RAMDAC. * * \**************************************************************************/
VOID vSetOverlayModeP3RD (PDEV * ppdev, ULONG EnableOverlay, // 0 to disable, 1 to enable
ULONG TransparentColor) { ULONG p3rdVal; GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
P3RD_READ_INDEX_REG (P3RD_MISC_CONTROL, p3rdVal); // Read current setting
if (EnableOverlay == GLINT_ENABLE_OVERLAY) { // Enable Overlay
p3rdVal |= P3RD_MISC_CONTROL_OVERLAYS_ENABLED; // Enable overlays
p3rdVal |= P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED; // Enable direct colour
P3RD_LOAD_INDEX_REG (P3RD_MISC_CONTROL, p3rdVal);
P3RD_LOAD_INDEX_REG (P3RD_OVERLAY_KEY, TransparentColor); // Set transparent colour
} else { // Disable Overlay
p3rdVal &= ~P3RD_MISC_CONTROL_OVERLAYS_ENABLED; // Disable overlays
p3rdVal &= ~P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED; // Disable direct colour
P3RD_LOAD_INDEX_REG (P3RD_MISC_CONTROL, p3rdVal); } }
VOID vP3RDSetPixelMask( PPDEV ppdev, ULONG ulMask) { GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT; P3RD_SET_PIXEL_READMASK (ulMask); }
/******************************Public*Routine******************************\
* BOOL bP3RDSwapCSBuffers * * 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 bP3RDSwapCSBuffers( PPDEV ppdev, LONG bufNo) { ULONG index; ULONG color; GLINT_DECL_VARS; P3RD_DECL_VARS; GLINT_DECL_INIT; P3RD_DECL_INIT;
// work out the RAMDAC read pixel mask for the buffer, wait for VBLANK
// and switch it.
//
DISPDBG((DBGLVL, "loading the palette to swap to buffer %d", bufNo)); P3RD_PALETTE_START_WR (0); GLINT_WAIT_FOR_VBLANK; if (bufNo == 0) { for (index = 0; index < 16; ++index) for (color = 0; color <= 0xff; color += 0x11) P3RD_LOAD_PALETTE (color, color, color); } else { for (color = 0; color <= 0xff; color += 0x11) for (index = 0; index < 16; ++index) P3RD_LOAD_PALETTE (color, color, color); }
return(TRUE); }
/******************************Public*Routine******************************\
* BOOL bP3RDCheckCSBuffering * * 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 bP3RDCheckCSBuffering(PPDEV ppdev) { // pixels must be 32 bits deep. White is set to the combined masks for
// each of red, green and blue. The pattern 0x0f0f0f is unique to
// interleaved 12 bpp mode.
//
return ((ppdev->cPelSize == 2) && (ppdev->ulWhite == 0x0f0f0f)); }
#endif
//@@END_DDKSPLIT
|