mirror of
https://github.com/VirtualDrivers/Virtual-Display-Driver.git
synced 2026-10-22 06:32:32 -05:00
347 lines
12 KiB
C++
347 lines
12 KiB
C++
/******************************Module*Header*******************************\
|
|
* Module Name: BltFuncs.cxx
|
|
*
|
|
* Basic Display Driver copying functionality
|
|
*
|
|
*
|
|
* Copyright (c) 2010 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "BDD.hxx"
|
|
|
|
// For the following macros, c must be a UCHAR.
|
|
#define UPPER_6_BITS(c) (((c) & rMaskTable[6 - 1]) >> 2)
|
|
#define UPPER_5_BITS(c) (((c) & rMaskTable[5 - 1]) >> 3)
|
|
#define LOWER_6_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 6])
|
|
#define LOWER_5_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 5])
|
|
|
|
|
|
#define SHIFT_FOR_UPPER_5_IN_565 (6 + 5)
|
|
#define SHIFT_FOR_MIDDLE_6_IN_565 (5)
|
|
#define SHIFT_UPPER_5_IN_565_BACK ((BITS_PER_BYTE * 2) + (BITS_PER_BYTE - 5))
|
|
#define SHIFT_MIDDLE_6_IN_565_BACK ((BITS_PER_BYTE * 1) + (BITS_PER_BYTE - 6))
|
|
#define SHIFT_LOWER_5_IN_565_BACK ((BITS_PER_BYTE * 0) + (BITS_PER_BYTE - 5))
|
|
|
|
// For the following macros, pPixel must be a BYTE* pointing to the start of a 32 bit pixel
|
|
#define CONVERT_32BPP_TO_16BPP(pPixel) ((UPPER_5_BITS(pPixel[2]) << SHIFT_FOR_UPPER_5_IN_565) | \
|
|
(UPPER_6_BITS(pPixel[1]) << SHIFT_FOR_MIDDLE_6_IN_565) | \
|
|
(UPPER_5_BITS(pPixel[0])))
|
|
|
|
// 8bpp is done with 6 levels per color channel since this gives true grays, even if it leaves 40 empty palette entries
|
|
// The 6 levels per color is the reason for dividing below by 43 (43 * 6 == 258, closest multiple of 6 to 256)
|
|
// It is also the reason for multiplying the red channel by 36 (== 6*6) and the green channel by 6, as this is the
|
|
// equivalent to bit shifting in a 3:3:2 model. Changes to this must be reflected in vesasup.cxx with the Blues/Greens/Reds arrays
|
|
#define CONVERT_32BPP_TO_8BPP(pPixel) (((pPixel[2] / 43) * 36) + \
|
|
((pPixel[1] / 43) * 6) + \
|
|
((pPixel[0] / 43)))
|
|
|
|
// 4bpp is done with strict grayscale since this has been found to be usable
|
|
// 30% of the red value, 59% of the green value, and 11% of the blue value is the standard way to convert true color to grayscale
|
|
#define CONVERT_32BPP_TO_4BPP(pPixel) ((BYTE)(((pPixel[2] * 30) + \
|
|
(pPixel[1] * 59) + \
|
|
(pPixel[0] * 11)) / (100 * 16)))
|
|
|
|
|
|
// For the following macro, Pixel must be a WORD representing a 16 bit pixel
|
|
#define CONVERT_16BPP_TO_32BPP(Pixel) (((ULONG)LOWER_5_BITS((Pixel) >> SHIFT_FOR_UPPER_5_IN_565) << SHIFT_UPPER_5_IN_565_BACK) | \
|
|
((ULONG)LOWER_6_BITS((Pixel) >> SHIFT_FOR_MIDDLE_6_IN_565) << SHIFT_MIDDLE_6_IN_565_BACK) | \
|
|
((ULONG)LOWER_5_BITS((Pixel)) << SHIFT_LOWER_5_IN_565_BACK))
|
|
|
|
#pragma code_seg(push)
|
|
#pragma code_seg()
|
|
// BEGIN: Non-Paged Code
|
|
|
|
// Bit is 1 from Idx to end of byte, with bit count starting at high order
|
|
BYTE lMaskTable[BITS_PER_BYTE] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
|
|
|
|
// Bit is 1 from Idx to start of byte, with bit count starting at high order
|
|
BYTE rMaskTable[BITS_PER_BYTE] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
|
|
|
|
// Bit of Idx is 1, with bit count starting at high order
|
|
BYTE PixelMask[BITS_PER_BYTE] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
|
|
|
|
/****************************Internal*Routine******************************\
|
|
* CopyBits32_32
|
|
*
|
|
*
|
|
* Copies rectangles from one surface to another. Both surfaces must have
|
|
* the same resolution.
|
|
*
|
|
* OffsetX, OffsetY - to add to the rectangle coordinates.
|
|
*
|
|
* Copied from %SDXROOT%\windows\Core\dxkernel\cdd\enable.cxx (CopySurfBits)
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID CopyBits32_32(
|
|
BLT_INFO* pDst,
|
|
CONST BLT_INFO* pSrc,
|
|
UINT NumRects,
|
|
_In_reads_(NumRects) CONST RECT *pRects)
|
|
{
|
|
NT_ASSERT((pDst->BitsPerPel == 32) &&
|
|
(pSrc->BitsPerPel == 32));
|
|
NT_ASSERT((pDst->Rotation == D3DKMDT_VPPR_IDENTITY) &&
|
|
(pSrc->Rotation == D3DKMDT_VPPR_IDENTITY));
|
|
|
|
for (UINT iRect = 0; iRect < NumRects; iRect++)
|
|
{
|
|
CONST RECT* pRect = &pRects[iRect];
|
|
|
|
NT_ASSERT(pRect->right >= pRect->left);
|
|
NT_ASSERT(pRect->bottom >= pRect->top);
|
|
|
|
UINT NumPixels = pRect->right - pRect->left;
|
|
UINT NumRows = pRect->bottom - pRect->top;
|
|
UINT BytesToCopy = NumPixels * 4;
|
|
BYTE* pStartDst = ((BYTE*)pDst->pBits +
|
|
(pRect->top + pDst->Offset.y) * pDst->Pitch +
|
|
(pRect->left + pDst->Offset.x) * 4);
|
|
CONST BYTE* pStartSrc = ((BYTE*)pSrc->pBits +
|
|
(pRect->top + pSrc->Offset.y) * pSrc->Pitch +
|
|
(pRect->left + pSrc->Offset.x) * 4);
|
|
|
|
for (UINT i = 0; i < NumRows; ++i)
|
|
{
|
|
RtlCopyMemory(pStartDst, pStartSrc, BytesToCopy);
|
|
pStartDst += pDst->Pitch;
|
|
pStartSrc += pSrc->Pitch;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch)
|
|
{
|
|
switch (pBltInfo->Rotation)
|
|
{
|
|
case D3DKMDT_VPPR_IDENTITY:
|
|
{
|
|
*pPixelPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
|
|
*pRowPitch = pBltInfo->Pitch;
|
|
return;
|
|
}
|
|
case D3DKMDT_VPPR_ROTATE90:
|
|
{
|
|
*pPixelPitch = -((LONG)pBltInfo->Pitch);
|
|
*pRowPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
|
|
return;
|
|
}
|
|
case D3DKMDT_VPPR_ROTATE180:
|
|
{
|
|
*pPixelPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE);
|
|
*pRowPitch = -((LONG)pBltInfo->Pitch);
|
|
return;
|
|
}
|
|
case D3DKMDT_VPPR_ROTATE270:
|
|
{
|
|
*pPixelPitch = pBltInfo->Pitch;
|
|
*pRowPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE);
|
|
return;
|
|
}
|
|
default:
|
|
{
|
|
BDD_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation);
|
|
*pPixelPitch = 0;
|
|
*pRowPitch = 0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
BYTE* GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect)
|
|
{
|
|
BYTE* pRet = NULL;
|
|
LONG OffLeft = pRect->left + pBltInfo->Offset.x;
|
|
LONG OffTop = pRect->top + pBltInfo->Offset.y;
|
|
LONG BytesPerPixel = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
|
|
switch (pBltInfo->Rotation)
|
|
{
|
|
case D3DKMDT_VPPR_IDENTITY:
|
|
{
|
|
pRet = ((BYTE*)pBltInfo->pBits +
|
|
OffTop * pBltInfo->Pitch +
|
|
OffLeft * BytesPerPixel);
|
|
break;
|
|
}
|
|
case D3DKMDT_VPPR_ROTATE90:
|
|
{
|
|
pRet = ((BYTE*)pBltInfo->pBits +
|
|
(pBltInfo->Height - 1 - OffLeft) * pBltInfo->Pitch +
|
|
OffTop * BytesPerPixel);
|
|
break;
|
|
}
|
|
case D3DKMDT_VPPR_ROTATE180:
|
|
{
|
|
pRet = ((BYTE*)pBltInfo->pBits +
|
|
(pBltInfo->Height - 1 - OffTop) * pBltInfo->Pitch +
|
|
(pBltInfo->Width - 1 - OffLeft) * BytesPerPixel);
|
|
break;
|
|
}
|
|
case D3DKMDT_VPPR_ROTATE270:
|
|
{
|
|
pRet = ((BYTE*)pBltInfo->pBits +
|
|
OffLeft * pBltInfo->Pitch +
|
|
(pBltInfo->Width - 1 - OffTop) * BytesPerPixel);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
BDD_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
/****************************Internal*Routine******************************\
|
|
* CopyBitsGeneric
|
|
*
|
|
*
|
|
* Blt function which can handle a rotated dst/src, offset rects in dst/src
|
|
* and bpp combinations of:
|
|
* dst | src
|
|
* 32 | 32 // For identity rotation this is much faster in CopyBits32_32
|
|
* 32 | 24
|
|
* 32 | 16
|
|
* 24 | 32
|
|
* 16 | 32
|
|
* 8 | 32
|
|
* 24 | 24 // untested
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID CopyBitsGeneric(
|
|
BLT_INFO* pDst,
|
|
CONST BLT_INFO* pSrc,
|
|
UINT NumRects,
|
|
_In_reads_(NumRects) CONST RECT *pRects)
|
|
{
|
|
LONG DstPixelPitch = 0;
|
|
LONG DstRowPitch = 0;
|
|
LONG SrcPixelPitch = 0;
|
|
LONG SrcRowPitch = 0;
|
|
|
|
GetPitches(pDst, &DstPixelPitch, &DstRowPitch);
|
|
GetPitches(pSrc, &SrcPixelPitch, &SrcRowPitch);
|
|
|
|
for (UINT iRect = 0; iRect < NumRects; iRect++)
|
|
{
|
|
CONST RECT* pRect = &pRects[iRect];
|
|
|
|
NT_ASSERT(pRect->right >= pRect->left);
|
|
NT_ASSERT(pRect->bottom >= pRect->top);
|
|
|
|
UINT NumPixels = pRect->right - pRect->left;
|
|
UINT NumRows = pRect->bottom - pRect->top;
|
|
|
|
BYTE* pDstRow = GetRowStart(pDst, pRect);
|
|
CONST BYTE* pSrcRow = GetRowStart(pSrc, pRect);
|
|
|
|
for (UINT y=0; y < NumRows; y++)
|
|
{
|
|
BYTE* pDstPixel = pDstRow;
|
|
CONST BYTE* pSrcPixel = pSrcRow;
|
|
|
|
for (UINT x=0; x < NumPixels; x++)
|
|
{
|
|
if ((pDst->BitsPerPel == 24) ||
|
|
(pSrc->BitsPerPel == 24))
|
|
{
|
|
pDstPixel[0] = pSrcPixel[0];
|
|
pDstPixel[1] = pSrcPixel[1];
|
|
pDstPixel[2] = pSrcPixel[2];
|
|
// pPixel[3] is the alpha channel and is ignored for whichever of Src/Dst is 32bpp
|
|
}
|
|
else if (pDst->BitsPerPel == 32)
|
|
{
|
|
if (pSrc->BitsPerPel == 32)
|
|
{
|
|
UINT32* pDstPixelAs32 = (UINT32*)pDstPixel;
|
|
UINT32* pSrcPixelAs32 = (UINT32*)pSrcPixel;
|
|
*pDstPixelAs32 = *pSrcPixelAs32;
|
|
}
|
|
else if (pSrc->BitsPerPel == 16)
|
|
{
|
|
UINT32* pDstPixelAs32 = (UINT32*)pDstPixel;
|
|
UINT16* pSrcPixelAs16 = (UINT16*)pSrcPixel;
|
|
|
|
*pDstPixelAs32 = CONVERT_16BPP_TO_32BPP(*pSrcPixelAs16);
|
|
}
|
|
else
|
|
{
|
|
// Invalid pSrc->BitsPerPel on a pDst->BitsPerPel of 32
|
|
NT_ASSERT(FALSE);
|
|
}
|
|
}
|
|
else if (pDst->BitsPerPel == 16)
|
|
{
|
|
NT_ASSERT(pSrc->BitsPerPel == 32);
|
|
|
|
UINT16* pDstPixelAs16 = (UINT16*)pDstPixel;
|
|
*pDstPixelAs16 = CONVERT_32BPP_TO_16BPP(pSrcPixel);
|
|
}
|
|
else if (pDst->BitsPerPel == 8)
|
|
{
|
|
NT_ASSERT(pSrc->BitsPerPel == 32);
|
|
|
|
*pDstPixel = CONVERT_32BPP_TO_8BPP(pSrcPixel);
|
|
}
|
|
else
|
|
{
|
|
// Invalid pDst->BitsPerPel
|
|
NT_ASSERT(FALSE);
|
|
}
|
|
pDstPixel += DstPixelPitch;
|
|
pSrcPixel += SrcPixelPitch;
|
|
}
|
|
|
|
pDstRow += DstRowPitch;
|
|
pSrcRow += SrcRowPitch;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************Internal*Routine******************************\
|
|
* BltBits
|
|
*
|
|
*
|
|
* Logic to decide which of the above functions to call based on Rotation/BPP
|
|
*
|
|
\**************************************************************************/
|
|
VOID BltBits(
|
|
BLT_INFO* pDst,
|
|
CONST BLT_INFO* pSrc,
|
|
UINT NumRects,
|
|
_In_reads_(NumRects) CONST RECT *pRects)
|
|
{
|
|
// pSrc->pBits might be coming from user-mode. User-mode addresses when accessed by kernel need to be protected by a __try/__except.
|
|
// This usage is redundant in the sample driver since it is already being used for MmProbeAndLockPages. However, it is very important
|
|
// to have this in place and to make sure developers don't miss it, it is in these two locations.
|
|
__try
|
|
{
|
|
if (pDst->BitsPerPel == 32 &&
|
|
pSrc->BitsPerPel == 32 &&
|
|
pDst->Rotation == D3DKMDT_VPPR_IDENTITY &&
|
|
pSrc->Rotation == D3DKMDT_VPPR_IDENTITY)
|
|
{
|
|
// This is by far the most common copy function being called
|
|
CopyBits32_32(pDst, pSrc, NumRects, pRects);
|
|
}
|
|
else
|
|
{
|
|
CopyBitsGeneric(pDst, pSrc, NumRects, pRects);
|
|
}
|
|
}
|
|
#pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
BDD_LOG_ERROR2("Either dst (0x%I64x) or src (0x%I64x) bits encountered exception during access.", pDst->pBits, pSrc->pBits);
|
|
}
|
|
}
|
|
|
|
// END: Non-Paged Code
|
|
#pragma code_seg(pop)
|
|
|