mirror of https://github.com/lianthony/NT4.0
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
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;
|
|
|
|
}
|
|
|