VirtualBox

Ignore:
Timestamp:
Nov 14, 2019 11:46:05 PM (5 years ago)
Author:
vboxsync
Message:

WDDM: exclude transparent pixels from the monochrome mouse pointers too; cleanups.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPWddm.cpp

    r81813 r81856  
    25382538}
    25392539
     2540/** Find which area of a 32 bit mouse pointer bitmap is actually used.
     2541 * Zero pixels on the right and the bottom of the bitmap are considered unused.
     2542 *
     2543 * @param pPixels               The bitmap.
     2544 * @param Pitch                 The bitmap scanline size in bytes.
     2545 * @param Width                 The bitmap width.
     2546 * @param Height                The bitmap height.
     2547 * @param piMaxFilledPixel      Where to store the maximum index of non-zero pixel within a scanline.
     2548 * @param piMaxFilledScanline   Where to store the zero based index of the last scanline with non-zero pixels.
     2549 */
     2550static void vboxWddmPointerFindDimensionsColor(void const *pPixels, UINT Pitch, UINT Width, UINT Height,
     2551                                               LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
     2552{
     2553    /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
     2554     * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
     2555     */
     2556    DWORD const *pdwScanline = (DWORD *)pPixels;
     2557    LONG iMaxFilledScanline = -1;
     2558    LONG iMaxFilledPixel = -1;
     2559    for (ULONG y = 0; y < Height; ++y)
     2560    {
     2561        LONG iLastFilledPixel = -1;
     2562        for (ULONG x = 0; x < Width; ++x)
     2563        {
     2564            if (pdwScanline[x])
     2565                iLastFilledPixel = x;
     2566        }
     2567
     2568        iMaxFilledPixel = RT_MAX(iMaxFilledPixel, iLastFilledPixel);
     2569
     2570        if (iLastFilledPixel >= 0)
     2571        {
     2572            /* Scanline contains non-zero pixels. */
     2573            iMaxFilledScanline = y;
     2574        }
     2575
     2576        pdwScanline = (DWORD *)((uint8_t *)pdwScanline + Pitch);
     2577    }
     2578
     2579    *piMaxFilledPixel = iMaxFilledPixel;
     2580    *piMaxFilledScanline = iMaxFilledScanline;
     2581}
     2582
     2583/** Find which area of a 1 bit AND/XOR mask bitmap is actually used, i.e. filled with actual data.
     2584 * For the AND mask the bytes with a value 0xff on the right and the bottom of the bitmap are considered unused.
     2585 * For the XOR mask the blank value is 0x00.
     2586 *
     2587 * @param pPixels             The 1bit bitmap.
     2588 * @param Pitch               The 1bit bitmap scanline size in bytes.
     2589 * @param Width               The bitmap width.
     2590 * @param Height              The bitmap height.
     2591 * @param Blank               The value of the unused bytes in the supplied bitmap.
     2592 * @param piMaxFilledPixel    Where to store the maximum index of a filled pixel within a scanline.
     2593 * @param piMaxFilledScanline Where to store the zero based index of the last scanline with filled pixels.
     2594 */
     2595static void vboxWddmPointerFindDimensionsMono(void const *pPixels, UINT Pitch, UINT Width, UINT Height, BYTE Blank,
     2596                                              LONG *piMaxFilledPixel, LONG *piMaxFilledScanline)
     2597{
     2598    /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
     2599     * Exclude the blank pixels (which are transparent anyway) from the right and the bottom of the bitmap.
     2600     */
     2601    BYTE const *pbScanline = (BYTE *)pPixels;
     2602    LONG iMaxFilledScanline = -1;
     2603    LONG iMaxFilledByte = -1;
     2604    for (ULONG y = 0; y < Height; ++y)
     2605    {
     2606        LONG iLastFilledByte = -1;
     2607        for (ULONG x = 0; x < Width / 8; ++x)
     2608        {
     2609            if (pbScanline[x] != Blank)
     2610                iLastFilledByte = x;
     2611        }
     2612
     2613        iMaxFilledByte = RT_MAX(iMaxFilledByte, iLastFilledByte);
     2614
     2615        if (iLastFilledByte >= 0)
     2616        {
     2617            /* Scanline contains filled pixels. */
     2618            iMaxFilledScanline = y;
     2619        }
     2620
     2621        pbScanline += Pitch;
     2622    }
     2623
     2624    *piMaxFilledPixel = iMaxFilledByte * 8;
     2625    *piMaxFilledScanline = iMaxFilledScanline;
     2626}
     2627
     2628/** Adjust the width and the height of the mouse pointer bitmap.
     2629 * See comments in the function for the adjustment criteria.
     2630 *
     2631 * @param iMaxX   The index of the rightmost pixel which we want to keep.
     2632 * @param iMaxY   The index of the bottom-most pixel which we want to keep.
     2633 * @param XHot    The mouse pointer hot spot.
     2634 * @param YHot    The mouse pointer hot spot.
     2635 * @param pWidth  Where to store the bitmap width.
     2636 * @param pHeight Where to store the bitmap height.
     2637 */
     2638static void vboxWddmPointerAdjustDimensions(LONG iMaxX, LONG iMaxY, UINT XHot, UINT YHot,
     2639                                            ULONG *pWidth, ULONG *pHeight)
     2640{
     2641    /* Both input parameters are zero based indexes, add 1 to get a width and a height. */
     2642    ULONG W = iMaxX + 1;
     2643    ULONG H = iMaxY + 1;
     2644
     2645    /* Always include the hotspot point. */
     2646    W = RT_MAX(XHot, W);
     2647    H = RT_MAX(YHot, H);
     2648
     2649    /* Align to 8 pixels, because the XOR/AND pointers are aligned like that.
     2650     * The AND mask has one bit per pixel with 8 bits per byte.
     2651     * In case the host can't deal with unaligned data.
     2652     */
     2653    W = RT_ALIGN_T(W, 8, ULONG);
     2654    H = RT_ALIGN_T(H, 8, ULONG);
     2655
     2656    /* Do not send bitmaps with zero dimensions. Actually make the min size 32x32. */
     2657    W = RT_MAX(32, W);
     2658    H = RT_MAX(32, H);
     2659
     2660    /* Make it square. Some hosts are known to require square pointers. */
     2661    W = RT_MAX(W, H);
     2662    H = W;
     2663
     2664    /* Do not exceed the supported size.
     2665     * Actually this should not be necessary because Windows never creates such pointers.
     2666     */
     2667    W = RT_MIN(W, VBOXWDDM_C_POINTER_MAX_WIDTH);
     2668    H = RT_MIN(H, VBOXWDDM_C_POINTER_MAX_HEIGHT);
     2669
     2670    *pWidth = W;
     2671    *pHeight = H;
     2672}
     2673
    25402674BOOL vboxWddmPointerCopyColorData(CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape, PVIDEO_POINTER_ATTRIBUTES pPointerAttributes)
    25412675{
     
    25482682     * Exclude zero pixels (which are transparent anyway) from the right and the bottom of the bitmap.
    25492683     */
    2550     DWORD *pdwScanline = (DWORD *)pSetPointerShape->pPixels;
    2551     LONG iLastNonZeroScanline = -1;
    2552     LONG iMaxNonZeroPixel = -1;
    2553     for (y = 0; y < pSetPointerShape->Height; ++y)
    2554     {
    2555         LONG iLastNonZeroPixel = -1;
    2556         for (x = 0; x < pSetPointerShape->Width; ++x)
    2557         {
    2558             if (pdwScanline[x])
    2559                 iLastNonZeroPixel = x;
    2560         }
    2561 
    2562         iMaxNonZeroPixel = RT_MAX(iMaxNonZeroPixel, iLastNonZeroPixel);
    2563 
    2564         if (iLastNonZeroPixel >= 0)
    2565         {
    2566             /* Scanline contains non-zero pixels. */
    2567             iLastNonZeroScanline = y;
    2568         }
    2569 
    2570         pdwScanline = (DWORD *)((uint8_t *)pdwScanline + pSetPointerShape->Pitch);
    2571     }
    2572 
    2573     /* Both variabled are zero based indexes, add 1 for width and height. */
    2574     srcMaskW = iMaxNonZeroPixel + 1;
    2575     srcMaskH = iLastNonZeroScanline + 1;
    2576 
    2577     /* Align to 4 pixels. Bitmap is 16 bytes aligned (in case the host can't deal with unaligned data). */
    2578     srcMaskW = RT_ALIGN_T(srcMaskW, 4, ULONG);
    2579     srcMaskH = RT_ALIGN_T(srcMaskH, 4, ULONG);
    2580 
    2581     /* Do not send bitmaps with zero dimensions. Actually make the min size 32x32. */
    2582     srcMaskW = RT_MAX(32, srcMaskW);
    2583     srcMaskH = RT_MAX(32, srcMaskH);
    2584 
    2585     /* Make it square. */
    2586     srcMaskW = RT_MAX(srcMaskW, srcMaskH);
    2587     srcMaskH = srcMaskW;
    2588 
    2589     /* truncate masks if we exceed supported size */
    2590     pPointerAttributes->Width = min(srcMaskW, VBOXWDDM_C_POINTER_MAX_WIDTH);
    2591     pPointerAttributes->Height = min(srcMaskH, VBOXWDDM_C_POINTER_MAX_HEIGHT);
     2684    LONG iMaxFilledPixel;
     2685    LONG iMaxFilledScanline;
     2686    vboxWddmPointerFindDimensionsColor(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
     2687                                       pSetPointerShape->Width, pSetPointerShape->Height,
     2688                                       &iMaxFilledPixel, &iMaxFilledScanline);
     2689
     2690    vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
     2691                                    pSetPointerShape->XHot, pSetPointerShape->YHot,
     2692                                    &srcMaskW, &srcMaskH);
     2693
     2694    pPointerAttributes->Width = srcMaskW;
     2695    pPointerAttributes->Height = srcMaskH;
    25922696    pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
    25932697
     
    26422746    BYTE *pSrc, *pDst, bit;
    26432747
    2644     srcMaskW = pSetPointerShape->Width;
    2645     srcMaskH = pSetPointerShape->Height;
    2646 
    2647     /* truncate masks if we exceed supported size */
    2648     pPointerAttributes->Width = min(srcMaskW, VBOXWDDM_C_POINTER_MAX_WIDTH);
    2649     pPointerAttributes->Height = min(srcMaskH, VBOXWDDM_C_POINTER_MAX_HEIGHT);
     2748    /* Windows always uses the maximum pointer size VBOXWDDM_C_POINTER_MAX_*
     2749     * Exclude unused pixels (which are transparent anyway) from the right and the bottom of the bitmap.
     2750     */
     2751    LONG iMaxFilledPixelAND;
     2752    LONG iMaxFilledScanlineAND;
     2753    vboxWddmPointerFindDimensionsMono(pSetPointerShape->pPixels, pSetPointerShape->Pitch,
     2754                                      pSetPointerShape->Width, pSetPointerShape->Height, 0xff,
     2755                                      &iMaxFilledPixelAND, &iMaxFilledScanlineAND);
     2756
     2757    LONG iMaxFilledPixelXOR;
     2758    LONG iMaxFilledScanlineXOR;
     2759    vboxWddmPointerFindDimensionsMono((BYTE *)pSetPointerShape->pPixels + pSetPointerShape->Height * pSetPointerShape->Pitch,
     2760                                      pSetPointerShape->Pitch,
     2761                                      pSetPointerShape->Width, pSetPointerShape->Height, 0x00,
     2762                                      &iMaxFilledPixelXOR, &iMaxFilledScanlineXOR);
     2763
     2764    LONG iMaxFilledPixel = RT_MAX(iMaxFilledPixelAND, iMaxFilledPixelXOR);
     2765    LONG iMaxFilledScanline = RT_MAX(iMaxFilledScanlineAND, iMaxFilledScanlineXOR);
     2766
     2767    vboxWddmPointerAdjustDimensions(iMaxFilledPixel, iMaxFilledScanline,
     2768                                    pSetPointerShape->XHot, pSetPointerShape->YHot,
     2769                                    &srcMaskW, &srcMaskH);
     2770
     2771    pPointerAttributes->Width = srcMaskW;
     2772    pPointerAttributes->Height = srcMaskH;
    26502773    pPointerAttributes->WidthInBytes = pPointerAttributes->Width * 4;
    26512774
     
    26612784
    26622785    /* convert XOR mask to RGB0 DIB, it start in pPointerAttributes->Pixels should be 4bytes aligned */
    2663     pSrc = (BYTE*)pSetPointerShape->pPixels + srcMaskH*pSetPointerShape->Pitch;
     2786    pSrc = (BYTE*)pSetPointerShape->pPixels + pSetPointerShape->Height*pSetPointerShape->Pitch;
    26642787    pDst = pPointerAttributes->Pixels + RT_ALIGN_T(dstBytesPerLine*pPointerAttributes->Height, 4, ULONG);
    26652788    dstBytesPerLine = pPointerAttributes->Width * 4;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette