BOOL APIENTRY VBoxDispDrvRealizeBrush(BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask, XLATEOBJ *pxlo, ULONG iHatch) { BOOL bRc = FALSE; LOGF_ENTER(); if (VBoxDispIsScreenSurface(psoTarget)) { PVBOXDISPDEV pDev = (PVBOXDISPDEV)psoTarget->dhpdev; if (pDev->vbvaCtx.pVBVA && (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED)) { if (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET) { vrdpReset(pDev); pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents &= ~VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET; } if (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_VRDP) { bRc = vrdpDrvRealizeBrush(pbo, psoTarget, psoPattern, psoMask, pxlo, iHatch); } } } LOGF_LEAVE(); return bRc; }
void vrdpDrvBitBlt(SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4) { PVBOXDISPDEV pDev = (PVBOXDISPDEV)psoTrg->dhpdev; /* * BitBlt operation is supported by following RDP orders: * RDP_ORDER_DESTBLT ROP on the screen bits (BLACKNESS, WHITENESS, DSTINVERT). * RDP_ORDER_PATBLT ROP with screen bits and a brush. * RDP_ORDER_SCREENBLT Screen to screen with ROP. * RDP_ORDER_RECT Solid fill (SRCCOPY). * RDP_ORDER_MEMBLT ROP with screen and cached offscreen bitmap. * RDP_ORDER_TRIBLT ROP with screen, cached offscreen bitmap and a brush. * * Actual BitBlts must be mapped to these RDP operations. * Anything that can not be mapped must be emulated with dirty rect. * */ VRDPCLIPRECTS clipRects; int clipResult; RECTL rclTrg = *prclTrg; vrdpOrderRect (&rclTrg); LOGF_ENTER(); clipResult = vrdpGetIntersectingClipRects(&clipRects, psoTrg, &rclTrg, pco, VBoxDispIsScreenSurface(psoSrc)? pptlSrc: NULL); if (clipResult == VRDP_CLIP_NO_INTERSECTION) { /* Do nothing. The Blt does not affect anything. */ WARN(("VRDP_CLIP_NO_INTERSECTION!!!")); dumpPCO (&rclTrg, pco); } else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS) { /* A very complex clip. Better to emulate it. */ WARN(("VRDP_CLIP_TOO_MANY_RECTS!!!")); dumpPCO (&rclTrg, pco); vrdpReportDirtyRects(pDev, &clipRects); } else if (ROP4_NEED_MASK (rop4)) { /* Operation with mask is not supported. */ WARN(("Operation with mask is not supported.")); vrdpReportDirtyRects(pDev, &clipRects); } else if (ROP3_NEED_BRUSH(rop4)) { LOG(("Operation requires brush.")); /* Operation requires brush. */ if (ROP3_NEED_SRC(rop4)) { /* @todo Three way blt. RDP_ORDER_TRIBLT. */ LOG(("TRIBLT pbo->iSolidColor = 0x%08X.", pbo->iSolidColor)); vrdpReportDirtyRects(pDev, &clipRects); } else { /* Only brush and destination. Check if the brush is solid. */ if (pbo->iSolidColor != 0xFFFFFFFF) { /* Solid brush. The iSolidColor is the target surface color. */ uint32_t rgb = vrdpColor2RGB(psoTrg, pbo->iSolidColor); /* Mix with solid brush. RDP_ORDER_PATBLT. Or RDP_ORDER_RECT for rop4 = 0xF0F0. */ LOG(("Solid PATBLT color = %08X, rgb %08X.", pbo->iSolidColor, rgb)); if (rop4 == 0xF0F0) { vrdpReportSolidRect(pDev, &rclTrg, &clipRects, rgb); } else { vrdpReportSolidBlt(pDev, &rclTrg, &clipRects, rgb, (uint8_t)rop4); } } else { /* Non solid brush. RDP_ORDER_PATBLT. */ LOG(("VRDP::vrdpBitBlt: PATBLT pbo->pvRbrush = %p.", pbo->pvRbrush)); /* Realize brush. */ if (!pbo->pvRbrush) { BRUSHOBJ_pvGetRbrush (pbo); } if (pbo->pvRbrush) { /* Brush has been realized. */ VRDPBRUSH *pBrush = (VRDPBRUSH *)pbo->pvRbrush; if (pBrush->fPattern) { vrdpReportPatBlt(pDev, &rclTrg, &clipRects, pBrush, pptlBrush, (uint8_t)rop4); } else { /* @todo BITMAPCACHE followed by MEMBLT? */ vrdpReportDirtyRects(pDev, &clipRects); } } else { /* Unsupported brush format. Fallback to dirty rects. */ vrdpReportDirtyRects(pDev, &clipRects); } } } } else { /* Operation does not require brush. */ if (ROP3_NEED_SRC(rop4)) { LOG(("MEMBLT or SCREENBLT.")); /* MEMBLT or SCREENBLT. */ if (VBoxDispIsScreenSurface(psoSrc)) { /* Screen to screen transfer. SCREENBLT. */ LOG(("SCREENBLT.")); vrdpReportScreenBlt(pDev, &rclTrg, &clipRects, pptlSrc, (uint8_t)rop4); } else { /* Offscreen bitmap to screen. MEMBLT. */ VRDPBCHASH hash; VRDPBCHASH hashDeleted; int cacheResult; LOG(("MEMBLT: bitmap %dx%d.", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy)); if ( pDev->bBitmapCacheDisabled || (psoSrc->fjBitmap & BMF_DONTCACHE) != 0 || psoSrc->iUniq == 0 /* Bitmaps with hdev == 0 seems to have different RGB layout for 16BPP modes. * Just do not cache these bitmaps and report the dirty display area instead. */ || ( psoSrc->hdev == 0 && !(psoSrc->iBitmapFormat == BMF_24BPP || psoSrc->iBitmapFormat == BMF_32BPP) ) /* Do not try to cache large bitmaps. The cache should be mostly used for icons, etc. * Computing a bitmap hash increases CPU load. Up to 384K pixels (~620x620) */ || psoSrc->sizlBitmap.cx * psoSrc->sizlBitmap.cy > 384 * _1K ) { LOG(("MEMBLT: non cacheable bitmap.")); cacheResult = VRDPBMP_RC_NOT_CACHED; } else { LOG(("MEMBLT: going to cache.")); cacheResult = vrdpbmpCacheSurface(&pDev->vrdpCache, psoSrc, &hash, &hashDeleted, FALSE); } LOG(("MEMBLT: cacheResult 0x%08X", cacheResult)); if (cacheResult & VRDPBMP_RC_F_DELETED) { LOG(("VRDPBMP_RC_F_DELETED")); vrdpReportDeletedBitmap(pDev, &hashDeleted); cacheResult &= ~VRDPBMP_RC_F_DELETED; } switch (cacheResult) { case VRDPBMP_RC_CACHED: vrdpReportCachedBitmap(pDev, psoSrc, &hash); LOG(("MEMBLT: cached add %dx%d", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy)); /* Continue and report MEMBLT order. */ case VRDPBMP_RC_ALREADY_CACHED: vrdpReportMemBlt(pDev, &clipRects, pptlSrc, (uint8_t)rop4, &hash); LOG(("MEMBLT: cached use %dx%d from %d,%d %dx%d", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy, pptlSrc->x, pptlSrc->y, rclTrg.right - rclTrg.left, rclTrg.bottom - rclTrg.top)); LOG((" %08X %08X %08X %08X", *(uint32_t *)&((uint8_t *)&hash)[0], *(uint32_t *)&((uint8_t *)&hash)[4], *(uint32_t *)&((uint8_t *)&hash)[8], *(uint32_t *)&((uint8_t *)&hash)[12] )); break; default: /* The surface was not cached. Fallback to dirty rects. */ LOG(("MEMBLT: not cached %dx%d from %d,%d %dx%d", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy, pptlSrc->x, pptlSrc->y, rclTrg.right - rclTrg.left, rclTrg.bottom - rclTrg.top)); VBoxDispDumpPSO(psoSrc, "psoSrc"); vrdpReportDirtyRects(pDev, &clipRects); } } } else { /* No source and no brush, only dest affected. DESTBLT. */ LOG(("DSTBLT with rop 0x%08X", rop4)); vrdpReportDstBlt(pDev, &rclTrg, &clipRects, (uint8_t)rop4); } } }
BOOL APIENTRY VBoxDispDrvCopyBits(SURFOBJ *psoDest, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDest, POINTL *pptlSrc) { BOOL bRc; RECTL rclDest = *prclDest; POINTL ptlSrc = *pptlSrc; BOOL bDo = TRUE; LOGF_ENTER(); STATDRVENTRY(CopyBits, psoDest); LOG(("psoDest = %p, psoSrc = %p, pco = %p, pxlo = %p, prclDest = %p, pptlSrc = %p", psoDest, psoSrc, pco, pxlo, prclDest, pptlSrc)); DUMPSURF(psoSrc, "psoSrc"); DUMPSURF(psoDest, "psoDest"); STATPRINT; #ifdef VBOX_VBVA_ADJUST_RECT /* Experimental fix for too large bitmap updates. * * Some application do a large bitmap update event if only * a small part of the bitmap is actually changed. * * The driver will find the changed rectangle by comparing * the current framebuffer content with the source bitmap. * * The optimization is only active when: * - the VBVA extension is enabled; * - the source bitmap is not cacheable; * - the bitmap formats of both the source and the screen surfaces are equal. * */ if ( psoSrc && !VBoxDispIsScreenSurface(psoSrc) && VBoxDispIsScreenSurface(psoDest)) { PVBOXDISPDEV pDev = ((PVBOXDISPDEV))psoDest->dhpdev; LOG(("offscreen->screen")); if ( pDev->vbvaCtx.pVBVA && (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED)) { if ( (psoSrc->fjBitmap & BMF_DONTCACHE) != 0 || psoSrc->iUniq == 0) { LOG(("non-cacheable %d->%d (pDev %p)", psoSrc->iBitmapFormat, psoDest->iBitmapFormat, pDev)); /* It is possible to apply the fix. */ bDo = vbvaFindChangedRect(getSurfObj(psoDest), getSurfObj(psoSrc), &rclDest, &ptlSrc); } } } if (!bDo) { /* The operation is a NOP. Just return success. */ LOGF_LEAVE(); return TRUE; } #endif /* VBOX_VBVA_ADJUST_RECT */ bRc = EngCopyBits(getSurfObj(psoDest), getSurfObj(psoSrc), pco, pxlo, &rclDest, &ptlSrc); VBVA_OPERATION(psoDest, CopyBits, (psoDest, psoSrc, pco, pxlo, &rclDest, &ptlSrc)); LOGF_LEAVE(); return bRc; }