VBoxDispVRDP.cpp revision b43f00592f321690997ff22fcb243059b0440091
/* $Id$ */
/** @file
* VBox XPDM Display driver
*/
/*
* Copyright (C) 2011-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "VBoxDisp.h"
/* vrdpGetIntersectingClipRects result */
#define VRDP_CLIP_OK 0
#define VRDP_CLIP_NO_INTERSECTION 1
#define VRDP_CLIP_TOO_MANY_RECTS 2
typedef struct _VRDPBRUSH
{
union {
struct {
} pat;
struct {
uint16_t w;
uint16_t h;
/* Here bits continue. */
} bitmap;
} u;
} VRDPBRUSH;
#if 1
#define dumpPCO(a, b) do {} while (0)
#else
{
LOG(("pco = %p Trg = %d-%d %d-%d", pco, prclTrg->left, prclTrg->right, prclTrg->top, prclTrg->bottom));
if (pco)
{
int cRects = 0;
LOG(("pco = %d %d-%d %d-%d dc %d fc %d mode %d opt %d",
do
{
{
cRects++;
}
} while (bMore);
}
}
#endif
{
switch (pso->iBitmapFormat)
{
case BMF_16BPP:
{
} break;
case BMF_24BPP:
case BMF_32BPP:
{
} break;
default:
}
return rgb;
}
{
}
{
pPoints->c++;
}
{
/* Bounds have inclusive pt1 and exclusive pt2. */
{
}
{
}
{
}
{
}
}
{
int tmp;
{
WARN(("Inverse X coordinates"));
}
{
WARN(("Inverse Y coordinates"));
}
}
{
}
{
/* Calculations are easier with left, right, top, bottom. */
/* Initialize result to empty record. */
if (xLeftResult < xRightResult)
{
/* There is intersection by X. */
if (yTopResult < yBottomResult)
{
/* There is intersection by Y. */
}
}
return;
}
{
int x;
int y;
int w;
int h;
LOGF(("%d-%d %d-%d on %dx%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom, pso->sizlBitmap.cx, pso->sizlBitmap.cy));
{
}
else
{
WARN(("Inverse X coordinates"));
}
{
}
else
{
WARN(("Inverse Y coordinates"));
}
Assert(w >= 0 && h >= 0);
/* Correct negative x and y coordinates. */
if (x < 0)
{
x += w; /* Compute xRight which is also the new width. */
w = (x < 0)? 0: x;
x = 0;
}
if (y < 0)
{
y += h; /* Compute xBottom, which is also the new height. */
h = (y < 0)? 0: y;
y = 0;
}
/* Also check if coords are greater than the display resolution. */
{
}
{
}
}
static int vrdpGetIntersectingClipRects(VRDPCLIPRECTS *pClipRects, SURFOBJ *pso, RECTL *prcl, CLIPOBJ *pco, POINTL *pptlSrc)
{
pClipRects->rects.c = 0;
{
if (pptlSrc)
{
/* Operation is performed on the same (screen) surface and enumeration direction
* must take into account the position of source and target rectangles.
*/
{
{
}
else
{
}
}
else
{
{
}
else
{
}
}
}
/* Clip the target rect by entire clipping region. Obtain the effective target. */
/* Enumerate rectangles. Try to get all rectangles at once and if there is not
* enough space (too many rectangles) fail with the bTooManyRects condition.
*/
if (!bTooManyRects)
{
if (cRects > 0)
{
{
if (vrdpIsRectEmpty(prclClipDst))
{
pClipRects->rects.c--;
}
else
{
prclClipDst++;
}
}
}
if (pClipRects->rects.c == 0)
{
}
}
}
{
return VRDP_CLIP_NO_INTERSECTION;
}
if (bTooManyRects)
{
pClipRects->rects.c = 0;
return VRDP_CLIP_TOO_MANY_RECTS;
}
return VRDP_CLIP_OK;
}
{
}
{
}
{
if (prcl)
{
}
else if (pco)
{
}
}
{
/* Ignore rects, report entire area. */
}
{
}
static BOOL vrdpWriteBits (PVBOXDISPDEV pDev, uint8_t *pu8Bits, int lDelta, int32_t x, int32_t y, uint32_t cWidth, uint32_t cHeight, int bytesPerPixel)
{
if (bRc)
{
while (cHeight--)
{
if (!bRc)
{
break;
}
}
}
return bRc;
}
/*
* RDP orders reporting.
*/
{
if (bRc)
{
}
return bRc;
}
{
}
{
if (pRects)
{
/* Start from index 1, because the first rect was already reported. */
unsigned i = 1;
{
if (!bRc)
{
return bRc;
}
}
}
return bRc;
}
{
/* This is a Bitmap Update Fallback operation. It takes bits from VRAM
* and inserts them in the pipeline. These bits are not cached.
*/
{
return;
}
if (bytesPerPixel > 0)
{
if (bRc)
{
bRc = vrdpWriteBits(pDev, pu8Bits, lDelta, rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel);
}
}
if (!bRc)
{
WARN(("failed!!! %d,%d %dx%d, bpp = %d\n",
}
}
const VRDEORDERBOUNDS *pBounds)
{
)
{
/* There is intersection. */
return TRUE;
}
/* No intersection. */
return FALSE;
}
const VRDPCLIPRECTS *pClipRects,
const VRDEORDERBOUNDS *pBounds)
{
pRects->c = 0; /* Number of clipping rects. */
if (pClipRects->rects.c == 0)
{
/* There were no clipping for the order. Therefore do nothing
* here and just return that order must be reported without
* clipping (rc = TRUE, pRects->c = 0).
*/
/* Do nothing. */
}
else
{
/* Find which clipping rects intersect with the bounds. */
unsigned c = 0;
unsigned i = 0;
{
{
c++;
}
}
if (c == 0)
{
/* No of clip rects intersect with the bounds. */
}
else
{
pRects->c = c;
}
}
return fReportOrder;
}
const VRDPCLIPRECTS *pClipRects,
const void *pvOrder,
unsigned cbOrder,
unsigned code)
{
{
if (!bRc)
{
return bRc;
}
}
if (!bRc)
{
return bRc;
}
{
}
return bRc;
}
const VRDPCLIPRECTS *pClipRects,
const VRDEORDERBOUNDS *pBounds,
const void *pvOrder,
unsigned cbOrder,
unsigned code)
{
{
}
}
{
}
{
}
{
if (pptlBrush)
{
/* Make sure that the coords fit in a 8 bit value.
* Only 8x8 pixel brushes are supported, so last 3 bits
* is a [0..7] coordinate of the brush, because the brush
* repeats after each 8 pixels.
*/
}
}
{
}
{
}
int xSrc,
int ySrc,
const VRDPBCHASH *phash)
{
}
const VRDPBCHASH *phash)
{
if (pClipRects->rects.c == 0)
{
vrdpReportMemBltRect (pDev, &pClipRects->rclDst, pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash);
}
else
{
ULONG i;
for (i = 0; i < pClipRects->rects.c; i++)
{
vrdpReportMemBltRect (pDev, &pClipRects->rects.arcl[i], pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash);
}
}
}
const VRDPBCHASH *phash)
{
if (bRc)
{
}
}
const VRDPBCHASH *phash)
{
}
{
return;
}
/*
* VRDP driver functions.
*/
{
/*
* LineTo operation is supported by RDP_ORDER_LINE.
*/
int clipResult;
if (clipResult == VRDP_CLIP_NO_INTERSECTION)
{
/* Do nothing. The Blt does not affect anything. */
LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
}
else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
{
/* A very complex clip. Better to emulate it. */
LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
}
{
/* Not solid brushes are not supported. */
}
else
{
LOG(("LINE %d,%d to %d,%d mix %02X rgb %08X bounds %d-%d %d-%d cliprects %d.",
}
}
{
/*
* StrokePath operation is supported by RDP_ORDER_POLYGON/POLYLINE/ELLIPSE.
*/
int clipResult;
LOGF(("pso = %p, ppo = %p, pco = %p, pxo = %p, pbo = %p, pptlBrushOrg = %p, plineattrs = %p, mix = 0x%08X",
LOG(("ppo: bounds %x-%x, %x-%x, %d-%d %d-%d",
if (clipResult == VRDP_CLIP_NO_INTERSECTION)
{
/* Do nothing. The operation does not affect anything. */
LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
}
else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
{
/* A very complex clip. Better to emulate it. */
LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
}
{
/* Not solid brushes are not supported. */
}
{
{
}
else
{
WARN(("ELLIPSE not supported"));
}
}
{
unsigned i;
do {
{
/* Setup first point. Start a new order. */
LOG(("BEGINSUBPATH"));
pptfx++;
i = 1;
}
else
{
LOG(("Continue order"));
i = 0;
}
{
LOG(("pd: %2d: %x,%x %d,%d",
{
/* Flush the order and start a new order. */
LOG(("Report order, points overflow."));
vrdpReportOrderGenericBounds(pDev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
}
}
{
/* Encode the start point as the end point. */
LOG(("Report order, CLOSEFIGURE"));
{
}
}
{
/* Finish the order. */
LOG(("Report order, ENDSUBPATH"));
{
vrdpReportOrderGenericBounds(pDev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
}
}
} while (bMore);
}
else
{
/* Not supported. */
WARN(("not supported: ppo->fl = %08X, plineattrs->fl = %08X, plineattrs->pstyle = %08X",
}
return;
}
{
}
{
}
{
/*
* TextOut operation is supported by RDP_ORDER_TEXT2/FONTCACHE.
*/
int clipResult;
if (clipResult == VRDP_CLIP_NO_INTERSECTION)
{
/* Do nothing. The operation does not affect anything. */
LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
}
else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
{
/* A very complex clip. Better to emulate it. */
LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
}
)
{
/* Unknown/unsupported parameters. */
WARN(("unsupported: pstro->pwszOrg=%p, prclExtra=%p, pfo->flFontType & FO_TYPE_RASTER = 0x%08X, "
"pstro->cGlyphs = %d, pboOpaque->iSolidColor %p, pfo->iUniq = %p",
}
else
{
#if 0
/* Testing: report a red rectangle for the text area. */
#else
/* Try to report the text order. */
{
}
#endif
}
return;
}
{
switch (iMode)
{
case SS_SAVE:
{
} break;
case SS_RESTORE:
{
{
uint32_t w;
uint32_t h;
int cbPixel;
}
} break;
default:
}
}
/* Whether the ROP4 operation requires MASK. */
/* Whether the ROP3 (lower byte of rop4) operation requires BRUSH. */
/* Whether the ROP3 (lower byte of rop4) operation requires SOURCE. */
/* Whether the ROP3 (lower byte of rop4) operation requires DESTINATION. */
void vrdpDrvBitBlt(SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
{
/*
* 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.
*
*/
int clipResult;
vrdpOrderRect (&rclTrg);
LOGF_ENTER();
if (clipResult == VRDP_CLIP_NO_INTERSECTION)
{
/* Do nothing. The Blt does not affect anything. */
WARN(("VRDP_CLIP_NO_INTERSECTION!!!"));
}
else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
{
/* A very complex clip. Better to emulate it. */
WARN(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
}
else if (ROP4_NEED_MASK (rop4))
{
/* Operation with mask is not supported. */
WARN(("Operation with mask is not supported."));
}
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. */
}
else
{
/* Only brush and destination. Check if the brush is solid. */
{
/* Solid brush. The iSolidColor is the target surface color. */
/* Mix with solid brush. RDP_ORDER_PATBLT. Or RDP_ORDER_RECT for rop4 = 0xF0F0. */
if (rop4 == 0xF0F0)
{
}
else
{
}
}
else
{
/* Non solid brush. RDP_ORDER_PATBLT. */
/* Realize brush. */
{
}
{
/* Brush has been realized. */
{
}
else
{
/* @todo BITMAPCACHE followed by MEMBLT? */
}
}
else
{
/* Unsupported brush format. Fallback to dirty rects. */
}
}
}
}
else
{
/* Operation does not require brush. */
if (ROP3_NEED_SRC(rop4))
{
LOG(("MEMBLT or SCREENBLT."));
/* MEMBLT or SCREENBLT. */
{
/* Screen to screen transfer. SCREENBLT. */
LOG(("SCREENBLT."));
}
else
{
/* Offscreen bitmap to screen. MEMBLT. */
int cacheResult;
/* 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.
*/
)
/* 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)
*/
)
{
LOG(("MEMBLT: non cacheable bitmap."));
}
else
{
LOG(("MEMBLT: going to cache."));
}
if (cacheResult & VRDPBMP_RC_F_DELETED)
{
LOG(("VRDPBMP_RC_F_DELETED"));
}
switch (cacheResult)
{
case VRDPBMP_RC_CACHED:
LOG(("MEMBLT: cached add %dx%d",
/* Continue and report MEMBLT order. */
LOG(("MEMBLT: cached use %dx%d from %d,%d %dx%d",
LOG((" %08X %08X %08X %08X",
));
break;
default:
/* The surface was not cached. Fallback to dirty rects. */
LOG(("MEMBLT: not cached %dx%d from %d,%d %dx%d",
}
}
}
else
{
/* No source and no brush, only dest affected. DESTBLT. */
}
}
}
void vrdpDrvStretchBlt(SURFOBJ *psoDest, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
{
}
void vrdpDrvCopyBits(SURFOBJ *psoDest, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDest, POINTL *pptlSrc)
{
/* The copy bits is the same as bit blt with particular set of parameters. */
}
{
if (psoPattern
)
{
if (pBrush)
{
int i;
for (i = 0; i < 8; i++)
{
}
/* Obtain RGB values for the brush fore and background colors:
* "should translate color zero through the XLATEOBJ to get the foreground color for the brush."
*/
}
}
#if 0
else if (psoPattern)
{
/* Color brushes and brushes >8x8 are cached and MEMBLT order generated. */
??? target
if (pBrush)
{
/* Byte per pattern pixel. */
/* Source bits scanline pointer. */
/* Target RGB pixel pointer. */
int y;
{
int x;
{
if (pxlo)
{
}
/* LOG(("%08X", pu32BitsDst[-1])); */
}
}
}
}
#endif /* 0 */
return bRc;
}