Sample Code

Windows Driver Samples/ Kernel mode display-only miniport driver (KMDOD) sample/ C++/ bltfuncs.cxx/

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

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS