VirtualBox

Changeset 45768 in vbox


Ignore:
Timestamp:
Apr 26, 2013 8:24:55 AM (12 years ago)
Author:
vboxsync
Message:

VBoxDisp: update for cached bitmap detection.

Location:
trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispVRDP.cpp

    r44529 r45768  
    66
    77/*
    8  * Copyright (C) 2011-2012 Oracle Corporation
     8 * Copyright (C) 2011-2013 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    14611461                int cacheResult;
    14621462
    1463                 LOG(("MEMBLT."));
     1463                LOG(("MEMBLT: bitmap %dx%d.", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
    14641464                if (   (psoSrc->fjBitmap & BMF_DONTCACHE) != 0
    14651465                    || psoSrc->iUniq == 0
     
    14701470                        && !(psoSrc->iBitmapFormat == BMF_24BPP || psoSrc->iBitmapFormat == BMF_32BPP)
    14711471                       )
     1472                       /* Do not try to cache large bitmaps. The cache should be mostly used for icons, etc.
     1473                        * Computing a bitmap hash increases CPU load. Up to 384K pixels (~620x620)
     1474                        */
     1475                    || psoSrc->sizlBitmap.cx * psoSrc->sizlBitmap.cy > 384 * _1K
    14721476                   )
    14731477                {
     
    14771481                else
    14781482                {
    1479                     LOG(("going to cache."));
    1480                     cacheResult = vrdpbmpCacheSurface(&pDev->vrdpCache, psoSrc, &hash, &hashDeleted);
    1481                 }
    1482 
    1483                 LOG(("MEMBLT: cacheResult 0x%08X. trg %d,%d %dx%d src %dx%d from %d,%d",
    1484                          cacheResult,
    1485                          rclTrg.left, rclTrg.top,
    1486                          rclTrg.right - rclTrg.left,
    1487                          rclTrg.bottom - rclTrg.top,
    1488                          psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
    1489                          pptlSrc->x, pptlSrc->y));
     1483                    LOG(("MEMBLT: going to cache."));
     1484                    cacheResult = vrdpbmpCacheSurface(&pDev->vrdpCache, psoSrc, &hash, &hashDeleted, FALSE);
     1485                }
     1486
     1487                LOG(("MEMBLT: cacheResult 0x%08X", cacheResult));
    14901488
    14911489                if (cacheResult & VRDPBMP_RC_F_DELETED)
     
    15001498                    case VRDPBMP_RC_CACHED:
    15011499                        vrdpReportCachedBitmap(pDev, psoSrc, &hash);
     1500                        LOG(("MEMBLT: cached add %dx%d",
     1501                             psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
    15021502                        /* Continue and report MEMBLT order. */
    15031503
    15041504                    case VRDPBMP_RC_ALREADY_CACHED:
    15051505                        vrdpReportMemBlt(pDev, &clipRects, pptlSrc, (uint8_t)rop4, &hash);
     1506                        LOG(("MEMBLT: cached use %dx%d from %d,%d %dx%d",
     1507                             psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
     1508                             pptlSrc->x, pptlSrc->y,
     1509                             rclTrg.right - rclTrg.left,
     1510                             rclTrg.bottom - rclTrg.top));
    15061511                        LOG(("        %08X %08X %08X %08X",
    15071512                                 *(uint32_t *)&((uint8_t *)&hash)[0],
     
    15141519                    default:
    15151520                        /* The surface was not cached. Fallback to dirty rects. */
    1516                         LOG(("MEMBLT: bitmap not cached."));
     1521                        LOG(("MEMBLT: not cached %dx%d from %d,%d %dx%d",
     1522                             psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
     1523                             pptlSrc->x, pptlSrc->y,
     1524                             rclTrg.right - rclTrg.left,
     1525                             rclTrg.bottom - rclTrg.top));
    15171526                        VBoxDispDumpPSO(psoSrc, "psoSrc");
    15181527                        vrdpReportDirtyRects(pDev, &clipRects);
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispVrdpBmp.cpp

    r36867 r45768  
    66
    77/*
    8  * Copyright (C) 2011 Oracle Corporation
     8 * Copyright (C) 2011-2013 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222
    2323/*
    24  * Cache has a fixed number of preallocated entries. Entries are linked in the MRU
    25  * list. The list contains both used and free entries. Free entries are at the end.
    26  * The most recently used entry is in the head.
     24 * Cache has a fixed number of preallocated entries. Entries are linked in the MRU lists.
     25 *
     26 * A new bitmap hash is added to the "temporary" list, and the caller is told that the
     27 * bitmap was not cached. If the hash is used again, then it is moved to the "cached" list.
     28 * This protects against "cache, memblt, cache, memblt, ..." sequences.
     29 *
     30 * "Temporary" list contains free and temporary entries. Temporary entries are at the head,
     31 * free entries are at the tail. New temporary entries are inserted in the head.
     32 *
     33 * "Cached" list contains cached entries. When a entry is used, it is moved to the head.
    2734 *
    2835 * The purpose of the cache is to answer whether the bitmap was already encountered
     
    7582}
    7683
    77 /* Meves an entry to the head of MRU list. */
    78 static void bcMoveToHead (VRDPBC *pCache, VRDPBCENTRY *pEntry)
     84static void bcRemoveFromCached(VRDPBC *pCache, VRDPBCENTRY *pEntry)
    7985{
    8086    if (pEntry->prev)
    8187    {
     88        pEntry->prev->next = pEntry->next;
     89    }
     90    else
     91    {
     92        pCache->headCached = pEntry->next;
     93    }
     94
     95    if (pEntry->next)
     96    {
     97        pEntry->next->prev = pEntry->prev;
     98    }
     99    else
     100    {
     101        pCache->tailCached = pEntry->prev;
     102    }
     103}
     104
     105static void bcRemoveFromTmp(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     106{
     107    if (pEntry->prev)
     108    {
     109        pEntry->prev->next = pEntry->next;
     110    }
     111    else
     112    {
     113        pCache->headTmp = pEntry->next;
     114    }
     115
     116    if (pEntry->next)
     117    {
     118        pEntry->next->prev = pEntry->prev;
     119    }
     120    else
     121    {
     122        pCache->tailTmp = pEntry->prev;
     123    }
     124}
     125
     126static void bcInsertHeadCached(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     127{
     128    pEntry->prev = NULL;
     129    pEntry->next = pCache->headCached;
     130
     131    if (pCache->headCached)
     132    {
     133        pCache->headCached->prev = pEntry;
     134    }
     135    else
     136    {
     137        pCache->tailCached = pEntry;
     138    }
     139
     140    pCache->headCached = pEntry;
     141}
     142
     143static void bcInsertHeadTmp(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     144{
     145    pEntry->prev = NULL;
     146    pEntry->next = pCache->headTmp;
     147
     148    if (pCache->headTmp)
     149    {
     150        pCache->headTmp->prev = pEntry;
     151    }
     152    else
     153    {
     154        pCache->tailTmp = pEntry;
     155    }
     156
     157    pCache->headTmp = pEntry;
     158}
     159
     160/* Moves an entry to the head of MRU list. */
     161static void bcMoveToHeadCached(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     162{
     163    if (pEntry->prev)
     164    {
    82165        /* The entry is not yet in the head. Exclude from list. */
    83         pEntry->prev->next = pEntry->next;
    84 
    85         if (pEntry->next)
    86         {
    87             pEntry->next->prev = pEntry->prev;
    88         }
    89         else
    90         {
    91             pCache->tail = pEntry->prev;
    92         }
     166        bcRemoveFromCached(pCache, pEntry);
    93167
    94168        /* Insert the entry at the head of MRU list. */
    95         pEntry->prev = NULL;
    96         pEntry->next = pCache->head;
    97 
    98         Assert(pCache->head);
    99 
    100         pCache->head->prev = pEntry;
    101         pCache->head = pEntry;
    102     }
    103 }
    104 
    105 /* Returns TRUE if the hash already presents in the cache.
    106  * Moves the found entry to the head of MRU list.
    107  */
    108 static BOOL bcFindHash (VRDPBC *pCache, const VRDPBCHASH *phash)
    109 {
    110     /* Search the MRU list. */
    111     VRDPBCENTRY *pEntry = pCache->head;
    112 
    113     while (pEntry && pEntry->fUsed)
     169        bcInsertHeadCached(pCache, pEntry);
     170    }
     171}
     172
     173static void bcMoveToHeadTmp(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     174{
     175    if (pEntry->prev)
     176    {
     177        /* The entry is not yet in the head. Exclude from list. */
     178        bcRemoveFromTmp(pCache, pEntry);
     179
     180        /* Insert the entry at the head of MRU list. */
     181        bcInsertHeadTmp(pCache, pEntry);
     182    }
     183}
     184
     185static void bcMoveTmpToCached(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     186{
     187    /* Remove from Tmp list. */
     188    bcRemoveFromTmp(pCache, pEntry);
     189
     190    /* Insert the entry at the head of Cached list. */
     191    bcInsertHeadCached(pCache, pEntry);
     192}
     193
     194static void bcMoveCachedToTmp(VRDPBC *pCache, VRDPBCENTRY *pEntry)
     195{
     196    /* Remove from cached list. */
     197    bcRemoveFromCached(pCache, pEntry);
     198
     199    /* Insert the entry at the head of Tmp list. */
     200    bcInsertHeadTmp(pCache, pEntry);
     201}
     202
     203
     204/* Returns pointer to the entry if the hash already presents in the cache.
     205 * Moves the found entry to the head of cached MRU list.
     206 */
     207static VRDPBCENTRY *bcFindHash (VRDPBC *pCache, const VRDPBCHASH *phash)
     208{
     209    /* Search the "Cached" MRU list. */
     210    VRDPBCENTRY *pEntry = pCache->headCached;
     211
     212    while (pEntry)
    114213    {
    115214        if (memcmp (&pEntry->hash, phash, sizeof (VRDPBCHASH)) == 0)
    116215        {
    117             /* Found the entry. Move it to the head of MRU list. */
    118             bcMoveToHead (pCache, pEntry);
    119 
    120             return TRUE;
     216            /* Found the entry. Move it to the head of Cached MRU list. */
     217            bcMoveToHeadCached(pCache, pEntry);
     218
     219            return pEntry;
    121220        }
    122221
     
    124223    }
    125224
    126     return FALSE;
    127 }
    128 
    129 /* Returns TRUE is a entry was also deleted to nake room for new entry. */
    130 static BOOL bcInsertHash (VRDPBC *pCache, const VRDPBCHASH *phash, VRDPBCHASH *phashDeleted)
    131 {
    132     BOOL bRc = FALSE;
    133     VRDPBCENTRY *pEntry;
    134 
    135     LOG(("insert hash cache %p, tail %p.", pCache, pCache->tail));
    136 
    137     /* Get the free entry to be used. Try tail, that should be */
    138     pEntry = pCache->tail;
    139 
    140     if (pEntry == NULL)
    141     {
    142         return bRc;
    143     }
    144 
    145     if (pEntry->fUsed)
    146     {
    147         /* The cache is full. Remove the tail. */
     225    /* Search the "Temporary" MRU list. */
     226    pEntry = pCache->headTmp;
     227
     228    while (   pEntry
     229           && pEntry->u32Status != VRDP_BC_ENTRY_STATUS_EMPTY)
     230    {
     231        if (memcmp (&pEntry->hash, phash, sizeof (VRDPBCHASH)) == 0)
     232        {
     233            /* Found the entry. It will be removed from the list by the caller. */
     234            return pEntry;
     235        }
     236
     237        pEntry = pEntry->next;
     238    }
     239
     240    return NULL;
     241}
     242
     243/* Returns TRUE is a entry was also deleted to make room for new entry. */
     244static int bcInsertHash (VRDPBC *pCache, const VRDPBCHASH *phash, VRDPBCHASH *phashDeleted, BOOL bForce)
     245{
     246    LOG(("bcInsertHash %p, tmp tail %p, cached tail %p.", pCache, pCache->tailTmp, pCache->tailCached));
     247
     248    /* Get the free entry to be used. Try Tmp list, then the tail of the Cached list. */
     249    VRDPBCENTRY *pEntry = pCache->tailTmp;
     250
     251    if (pEntry != NULL)
     252    {
     253        /* Insert to the head of Tmp list. */
     254        bcMoveToHeadTmp(pCache, pEntry);
     255        LOG(("bcInsertHash %p, use tmp tail %p.", pCache, pEntry));
     256    }
     257    else
     258    {
     259        pEntry = pCache->tailCached;
     260        LOG(("bcInsertHash %p, reuse cached tail %p.", pCache, pEntry, pEntry? pEntry->u32Status: 0));
     261
     262        if (pEntry != NULL)
     263        {
     264            bcMoveCachedToTmp(pCache, pEntry);
     265        }
     266    }
     267
     268    if (!pEntry)
     269    {
     270        LOG(("bcInsertHash %p, failed to find an entry!!!", pCache));
     271        return VRDPBMP_RC_NOT_CACHED;
     272    }
     273
     274    BOOL bHashDeleted;
     275    if (pEntry->u32Status == VRDP_BC_ENTRY_STATUS_CACHED)
     276    {
     277        /* The cache is full. Remove the tail hash. */
    148278        memcpy (phashDeleted, &pEntry->hash, sizeof (VRDPBCHASH));
    149         bRc = TRUE;
    150     }
    151 
    152     bcMoveToHead (pCache, pEntry);
    153 
     279        bHashDeleted = TRUE;
     280    }
     281    else
     282    {
     283        bHashDeleted = FALSE;
     284    }
     285
     286    /* The just inserted entry is at the head of Tmp list, so the temporary
     287     * entries will be deleted when there is no room in the cache.
     288     */
    154289    memcpy (&pEntry->hash, phash, sizeof (VRDPBCHASH));
    155     pEntry->fUsed = TRUE;
    156 
    157     return bRc;
     290
     291    int rc;
     292    if (bForce)
     293    {
     294        LOG(("Force cache"));
     295        bcMoveTmpToCached(pCache, pEntry);
     296        pEntry->u32Status = VRDP_BC_ENTRY_STATUS_CACHED;
     297        rc = VRDPBMP_RC_CACHED;
     298    }
     299    else
     300    {
     301        pEntry->u32Status = VRDP_BC_ENTRY_STATUS_TEMPORARY;
     302        rc = VRDPBMP_RC_NOT_CACHED;
     303    }
     304
     305    if (bHashDeleted)
     306    {
     307        rc |= VRDPBMP_RC_F_DELETED;
     308    }
     309
     310    return rc;
    158311}
    159312
    160313/* Find out whether the surface already in the cache.
    161314 * Insert in the cache if not.
    162  */
    163 int vrdpbmpCacheSurface(VRDPBC *pCache, const SURFOBJ *pso, VRDPBCHASH *phash, VRDPBCHASH *phashDeleted)
    164 {
    165     int rc;
    166 
     315 * Protection against "cache, memblt, cache, memblt, ..." sequence:
     316 *    first time just append the bitmap hash and mark it as "temporary";
     317 *    if the hash is used again, mark as cached and tell the caller to cache the bitmap;
     318 *    remove "temporary" entries before any other.
     319 *   
     320 */
     321int vrdpbmpCacheSurface(VRDPBC *pCache, const SURFOBJ *pso, VRDPBCHASH *phash, VRDPBCHASH *phashDeleted, BOOL bForce)
     322{
    167323    VRDPBCHASH hash;
    168324
    169325    BOOL bResult = bcComputeHash (pso, &hash);
    170 
    171326    LOG(("vrdpbmpCacheSurface: compute hash %d.", bResult));
     327
    172328    if (!bResult)
    173329    {
     
    176332    }
    177333
    178     bResult = bcFindHash (pCache, &hash);
    179 
    180     LOG(("vrdpbmpCacheSurface: find hash %d.", bResult));
    181334    *phash = hash;
    182335
    183     if (bResult)
    184     {
    185         return VRDPBMP_RC_ALREADY_CACHED;
    186     }
    187 
    188     rc = VRDPBMP_RC_CACHED;
    189 
    190     bResult = bcInsertHash (pCache, &hash, phashDeleted);
    191 
    192     LOG(("vrdpbmpCacheSurface: insert hash %d.", bResult));
    193     if (bResult)
    194     {
    195         rc |= VRDPBMP_RC_F_DELETED;
    196     }
     336    VRDPBCENTRY *pEntry = bcFindHash (pCache, &hash);
     337    LOG(("vrdpbmpCacheSurface: find hash %d.", pEntry? pEntry->u32Status: 0));
     338
     339    if (pEntry)
     340    {
     341        if (pEntry->u32Status == VRDP_BC_ENTRY_STATUS_CACHED)
     342        {
     343            return VRDPBMP_RC_ALREADY_CACHED;
     344        }
     345
     346        /* The status must be VRDP_BC_ENTRY_STATUS_TEMPORARY here.
     347         * Update it to *_CACHED.
     348         */
     349        if (pEntry->u32Status != VRDP_BC_ENTRY_STATUS_TEMPORARY)
     350        {
     351            LOG(("MEMBLT: vrdpbmpCacheSurface: unexpected status %d.", pEntry->u32Status));
     352            return VRDPBMP_RC_NOT_CACHED;
     353        }
     354
     355        bcMoveTmpToCached(pCache, pEntry);
     356
     357        pEntry->u32Status = VRDP_BC_ENTRY_STATUS_CACHED;
     358        return VRDPBMP_RC_CACHED;
     359    }
     360
     361    int rc = bcInsertHash (pCache, &hash, phashDeleted, bForce);
     362    LOG(("vrdpbmpCacheSurface: insert hash %x.", rc));
    197363
    198364    return rc;
     
    206372    Assert(sizeof (VRDPBCHASH) == sizeof (VRDEBITMAPHASH));
    207373
     374    LOG(("vrdpbmpReset: %p.", pCache));
     375
    208376    /* Reinitialize the cache structure. */
    209377    memset(pCache, 0, sizeof (VRDPBC));
    210378
    211     pCache->head = &pCache->aEntries[0];
    212     pCache->tail = &pCache->aEntries[RT_ELEMENTS(pCache->aEntries) - 1];
     379    pCache->headTmp = &pCache->aEntries[0];
     380    pCache->tailTmp = &pCache->aEntries[RT_ELEMENTS(pCache->aEntries) - 1];
    213381
    214382    for (i = 0; i < RT_ELEMENTS(pCache->aEntries); i++)
     
    216384        VRDPBCENTRY *pEntry = &pCache->aEntries[i];
    217385
    218         if (pEntry != pCache->tail)
     386        if (pEntry != pCache->tailTmp)
    219387        {
    220388            pEntry->next = &pCache->aEntries[i + 1];
    221389        }
    222390
    223         if (pEntry != pCache->head)
     391        if (pEntry != pCache->headTmp)
    224392        {
    225393            pEntry->prev = &pCache->aEntries[i - 1];
    226394        }
    227395    }
    228 }
     396
     397    pCache->headCached = NULL;
     398    pCache->tailCached = NULL;
     399}
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispVrdpBmp.h

    r36867 r45768  
    66
    77/*
    8  * Copyright (C) 2011 Oracle Corporation
     8 * Copyright (C) 2011-2013 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    5656#pragma pack ()
    5757
     58#define VRDP_BC_ENTRY_STATUS_EMPTY     0
     59#define VRDP_BC_ENTRY_STATUS_TEMPORARY 1
     60#define VRDP_BC_ENTRY_STATUS_CACHED    2
     61
    5862typedef struct _VRDPBCENTRY
    5963{
    60     bool fUsed;
    6164    struct _VRDPBCENTRY *next;
    6265    struct _VRDPBCENTRY *prev;
    6366    VRDPBCHASH hash;
     67    uint32_t u32Status;
    6468} VRDPBCENTRY;
    6569
    6670typedef struct _VRDPBC
    6771{
    68     VRDPBCENTRY *head;
    69     VRDPBCENTRY *tail;
     72    VRDPBCENTRY *headTmp;
     73    VRDPBCENTRY *tailTmp;
     74    VRDPBCENTRY *headCached;
     75    VRDPBCENTRY *tailCached;
    7076    VRDPBCENTRY aEntries[VRDPBMP_N_CACHED_BITMAPS];
    7177} VRDPBC;
    7278
    7379void vrdpbmpReset (VRDPBC *pCache);
    74 int vrdpbmpCacheSurface (VRDPBC *pCache, const SURFOBJ *pso, VRDPBCHASH *phash, VRDPBCHASH *phashDeleted);
     80int vrdpbmpCacheSurface (VRDPBC *pCache, const SURFOBJ *pso, VRDPBCHASH *phash, VRDPBCHASH *phashDeleted, BOOL bForce);
    7581
    7682#endif /*VBOXDISPVRDPBMP_H*/
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