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.
2123 lines
68 KiB
2123 lines
68 KiB
/******************************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()
|
|
|