Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1652 lines
58 KiB

/******************************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