Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1034 lines
35 KiB

/*
* Copyright (c) 1992 Microsoft Corporation
*
* Copyright (C) 1993-1995 by
* DIGITAL EQUIPMENT CORPORATION, Maynard, MA.
*
* This software is furnished under a license and may be used and copied
* only in accordance with the terms of such license and with the inclusion
* of the above copyright notice. This software or any other copies there-
* of may not be provided or otherwise made available to any other person.
* No title to and ownership of the software is hereby transferred.
*
* The information in this software is subject to change without notice
* and should not be construed as a commitment by DIGITAL EQUIPMENT COR-
* PORATION.
*
* DIGITAL assumes no responsibility for the use or reliability of its
* software on equipment which is not supplied by DIGITAL.
*
*******************************************************************************
*
* Module: pointer.c
*
* Abstract: Contains all the pointer management functions.
*
* HISTORY
*
* 1-Nov-1993 Barry Tannenbaum
* Original version.
*
* 3-Nov-1994 Bob Seitsinger
* Modify to support 24 plane TGA-based cursor management. Lots of
* new code.
*
* 4-Nov-1994 Bob Seitsinger
* Fix bug in 24 plane hardware cursor code where it merges the
* bits. The I-Beam cursor was transparent with the existing
* bit merging scheme, so adjusted it to make that cursor appear
* correctly.
*
* 2-Mar-1995 Barry Tannenbaum
* EV5 changes
*
* 11-Mar-1995 Barry Tannenbaum
* Allow 24BPP cursor to be updated asynchronously
*/
#include "driver.h"
BOOL bCopyColorPointer (PPDEV ppdev,
SURFOBJ *psoMask,
SURFOBJ *psoColor,
XLATEOBJ *pxlo);
BOOL bCopyMonoPointer (PPDEV ppdev,
SURFOBJ *psoMask);
BOOL bSetHardwarePointerShape (SURFOBJ *pso,
SURFOBJ *psoMask,
SURFOBJ *psoColor,
XLATEOBJ *pxlo,
LONG x,
LONG y,
FLONG fl);
// This table is for 24 plane boards only, where we're
// using the TGAs cursor management capability.
//
// This table contains 'merged' versions of two 4-bit
// sequences of the AND (cursor image) and XOR cursor
// masks.
//
// We have to stuff the cursor bits into the low 1k of
// the frame buffer, in the format the bt463 ramdac
// expects.
//
// The format is one in which the AND bit for a given
// pixel is followed by the XOR bit for that same pixel.
// Actually, it's a little more involved than that, so
// see comments in the new code below.
//
// Instead of doing all the shifting and or'ing of the
// individual bits, this table allows us to quickly
// deal with four bits from the AND and XOR mask at
// a time, generating one 'merged' byte of four (4)
// pixels. It was pulled from the TGA OSF driver.
// Good deal, huh?
static unsigned char
cursor_merged_bits [256] = {
0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a, // 7
0x80, 0x82, 0x88, 0x8a, 0xa0, 0xa2, 0xa8, 0xaa, // 15
0x01, 0x03, 0x09, 0x0b, 0x21, 0x23, 0x29, 0x2b, // 23
0x81, 0x83, 0x89, 0x8b, 0xa1, 0xa3, 0xa9, 0xab, // 31
0x04, 0x06, 0x0c, 0x0e, 0x24, 0x26, 0x2c, 0x2e, // 39
0x84, 0x86, 0x8c, 0x8e, 0xa4, 0xa6, 0xac, 0xae, // 47
0x05, 0x07, 0x0d, 0x0f, 0x25, 0x27, 0x2d, 0x2f, // 55
0x85, 0x87, 0x8d, 0x8f, 0xa5, 0xa7, 0xad, 0xaf, // 63
0x10, 0x12, 0x18, 0x1a, 0x30, 0x32, 0x38, 0x3a, // 71
0x90, 0x92, 0x98, 0x9a, 0xb0, 0xb2, 0xb8, 0xba, // 79
0x11, 0x13, 0x19, 0x1b, 0x31, 0x33, 0x39, 0x3b, // 87
0x91, 0x93, 0x99, 0x9b, 0xb1, 0xb3, 0xb9, 0xbb, // 95
0x14, 0x16, 0x1c, 0x1e, 0x34, 0x36, 0x3c, 0x3e, // 103
0x94, 0x96, 0x9c, 0x9e, 0xb4, 0xb6, 0xbc, 0xbe, // 111
0x15, 0x17, 0x1d, 0x1f, 0x35, 0x37, 0x3d, 0x3f, // 119
0x95, 0x97, 0x9d, 0x9f, 0xb5, 0xb7, 0xbd, 0xbf, // 127
0x40, 0x42, 0x48, 0x4a, 0x60, 0x62, 0x68, 0x6a, // 135
0xc0, 0xc2, 0xc8, 0xca, 0xe0, 0xe2, 0xe8, 0xea, // 143
0x41, 0x43, 0x49, 0x4b, 0x61, 0x63, 0x69, 0x6b, // 151
0xc1, 0xc3, 0xc9, 0xcb, 0xe1, 0xe3, 0xe9, 0xeb, // 159
0x44, 0x46, 0x4c, 0x4e, 0x64, 0x66, 0x6c, 0x6e, // 167
0xc4, 0xc6, 0xcc, 0xce, 0xe4, 0xe6, 0xec, 0xee, // 175
0x45, 0x47, 0x4d, 0x4f, 0x65, 0x67, 0x6d, 0x6f, // 183
0xc5, 0xc7, 0xcd, 0xcf, 0xe5, 0xe7, 0xed, 0xef, // 191
0x50, 0x52, 0x58, 0x5a, 0x70, 0x72, 0x78, 0x7a, // 199
0xd0, 0xd2, 0xd8, 0xda, 0xf0, 0xf2, 0xf8, 0xfa, // 207
0x51, 0x53, 0x59, 0x5b, 0x71, 0x73, 0x79, 0x7b, // 215
0xd1, 0xd3, 0xd9, 0xdb, 0xf1, 0xf3, 0xf9, 0xfb, // 223
0x54, 0x56, 0x5c, 0x5e, 0x74, 0x76, 0x7c, 0x7e, // 231
0xd4, 0xd6, 0xdc, 0xde, 0xf4, 0xf6, 0xfc, 0xfe, // 239
0x55, 0x57, 0x5d, 0x5f, 0x75, 0x77, 0x7d, 0x7f, // 247
0xd5, 0xd7, 0xdd, 0xdf, 0xf5, 0xf7, 0xfd, 0xff // 255
};
/******************************Public*Routine******************************\
* DrvMovePointer
*
* Moves the hardware pointer to a new position.
*
\**************************************************************************/
VOID DrvMovePointer (SURFOBJ *pso,
LONG x,
LONG y,
RECTL *prcl)
{
PPDEV ppdev = (PPDEV) pso->dhpdev;
DWORD returnedDataLength;
VIDEO_POINTER_POSITION NewPointerPosition;
ULONG ulCursor_XY;
LONG lXValue, lYValue;
ULONG ulRows, ulBase = 0;
VVALIDREG VideoValidReg;
// We don't use the exclusion rectangle because we only support
// hardware Pointers. If we were doing our own Pointer simulations
// we would want to update prcl so that the engine would call us
// to exclude out pointer before drawing to the pixels in prcl.
UNREFERENCED_PARAMETER (prcl);
DISPDBG ((1, "TGA.DLL!DrvMovePointer - Entry, x [%d][%x], y [%d][%x]\n",
x, x, y, y));
if (x == -1)
{
// A new position of (-1,-1) means hide the pointer.
if (8 == ppdev->ulBitCount)
{
if (EngDeviceIoControl (ppdev->hDriver,
IOCTL_VIDEO_DISABLE_POINTER,
NULL,
0,
NULL,
0,
&returnedDataLength))
{
// Not the end of the world, print warning in checked build.
DISPDBG ((1, "DISP vMoveHardwarePointer failed IOCTL_VIDEO_DISABLE_POINTER\n"));
}
}
else
{
DISPDBG ((2, "TGA.DLL!DrvMovePointer - disabling cursor\n"));
// Disable the cursor.
WBFLUSH (ppdev);
TGASYNC (ppdev);
TGAVIDEOVALIDREAD (ppdev, VideoValidReg.u32);
VideoValidReg.reg.cursor_enable = 0;
TGAVIDEOVALID (ppdev, VideoValidReg.u32);
}
}
else
{
if (8 == ppdev->ulBitCount)
{
NewPointerPosition.Column = (SHORT) x - (SHORT) (ppdev->ptlHotSpot.x);
NewPointerPosition.Row = (SHORT) y - (SHORT) (ppdev->ptlHotSpot.y);
// Call NT screen driver to move Pointer.
if (EngDeviceIoControl (ppdev->hDriver,
IOCTL_VIDEO_SET_POINTER_POSITION,
&NewPointerPosition,
sizeof(VIDEO_POINTER_POSITION),
NULL,
0,
&returnedDataLength))
{
// Not the end of the world, print warning in checked build.
DISPDBG((1, "DISP vMoveHardwarePointer failed IOCTL_VIDEO_SET_POINTER_POSITION\n"));
}
}
else
{
WBFLUSH (ppdev);
// The x position is in the low-order 12 bits.
// The y position is in the next 12 bits.
// The high 8 bits are reserved.
//
// Take into account where the hot spot needs to be
// in relation to the start of the cursor itself and
// the X and Y offsets calculated at startup.
lXValue = (x + ppdev->ulCursorXOffset - ppdev->ptlHotSpot.x);
lYValue = (y + ppdev->ulCursorYOffset - ppdev->ptlHotSpot.y);
// Adjust the Y offset/ulBase/ulRows. Why? It has something to do
// with those situations when in an attempt to move the hot spot
// to the outermost (top,bottom,right,left) pixel, and there isn't
// enough 'back porch(?)' screen real-estate to handle a large cursor
// image rectangle, like 64x64, to allow the 'hot spot' to get to the
// last pixel on the screen. So, we need to adjust the cursor base
// address and the number of rows in order to allow us to do that.
// Confusing, huh? Yuh, I know! Sorry I can't explain it any better
// but I just barely understand it myself. This code was taken from
// the TGA OSF driver and it seems to produce the desired effect.
if (0 > lYValue)
{
ulBase = ulRows = (ULONG) (-lYValue);
lYValue = 0;
}
else
{
if (64 <= (ulRows = ppdev->cyScreen + 3 - y + ppdev->ptlHotSpot.y))
{
ulRows = 64;
}
}
// Update the Cursor Base Address, if necessary.
if (ulRows != ppdev->ulCursorPreviousRows)
{
TGACURSORBASE (ppdev, (((ulRows - 1) << 10) | (ulBase << 4)) );
ppdev->ulCursorPreviousRows = ulRows;
}
// Build the cursor xy position value for later use.
ulCursor_XY = (lYValue << 12) | lXValue;
DISPDBG ((2, "TGA.DLL!DrvMovePointer - ppdev: XOffset [%d], YOffset [%d]\n",
ppdev->ulCursorXOffset, ppdev->ulCursorYOffset));
DISPDBG ((2, "TGA.DLL!DrvMovePointer - XValue [%d][%x], YValue [%d][%x]\n",
lXValue, lXValue, lYValue, lYValue));
DISPDBG ((2, "TGA.DLL!DrvMovePointer - cursor xy [%08x], ppdev: hot x [%d], hot y [%d]\n",
ulCursor_XY, ppdev->ptlHotSpot.x, ppdev->ptlHotSpot.y));
// Make sure TGA-based cursor management is enabled.
TGASYNC (ppdev);
TGAVIDEOVALIDREAD (ppdev, VideoValidReg.u32);
VideoValidReg.reg.cursor_enable = 1;
TGAVIDEOVALID (ppdev, VideoValidReg.u32);
// Update the cursor x,y position.
TGACURSOR (ppdev, ulCursor_XY);
}
}
DISPDBG ((1, "TGA.DLL!DrvMovePointer - Exit\n"));
}
/******************************Public*Routine******************************\
* DrvSetPointerShape
*
* Sets the new pointer shape.
*
\**************************************************************************/
ULONG DrvSetPointerShape (SURFOBJ *pso,
SURFOBJ *psoMask,
SURFOBJ *psoColor,
XLATEOBJ *pxlo,
LONG xHot,
LONG yHot,
LONG x,
LONG y,
RECTL *prcl,
FLONG fl)
{
PPDEV ppdev = (PPDEV) pso->dhpdev;
DWORD returnedDataLength;
VVALIDREG VideoValidReg;
// We don't use the exclusion rectangle because we only support
// hardware Pointers. If we were doing our own Pointer simulations
// we would want to update prcl so that the engine would call us
// to exclude out pointer before drawing to the pixels in prcl.
UNREFERENCED_PARAMETER(prcl);
DISPDBG ((1, "TGA.DLL!DrvSetPointerShape - Entry\n"));
if (ppdev->pPointerAttributes == (PVIDEO_POINTER_ATTRIBUTES) NULL)
{
// Mini-port has no hardware Pointer support.
return SPS_ERROR;
}
// See if we are being asked to hide the pointer
if (psoMask == (SURFOBJ *) NULL)
{
if (8 == ppdev->ulBitCount)
{
if (EngDeviceIoControl (ppdev->hDriver,
IOCTL_VIDEO_DISABLE_POINTER,
NULL,
0,
NULL,
0,
&returnedDataLength))
{
// It should never be possible to fail.
// Message supplied for debugging.
DISPDBG ((0, "DISP bSetHardwarePointerShape failed IOCTL_VIDEO_DISABLE_POINTER\n"));
}
}
else
{
DISPDBG ((2, "TGA.DLL!DrvSetPointerShape - disabling cursor #1\n"));
// Disable the cursor.
WBFLUSH (ppdev);
TGASYNC (ppdev);
TGAVIDEOVALIDREAD (ppdev, VideoValidReg.u32);
VideoValidReg.reg.cursor_enable = 0;
TGAVIDEOVALID (ppdev, VideoValidReg.u32);
}
return TRUE;
}
// Remember the cursor hot-spot.
ppdev->ptlHotSpot.x = xHot;
ppdev->ptlHotSpot.y = yHot;
// Copy the new cursor shape.
if (! bSetHardwarePointerShape (pso, psoMask, psoColor, pxlo, x, y, fl))
{
if (ppdev->fHwCursorActive)
{
ppdev->fHwCursorActive = FALSE;
if (8 == ppdev->ulBitCount)
{
if (EngDeviceIoControl (ppdev->hDriver,
IOCTL_VIDEO_DISABLE_POINTER,
NULL,
0,
NULL,
0,
&returnedDataLength))
{
DISPDBG ((0, "DISP bSetHardwarePointerShape failed IOCTL_VIDEO_DISABLE_POINTER\n"));
}
}
else
{
DISPDBG ((2, "TGA.DLL!DrvSetPointerShape - disabling cursor #2\n"));
// Disable the cursor.
WBFLUSH (ppdev);
TGASYNC (ppdev);
TGAVIDEOVALIDREAD (ppdev, VideoValidReg.u32);
VideoValidReg.reg.cursor_enable = 0;
TGAVIDEOVALID (ppdev, VideoValidReg.u32);
}
}
// Mini-port declines to realize this Pointer
DISPDBG ((1, "TGA.DLL!DrvSetPointerShape - Exit (declining!!)\n"));
return SPS_DECLINE;
}
else
ppdev->fHwCursorActive = TRUE;
DISPDBG ((1, "TGA.DLL!DrvSetPointerShape - Exit (normal)\n"));
return SPS_ACCEPT_NOEXCLUDE;
}
/******************************Public*Routine******************************\
* bSetHardwarePointerShape
*
* Changes the shape of the Hardware Pointer.
*
* Returns: True if successful, False if Pointer shape can't be hardware.
*
\**************************************************************************/
BOOL bSetHardwarePointerShape (SURFOBJ *pso,
SURFOBJ *psoMask,
SURFOBJ *psoColor,
XLATEOBJ *pxlo,
LONG x,
LONG y,
FLONG fl)
{
PPDEV ppdev = (PPDEV) pso->dhpdev;
PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
DWORD returnedDataLength;
ULONG *pulFB, j;
ULONG *pulCursorBits;
DISPDBG ((1, "TGA.DLL!bSetHardwarePointerShape - Entry\n"));
// Get the new cursor bits.
if (psoColor != (SURFOBJ *) NULL)
{
if ((ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER) &&
bCopyColorPointer (ppdev, psoMask, psoColor, pxlo))
{
pPointerAttributes->Flags |= VIDEO_MODE_COLOR_POINTER;
}
else
{
DISPDBG ((0, "TGA.DLL!bSetHWPointerShape - CopyColor failed!\n"));
return FALSE;
}
}
else
{
if ((ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER) &&
bCopyMonoPointer(ppdev, psoMask))
{
pPointerAttributes->Flags |= VIDEO_MODE_MONO_POINTER;
}
else
{
DISPDBG ((0, "TGA.DLL!bSetHWPointerShape - CopyMono failed!\n"));
return(FALSE);
}
}
// Initialize Pointer attributes and position
pPointerAttributes->Column = (SHORT)(x - ppdev->ptlHotSpot.x);
pPointerAttributes->Row = (SHORT)(y - ppdev->ptlHotSpot.y);
pPointerAttributes->Enable = 1;
if (fl & SPS_ANIMATESTART)
{
pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_START;
}
else
if (fl & SPS_ANIMATEUPDATE)
{
pPointerAttributes->Flags |= VIDEO_MODE_ANIMATE_UPDATE;
}
// Set the new Pointer shape.
//
// For 8 plane boards, ask the kernel driver to write the
// bits to the ramdac.
//
// For 24 plane boards, use simple mode to write the bits
// to the first 1k of the frame buffer.
if (8 == ppdev->ulBitCount)
{
if (EngDeviceIoControl (ppdev->hDriver,
IOCTL_VIDEO_SET_POINTER_ATTR,
pPointerAttributes,
ppdev->cjPointerAttributes,
NULL,
0,
&returnedDataLength))
{
DISPDBG((1, "DISP:Failed IOCTL_VIDEO_SET_POINTER_ATTR call\n"));
return FALSE;
}
}
else
{
// Move to the new pointer location.
DrvMovePointer (pso, x, y, NULL);
// Copy the new cursor bits to the frame buffer.
DISPDBG ((2, "TGA.DLL!bSetHardwarePointerShape - 24 plane copy to FB\n"));
pulFB = (ULONG *) ppdev->pjVideoMemory;
pulCursorBits = (ULONG *) ppdev->pjCursorBuffer;
DISPDBG ((2, "TGA.DLL!bSetHWPointerShape - S->FB, pulFB [%08x], pulCursorBits [%08x]\n",
pulFB, pulCursorBits));
WBFLUSH (ppdev);
TGAPLANEMASK (ppdev, 0xffffffff);
TGAPIXELMASK (ppdev, 0xffffffff);
TGAMODE (ppdev, ppdev->ulModeTemplate | TGA_MODE_SIMPLE);
TGAROP (ppdev, ppdev->ulRopTemplate | TGA_ROP_COPY);
// When setting planemask to something other than ulPlanemaskTemplate
// we must set state to 'NOT Simple mode'.
ppdev->bSimpleMode = FALSE;
for (j = 0; j < (TGA_CURSOR_BUFFER_SIZE / 4); j++)
{
DISPDBG ((2, "TGA.DLL!bSetHWPointerShape/S->FB/j [%d], pulFB [%08x][%08x], *pulCursorBits [%08x][%08x]\n",
j, pulFB, *pulFB, pulCursorBits, *pulCursorBits));
TGAWRITE (ppdev, pulFB, *pulCursorBits);
pulFB++;
pulCursorBits++;
}
}
DISPDBG ((1, "TGA.DLL!bSetHardwarePointerShape - Exit\n"));
return TRUE;
}
/******************************Public*Routine******************************\
* bCopyMonoPointer
*
* Copies two monochrome masks into a buffer of the maximum size handled by the
* miniport, with any extra bits set to 0. The masks are converted to topdown
* form if they aren't already. Returns TRUE if we can handle this pointer in
* hardware, FALSE if not.
*
\**************************************************************************/
BOOL bCopyMonoPointer (PPDEV ppdev,
SURFOBJ *pso)
{
ULONG cy;
PBYTE pjSrcAnd, pjSrcXor;
LONG lDeltaSrc, lDeltaDst;
LONG lSrcWidthInBytes;
ULONG cxSrc = pso->sizlBitmap.cx;
ULONG cySrc = pso->sizlBitmap.cy;
ULONG cxSrcBytes;
PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = ppdev->pPointerAttributes;
PBYTE pjDstAnd;
PBYTE pjDstXor;
PBYTE pjDst;
ULONG *pulDst;
ULONG ulAndBits, ulXorBits, ulMask, ulEvenMask, ulOddMask;
ULONG i, j, iShifts;
DISPDBG ((1, "TGA.DLL!bCopyMonoPointer - Entry\n"));
// Make sure the new pointer isn't too big to handle
// (*2 because both masks are in there)
if ((cxSrc > ppdev->PointerCapabilities.MaxWidth) ||
(cySrc > (ppdev->PointerCapabilities.MaxHeight * 2)))
{
return FALSE;
}
// For 8 plane boards, load up the cursor bits into a temporary
// area that is later accessed by the kernel driver, which loads
// the bits into the ramdac.
//
// For 24 plane boards, load up the 'merged' cursor bits into a
// temporary buffer that is later accessed by this driver to write
// the bits to the first 1k of the frame buffer. The ramdac pulls
// the bits for the cursor directly from there (it's hardwired).
if (8 == ppdev->ulBitCount)
{
pjDstAnd = pPointerAttributes->Pixels;
pjDstXor = pPointerAttributes->Pixels +
((ppdev->PointerCapabilities.MaxWidth + 7) / 8) *
ppdev->pPointerAttributes->Height;
// set the desk and mask to 0xff
RtlFillMemory(pjDstAnd, ppdev->pPointerAttributes->WidthInBytes *
ppdev->pPointerAttributes->Height, 0xFF);
// Zero the dest XOR mask
RtlZeroMemory (pjDstXor, ppdev->pPointerAttributes->WidthInBytes *
ppdev->pPointerAttributes->Height);
cxSrcBytes = (cxSrc + 7) / 8;
if ((lDeltaSrc = pso->lDelta) < 0)
{
lSrcWidthInBytes = -lDeltaSrc;
}
else
{
lSrcWidthInBytes = lDeltaSrc;
}
pjSrcAnd = (PBYTE) pso->pvBits;
// If the incoming pointer bitmap is bottomup, we'll flip it to topdown to
// save the miniport some work
if (! (pso->fjBitmap & BMF_TOPDOWN))
{
// Copy from the bottom
pjSrcAnd += lSrcWidthInBytes * (cySrc - 1);
}
// Height of just AND mask
cySrc = cySrc / 2;
// Point to XOR mask
pjSrcXor = pjSrcAnd + (cySrc * lDeltaSrc);
// Offset from end of one dest scan to start of next
lDeltaDst = ppdev->pPointerAttributes->WidthInBytes;
for (cy = 0; cy < cySrc; ++cy)
{
RtlCopyMemory (pjDstAnd, pjSrcAnd, cxSrcBytes);
RtlCopyMemory (pjDstXor, pjSrcXor, cxSrcBytes);
// Point to next source and dest scans
pjSrcAnd += lDeltaSrc;
pjSrcXor += lDeltaSrc;
pjDstAnd += lDeltaDst;
pjDstXor += lDeltaDst;
}
}
else
{
// This code handles cursors of width and height 1->64 pixels.
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - Starting 24plane code\n"));
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - cxSrc [%d], cySrc [%d]\n", cxSrc, cySrc));
// Destination location - a temporary buffer.
pjDst = ppdev->pjCursorBuffer;
if ((lDeltaSrc = pso->lDelta) < 0)
{
lSrcWidthInBytes = -lDeltaSrc;
}
else
{
lSrcWidthInBytes = lDeltaSrc;
}
pjSrcAnd = (PBYTE) pso->pvBits;
// If the incoming pointer bitmap is bottomup, we'll flip it to topdown to
// save the miniport some work.
if (! (pso->fjBitmap & BMF_TOPDOWN))
{
// Copy from the bottom
pjSrcAnd += lSrcWidthInBytes * (cySrc - 1);
}
// Height of just the AND mask.
cySrc = cySrc / 2;
// Point to XOR mask
pjSrcXor = pjSrcAnd + (cySrc * lDeltaSrc);
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - pjDst [%08x], pjSrcAnd [%08x], pjSrcXor [%08x]\n",
pjDst, pjSrcAnd, pjSrcXor));
// Offset from end of one dest scan to start of next
lDeltaDst = ppdev->pPointerAttributes->WidthInBytes;
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - lDeltaSrc [%d], lDeltaDst [%d]\n",
lDeltaSrc, lDeltaDst));
// Assume, by default, the cursor is 32 pixels wide.
ulMask = 0xffffffff;
// Adjust masks as necessary, for cursor bitmaps
// that are either 1->32 pixels wide, or 33->64
// pixels wide.
if (cxSrc > 32)
{
// Double the height for a cursor that is more than
// 32 pixels wide, because we'll have to go through
// the loop below twice the number of times.
//
cySrc *= 2;
//
// Adjust the shift value, so the mask shifting will
// generate the appropriate mask.
//
iShifts = 32 - (cxSrc - 32);
//
// ulEvenMask represents the first 32 bits for this
// very wide cursor.
//
ulEvenMask = 0xffffffff;
//
// ulOddMask represents the rest (0->32) of the bits,
// so need to adjust that mask appropriately.
//
ulOddMask = (ulEvenMask << iShifts) >> iShifts;
}
else
{
iShifts = 32 - cxSrc;
//
// This cursor is 1->32 pixels wide, so adjust both
// the even and odd masks appropriately.
//
ulEvenMask = ulOddMask = (ulMask << iShifts) >> iShifts;
}
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - ulMask [%08x], ulEMask [%08x], ulOmask [%08x]\n",
ulMask, ulEvenMask, ulOddMask));
// For each cursor scan line, write the merged bits
// to the 'merged' cursor bits buffer.
for (i = 0; i < cySrc; i++)
{
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - top of loop, i [%d]==================\n", i));
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - pjDst [%08x], pjSrcAnd [%08x], pjSrcXor [%08x]\n",
pjDst, pjSrcAnd, pjSrcXor));
// Use the appropriate mask, based on loop iteration.
// They could be difference only when the source
// cursor pixel width is greater than 32.
ulMask = ulEvenMask;
if (i & 0x1) ulMask = ulOddMask;
// Get the next 32bits of the AND and XOR masks.
ulAndBits = *((ULONG *) pjSrcAnd) & ulMask;
ulXorBits = *((ULONG *) pjSrcXor) & ulMask;
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - ulAndBits [%08x], ulXorBits [%08x]\n",
ulAndBits, ulXorBits));
// Reverse the bits, since this is a monochrome bitmap and we need
// a given bytes bits in memory low->high and NT gives them to us
// high->low. Isn't that nice of them!?
REVERSE_BYTE (ulAndBits);
REVERSE_BYTE (ulXorBits);
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - ulAndBits [%08x], ulXorBits [%08x]\n",
ulAndBits, ulXorBits));
// For one longword, merge the bits and stuff the merged bits
// into the temporary cursor buffer.
DISPDBG ((2, "TGA.DLL!bCopy - ["));
// Ok, here goes my attempt at explaining the bit twiddling below.
//
// GDI presents us with two monochrome bitmaps. The AND mask (which
// is the cursor image) and the XOR mask, which is supposed to define
// what bits (pixels) of the AND mask are eligible for display.
//
// An XOR bit value of zero (0) means this pixel is transparent, i.e.
// no change to the pixel color that is currently there. A value of
// one (1) means use the AND mask bit value to determine whether to
// use the foreground or background color register value for this pixel.
//
// An AND bit value of zero (0) means use the background color, and
// a value of one (1) means use the foreground color. These colors
// come from the ramdacs foreground and background registers that
// are loaded by the kernel driver. You can load any two colors into
// these registers, not just black and white.
//
// Ok so far, next:
//
// Based on the TGA documentation, the VMS and OSF drivers for TGA,
// and conversations with various folks, what I originally figured
// we could do was simply sequence the bits as AXAXAXAX... (where
// A is for AND bit and X is for XOR bit) and stuff this into the
// low 1k of the frame buffer. Sounded simple enough, especially
// after I stole some OSF code that allowed me to quickly convert
// a nibble (4 bits) of the AND and XOR masks into a byte (8 bits)
// of combined and sequenced output - ready and waiting for the
// ramdac to read it in.
//
// As such, that would have made the 'merge' code:
//
// *pjDst = cursor_merged_bits [((ulAndBits << 4) |
// (ulXorBits & 0xf)) & 0xff];
//
// for every 4 bits of AND and XOR source.
//
// Well, as it turns out, it's not quite that simple. (Isn't it always!)
//
// The above algorithm was producing a background color where
// the foreground should have been and was missing altogether the
// border around the cursor, where the background color 'should' have
// shown up.
//
// To try to figure this out I manually graphed the AND and XOR bits
// onto some graph paper (overlaying the XOR on top of the AND bits)
// for a given set of cursor bits and quickly discovered that all the
// right bits where there, I was just using them in the wrong way.
// The 'merge' code below reflects that realization, and produces
// the correct cursor image.
//
// As you can see, the 'AND bit part' of each pixel is 'AND OR XOR',
// while the 'XOR bit part' is really the negation of the AND bit for
// that same pixel. NOT what I would have expected, BUT, as they say
// somewhere, it works!! and it makes sense based on what we're getting
// from GDI. The new AND and XOR bits are then OR'd to provide an index
// into the conversion array, which gives us back 'merged' bits for a
// 4 pixel sequence, or a total of 8 bits.
//
// Actually, the above explanation is the case for most cursors. The
// I-beam cursor, however, needs a different bit merging scheme to
// appear correctly. It takes the 'else' path in the 'if' statement
// below.
for (j = 0; j < 8; j++)
{
if (!((ulAndBits & 0xf) & (ulXorBits & 0xf)))
*pjDst = cursor_merged_bits [(((ulAndBits | ulXorBits) << 4) |
(~ulAndBits & 0xf)) & 0xff];
else
*pjDst = cursor_merged_bits [((~ulAndBits << 4) |
(ulXorBits & 0xf)) & 0xff];
DISPDBG ((2, "%02x ", *pjDst));
pjDst++;
ulAndBits >>= 4;
ulXorBits >>= 4;
}
DISPDBG ((2, "]\n"));
// If the source cursor is a 1->32 pixel wide cursor,
// then we have to Zero out the rest of this 'scan-line',
// since the bt463 expects a 64x64 cursor image.
if (cxSrc <= 32)
{
DISPDBG ((2, "TGA.DLL!bCopy - Finish, pjDst [%08x]\n", pjDst));
pulDst = (ULONG *) pjDst;
*pulDst++ = 0L;
*pulDst++ = 0L;
pjDst = (PBYTE) pulDst;
}
// Bump the source pointers.
pjSrcAnd += lDeltaSrc;
pjSrcXor += lDeltaSrc;
}
// Fill the rest of the temporary 'merged' cursor area to zero.
// Effectively making those pixels transparent.
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - Finish the rest of the buffer\n"));
pulDst = (ULONG *) pjDst;
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - From: pulDst [%08x], To: Curs+buffsize [%08x]\n",
pulDst, ppdev->pjCursorBuffer + TGA_CURSOR_BUFFER_SIZE));
while (pulDst < (ULONG *) (ppdev->pjCursorBuffer + TGA_CURSOR_BUFFER_SIZE))
{
DISPDBG ((2, "TGA.DLL!bCopyMonoPointer - pulDst [%08x]\n", pulDst));
*pulDst++ = 0L;
}
}
DISPDBG ((1, "TGA.DLL!bCopyMonoPointer - Exit\n"));
return TRUE;
}
/******************************Public*Routine******************************\
* bCopyColorPointer
*
* Copies the mono and color masks into the buffer of maximum size
* handled by the miniport with any extra bits set to 0. Color translation
* is handled at this time. The masks are converted to topdown form if they
* aren't already. Returns TRUE if we can handle this pointer in hardware,
* FALSE if not.
*
\**************************************************************************/
BOOL bCopyColorPointer (PPDEV ppdev,
SURFOBJ *psoMask,
SURFOBJ *psoColor,
XLATEOBJ *pxlo)
{
DISPDBG ((0, "TGA.DLL!bCopyColorPointer - Entry!!!! Shouldn't ever get this!!!\n"));
return FALSE;
}
/******************************Public*Routine******************************\
* bInitPointer
*
* Initialize the Pointer attributes.
*
\**************************************************************************/
BOOL bInitPointer (PPDEV ppdev, DEVINFO *pdevinfo)
{
DWORD returnedDataLength;
ppdev->pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES) NULL;
ppdev->cjPointerAttributes = 0; // initialized in screen.c
DISPDBG ((1, "TGA.DLL!bInitPointer - Entry\n"));
// Ask the miniport whether it provides pointer support.
if (EngDeviceIoControl (ppdev->hDriver,
IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES,
&ppdev->ulMode,
sizeof(PVIDEO_MODE),
&ppdev->PointerCapabilities,
sizeof(ppdev->PointerCapabilities),
&returnedDataLength))
{
return FALSE;
}
// If neither mono nor color hardware pointer is supported, there's no
// hardware pointer support and we're done.
if ((!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_MONO_POINTER)) &&
(!(ppdev->PointerCapabilities.Flags & VIDEO_MODE_COLOR_POINTER)))
{
return TRUE;
}
// Note: The buffer itself is allocated after we set the
// mode. At that time we know the pixel depth and we can
// allocate the correct size for the color pointer if supported.
// Set the asynchronous support status (async means miniport is capable of
// drawing the Pointer at any time, with no interference with any ongoing
// drawing operation).
//
// Note that this does *NOT* include *setting* the cursor shape!
if (ppdev->PointerCapabilities.Flags & VIDEO_MODE_ASYNC_POINTER)
{
pdevinfo->flGraphicsCaps |= GCAPS_ASYNCMOVE;
}
DISPDBG ((1, "TGA.DLL!bInitPointer - Exit\n"));
return TRUE;
}