Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

629 lines
25 KiB

/****************************************************************************/
// nsdgint.cpp
//
// RDP Screen Data Grabber internal functions
//
// Copyright (C) 1996-2000 Microsoft Corporation
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "nsdgint"
#include <as_conf.hpp>
#include <nprcount.h>
/****************************************************************************/
/* Name: SDGSendSDARect */
/* */
/* Purpose: Attempts to send the given rectangle of Screen Data */
/* in one or more BitmapPDUs */
/* */
/* Returns: TRUE if whole rectangle sucessfully sent, FALSE otherwise. */
/* The supplied rectangle is always updated to remove the area */
/* that was successfully sent i.e. upon return the rectangle */
/* contains the area that was NOT sent. */
/* */
/* Params: IN: pFrameBuf - pointer to the Frame Buffer */
/* IN/OUT: pRect - pointer to rectangle to send. Updated to */
/* contain the rectangle that was not sent. */
/* IN: mustSend - set if the PDU must be sent (last rectangle) */
/* IN: pPkgInfo - PDU package to use */
/****************************************************************************/
BOOL RDPCALL SHCLASS SDGSendSDARect(
BYTE *pFrameBuf,
unsigned frameBufferWidth,
PRECTL pRect,
BOOL mustSend,
PPDU_PACKAGE_INFO pPkgInfo,
SDG_ENCODE_CONTEXT *pContext)
{
BOOL rc = FALSE;
int rectWidth;
int rectHeight;
int paddedWidthInPels;
// DC_HICOLOR
int paddedWidthInBytes;
unsigned padByte;
unsigned maxRowsLeft;
BYTE *pSrc;
BYTE *pPrevSrc;
unsigned uncompressedBitmapSize;
unsigned compressedBitmapSize = 0;
unsigned transferHeight;
unsigned pduSize;
unsigned compEst;
unsigned cbAdded;
unsigned compRowsLeft;
unsigned dataLeft;
unsigned buffSpaceLeft;
BOOL compRc;
// Macro to calculate remaining space in the BitmapPDU, allowing for
// any current rectangles.
#define SDG_SPACE_LEFT \
((pContext->pPackageSpace + pContext->BitmapPDUSize) - \
((BYTE *)pContext->pSDARect + \
FIELDOFFSET(TS_BITMAP_DATA, bitmapData[0])))
DC_BEGIN_FN("SDGSendSDARect");
TRC_NRM((TB, "SDA rect: (%d,%d)(%d,%d)", pRect->left, pRect->top,
pRect->right, pRect->bottom));
#ifdef DC_HICOLOR
// For simplicity on 4bpp, round left down to an even number.
if (m_pTSWd->desktopBpp == 4)
pRect->left &= (~0x1);
// Get the rectangle width and height, remembering that the supplied
// coords are inclusive.
rectWidth = pRect->right - pRect->left;
rectHeight = pRect->bottom - pRect->top;
// Pad rect width so that each row is dword aligned.
paddedWidthInPels = (rectWidth + 3) & (~0x03);
// Set up a pointer to the first byte to fetch from the Frame Buffer,
// alowing for the color depth.
if (m_pTSWd->desktopBpp == 24) {
pSrc = pFrameBuf + 3 * (pRect->top * frameBufferWidth + pRect->left);
paddedWidthInBytes = paddedWidthInPels * 3;
}
else if ((m_pTSWd->desktopBpp == 16) || (m_pTSWd->desktopBpp == 15)) {
pSrc = pFrameBuf + 2 * (pRect->top * frameBufferWidth + pRect->left);
paddedWidthInBytes = paddedWidthInPels * 2;
}
else if (m_pTSWd->desktopBpp == 8) {
pSrc = pFrameBuf + (pRect->top * frameBufferWidth) + pRect->left;
paddedWidthInBytes = paddedWidthInPels;
}
else {
pSrc = pFrameBuf +
(((pRect->top * frameBufferWidth) + pRect->left) >> 1);
paddedWidthInBytes = paddedWidthInPels;
}
#else
// Set up a pointer to the first byte to fetch from the Frame Buffer.
if (m_pTSWd->desktopBpp == 8) {
// Get the rectangle width and height, remembering that the
// supplied coords are exclusive.
rectWidth = pRect->right - pRect->left;
rectHeight = pRect->bottom - pRect->top;
pSrc = pFrameBuf + (pRect->top * frameBufferWidth) + pRect->left;
// DC_HICOLOR
paddedWidthInBytes = (rectWidth + 3) & (~0x03);
}
else {
// Get the rectangle width and height, remembering that the
// supplied coords are exclusive.
// For simplicity on 4bpp, round left down to an even number.
pRect->left &= (~0x1);
rectWidth = pRect->right - pRect->left;
rectHeight = pRect->bottom - pRect->top;
pSrc = pFrameBuf + (((pRect->top * frameBufferWidth) +
pRect->left) >> 1);
// DC_HICOLOR
paddedWidthInBytes = (rectWidth + 3) & (~0x03);
}
#endif
TRC_NRM((TB, "%dbpp: pSrc %p, bytes/row %d",
m_pTSWd->desktopBpp, pSrc, paddedWidthInBytes));
#ifndef DC_HICOLOR
// Pad rect width so that each row is dword aligned.
paddedWidthInPels = (rectWidth + 3) & (~0x03);
#endif
while ((rectHeight > 0) || mustSend) {
// Have we filled the current PDU? Yes, if:
// - there is no room for more data; or
// - the last rectangle has been completely added; or
// - multiple rects per PDU are not supported.
if ((pContext->pBitmapPDU != NULL) &&
((SDG_SPACE_LEFT < paddedWidthInBytes) ||
(rectHeight == 0)))
{
pduSize = (unsigned)((BYTE *)pContext->pSDARect -
pContext->pPackageSpace);
TRC_NRM((TB, "Send PDU size %u, numrects=%u", pduSize,
pContext->pBitmapPDU->numberRectangles));
// Add the PDU to the package.
SC_AddToPackage(pPkgInfo, pduSize, TRUE);
INC_INCOUNTER(IN_SND_SDA_PDUS);
// Just used up an entire PDU. Quit if the entire rectangle
// was consumed OR we are in the middle of accumulating a
// shadow buffer.
pContext->pPackageSpace = NULL;
pContext->pBitmapPDU = NULL;
pContext->pSDARect = NULL;
TRC_DBG((TB, "Reset pSDARect and pBitmapPDU"));
if ((rectHeight == 0) || m_pTSWd->shadowState) {
// There is no new data. Break out of while loop.
// mustSend must be set.
TRC_NRM((TB, "Finished processing rectangle"));
break;
}
}
// Set up a new PDU if required.
if (pContext->pBitmapPDU == NULL) {
// Find space needed for headers plus one TS_BITMAP_DATA hdr plus
// the size of the header, throttled by the large packing size.
dataLeft = rectHeight * paddedWidthInBytes + scUpdatePDUHeaderSpace +
(unsigned)FIELDOFFSET(TS_UPDATE_BITMAP_PDU_DATA,
rectangle[0]) +
(unsigned)FIELDOFFSET(TS_BITMAP_DATA, bitmapData[0]);
dataLeft = min(dataLeft, m_pShm->sch.LargePackingSize);
TRC_NRM((TB, "Getting PDU, min size %d", dataLeft));
pContext->pPackageSpace = SC_GetSpaceInPackage(pPkgInfo,
dataLeft);
if (pContext->pPackageSpace != NULL) {
// Set up the current PDU size. Throttle to the large
// packing size.
pContext->BitmapPDUSize = min(
(pPkgInfo->cbLen - pPkgInfo->cbInUse),
m_pShm->sch.LargePackingSize);
TRC_NRM((TB, "Got PDU size %d", pContext->BitmapPDUSize));
// Fill in PDU header.
if (scUseFastPathOutput) {
pContext->pPackageSpace[0] = TS_UPDATETYPE_BITMAP |
scCompressionUsedValue;
}
else {
((TS_UPDATE_BITMAP_PDU UNALIGNED *)
pContext->pPackageSpace)->shareDataHeader.pduType2 =
TS_PDUTYPE2_UPDATE;
}
pContext->pBitmapPDU = (TS_UPDATE_BITMAP_PDU_DATA UNALIGNED *)
(pContext->pPackageSpace + scUpdatePDUHeaderSpace);
pContext->pBitmapPDU->updateType = TS_UPDATETYPE_BITMAP;
pContext->pBitmapPDU->numberRectangles = 0;
// Set up a pointer to the rectangles.
pContext->pSDARect = &(pContext->pBitmapPDU->rectangle[0]);
}
else {
TRC_ALT((TB, "Failed to allocate buffer"));
DC_QUIT;
}
}
// Now copy as many lines as possible into the PDU. Code above
// means there must be room for a line.
TRC_ASSERT((paddedWidthInBytes > 0), (TB, "zero paddedRectWidth"));
maxRowsLeft = (unsigned)SDG_SPACE_LEFT / paddedWidthInBytes;
TRC_ASSERT((maxRowsLeft > 0),
(TB, "Internal error: no room for a row, space %u, width %u",
SDG_SPACE_LEFT, paddedWidthInBytes));
// This figure does not allow for the compression we are about to
// apply - lets revise it accordingly.
compRowsLeft = maxRowsLeft * SCH_UNCOMP_BYTES /
SCH_GetBACompressionEst();
transferHeight = min((unsigned)rectHeight, compRowsLeft);
uncompressedBitmapSize = transferHeight * paddedWidthInBytes;
// Check that this won't blow the compression algorithm.
if (uncompressedBitmapSize > MAX_UNCOMPRESSED_DATA_SIZE) {
TRC_NRM((TB, "Rect size %u too big to compress in one go",
uncompressedBitmapSize));
transferHeight = MAX_UNCOMPRESSED_DATA_SIZE / paddedWidthInBytes;
uncompressedBitmapSize = transferHeight * paddedWidthInBytes;
TRC_NRM((TB, "Reduced size to %u (%u rows)",
uncompressedBitmapSize, transferHeight));
}
// Fill in the common header fields for this rectangle.
// Convert the rect to inclusive for the wire protocol.
pContext->pBitmapPDU->numberRectangles++;
pContext->pSDARect->destLeft = (INT16)(pRect->left);
pContext->pSDARect->destRight = (INT16)(pRect->right - 1);
pContext->pSDARect->destTop = (INT16)(pRect->top);
pContext->pSDARect->width = (UINT16)paddedWidthInPels;
#ifdef DC_HICOLOR
pContext->pSDARect->bitsPerPixel = (UINT16)m_pTSWd->desktopBpp;
if (pContext->pSDARect->bitsPerPixel < 8) {
pContext->pSDARect->bitsPerPixel = 8;
}
#else
pContext->pSDARect->bitsPerPixel = 8;
#endif
// Set up the data in the transfer buffer.
pPrevSrc = pSrc;
SDGPrepareData(&pSrc, rectWidth, paddedWidthInBytes,
transferHeight, frameBufferWidth);
// The compression algorithm does not deal well with very small
// buffers.
if (transferHeight > 1 || paddedWidthInPels > 12) {
// Try to compress the bitmap directly into the network packet.
// First we try to compress with the data size based on how well
// we expect it to compress.
buffSpaceLeft = min((unsigned)SDG_SPACE_LEFT,
uncompressedBitmapSize);
#ifdef DC_HICOLOR
compRc = BC_CompressBitmap(
m_pShm->sdgTransferBuffer,
pContext->pSDARect->bitmapData,
NULL,
buffSpaceLeft,
&compressedBitmapSize,
paddedWidthInPels,
transferHeight,
m_pTSWd->desktopBpp);
#else
compRc = BC_CompressBitmap(m_pShm->sdgTransferBuffer,
pContext->pSDARect->bitmapData, buffSpaceLeft,
&compressedBitmapSize, paddedWidthInPels,
transferHeight);
#endif
if (compRc) {
// We have successfully compressed the bitmap data.
pContext->pSDARect->compressedFlag = TRUE;
// Indicates if this SDA data includes BC header or not.
pContext->pSDARect->compressedFlag |=
m_pShm->bc.noBitmapCompressionHdr;
TRC_NRM((TB, "1st pass compr of %u x %u, size %u -> %u",
transferHeight, paddedWidthInPels,
uncompressedBitmapSize, compressedBitmapSize));
goto COMPRESSION_DONE;
}
// Compression failed - may be because the data didn't compress
// quite as well as we thought it would and hence didn't fit into
// the buffer, so we'll try again.
// Copy as many lines as possible into the PDU. Code above means
// there must be room for a line.
TRC_NRM((TB, "Failed compress bitmap size %u (%u rows) - " \
"try smaller chunk", uncompressedBitmapSize,
transferHeight));
maxRowsLeft = (unsigned)SDG_SPACE_LEFT / paddedWidthInBytes;
TRC_ASSERT((maxRowsLeft > 0),
(TB, "No room for a row, space %u, width %u",
SDG_SPACE_LEFT, paddedWidthInBytes));
transferHeight = min((unsigned)rectHeight, maxRowsLeft);
uncompressedBitmapSize = transferHeight * paddedWidthInBytes;
TRC_DBG((TB, "Retry with %u rows", transferHeight));
// Set up the new data in the transfer buffer.
pSrc = pPrevSrc;
SDGPrepareData(&pSrc, rectWidth, paddedWidthInBytes,
transferHeight, frameBufferWidth);
// Try to compress the bitmap directly into the network packet.
buffSpaceLeft = min((unsigned)SDG_SPACE_LEFT,
uncompressedBitmapSize);
#ifdef DC_HICOLOR
compRc = BC_CompressBitmap(m_pShm->sdgTransferBuffer,
pContext->pSDARect->bitmapData, NULL, buffSpaceLeft,
&compressedBitmapSize, paddedWidthInPels,
transferHeight, m_pTSWd->desktopBpp);
#else
compRc = BC_CompressBitmap(m_pShm->sdgTransferBuffer,
pContext->pSDARect->bitmapData, buffSpaceLeft,
&compressedBitmapSize, paddedWidthInPels, transferHeight);
#endif
if (compRc) {
TRC_NRM((TB,
"2nd pass compr %u x %u, size %u -> %u",
transferHeight, paddedWidthInPels,
uncompressedBitmapSize, compressedBitmapSize));
pContext->pSDARect->compressedFlag = TRUE;
// Indicates if this SDA data includes BC header or not.
pContext->pSDARect->compressedFlag |=
m_pShm->bc.noBitmapCompressionHdr;
goto COMPRESSION_DONE;
}
// The compression really really failed so just copy the
// uncompressed data from the sdgTransferBuffer to the packet and
// send it uncompressed.
TRC_NRM((TB, "Really failed to compress bitmap size(%u)",
uncompressedBitmapSize));
TRC_NRM((TB, "Copy %u x %u, size %u",
transferHeight, paddedWidthInPels, uncompressedBitmapSize));
goto NoCompression;
}
else {
// Small buffer, no compression applied.
// So we just copy the uncompressed data from the sdgTransferBuffer
// to the packet and send it uncompressed.
TRC_NRM((TB, "first time copy of %u rows by %u columns, size %u",
transferHeight, paddedWidthInPels, uncompressedBitmapSize));
NoCompression:
pContext->pSDARect->compressedFlag = FALSE;
memcpy(pContext->pSDARect->bitmapData,
m_pShm->sdgTransferBuffer,
uncompressedBitmapSize);
// Init the compressed data size to the uncompressed size.
compressedBitmapSize = uncompressedBitmapSize;
}
COMPRESSION_DONE:
// Write the size of the data into the header. Be sure compressedSize
// has been set up, even if uncompressed.
pContext->pSDARect->bitmapLength = (UINT16)compressedBitmapSize;
// Now we know the height actually used, we can fill in the rest of
// the SDA header.
pContext->pSDARect->height = (UINT16)transferHeight;
pContext->pSDARect->destBottom =
(INT16)(pRect->top + (transferHeight - 1));
TRC_NRM((TB, "Add rect %d: (%d,%d)(%d,%d) %u(%u->%u bytes)",
pContext->pBitmapPDU->numberRectangles,
pContext->pSDARect->destLeft,
pContext->pSDARect->destTop,
pContext->pSDARect->destRight,
pContext->pSDARect->destBottom,
pContext->pSDARect->compressedFlag,
uncompressedBitmapSize,
compressedBitmapSize));
// Update the compression statistics.
sdgUncompTotal += uncompressedBitmapSize;
sdgCompTotal += compressedBitmapSize;
if (sdgUncompTotal >= SDG_SAMPLE_SIZE) {
// Compression estimate is average # of bytes that
// SCH_UNCOMP_BYTES bytes of uncomp data compress to.
compEst = SCH_UNCOMP_BYTES * sdgCompTotal / sdgUncompTotal;
TRC_ASSERT((compEst <= 1024),(TB,"Screen data compression "
"estimate out of range - %u", compEst));
sdgCompTotal = 0;
sdgUncompTotal = 0;
if (compEst < SCH_COMP_LIMIT)
compEst = SCH_COMP_LIMIT;
SCH_UpdateBACompressionEst(compEst);
TRC_NRM((TB, "New BA compression estimate %lu", compEst));
}
// Update variables to reflect the chunk of data we successfully sent.
rectHeight -= transferHeight;
pRect->top += transferHeight;
// Update the SDA pointer. Add the TS_BITMAP_DATA header plus the
// actual bitmap bits.
cbAdded = (unsigned)FIELDOFFSET(TS_BITMAP_DATA, bitmapData[0]) +
pContext->pSDARect->bitmapLength;
pContext->pSDARect = (TS_BITMAP_DATA UNALIGNED *)
((BYTE *)pContext->pSDARect + cbAdded);
TRC_DBG((TB, "pSDARect = %p", pContext->pSDARect));
} /* ... while (rectHeight > 0) */
// The entire rectangle was consumed if we managed to pack in all the rows.
// For shadowing, we want to indicate if more work is required to finish
rc = (rectHeight == 0);
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
// SDGPrepareData
//
// Copies a bitmap rectangle from the screen buffer to sdgTransferBuffer.
/****************************************************************************/
void RDPCALL SHCLASS SDGPrepareData(
BYTE **ppSrc,
int rectWidth,
int paddedRectWidth,
unsigned transferHeight,
unsigned frameBufferWidth)
{
PBYTE pDst;
PBYTE pEnd4, pDst4, pSrc4;
unsigned row;
unsigned numPadBytes;
unsigned lineWidth;
PBYTE pSrc = *ppSrc;
DC_BEGIN_FN("SDGPrepareData");
// We need to copy the data from the Frame Buffer into the
// sdgTransferBuffer so that each of the rectangle rows to be sent are
// contiguous in memory.
// However, we also need to flip the bitmap vertically to convert from
// the top-down format of the frame buffer to the bottom-up format of
// the PDU bitmap data. We therefore set pDst to point to the address
// of the beginning of the last row (in memory) of the bitmap within
// the Transfer Buffer and the code below moves it back through memory
// as we copy each row of source data.
#ifdef DC_HICOLOR
pDst = m_pShm->sdgTransferBuffer + paddedRectWidth * (transferHeight - 1);
if (m_pTSWd->desktopBpp == 8)
lineWidth = frameBufferWidth;
else if (m_pTSWd->desktopBpp == 24)
lineWidth = frameBufferWidth * 3;
else if ((m_pTSWd->desktopBpp == 16) || (m_pTSWd->desktopBpp == 15))
lineWidth = frameBufferWidth * 2;
else if (m_pTSWd->desktopBpp == 4)
lineWidth = frameBufferWidth / 2;
#else
pDst = m_pShm->sdgTransferBuffer + (paddedRectWidth * (transferHeight-1));
lineWidth = (m_pTSWd->desktopBpp == 4) ? (frameBufferWidth / 2)
: frameBufferWidth;
#endif
TRC_NRM((TB, "FB width %d, line width %d, Bpp %d",
frameBufferWidth, lineWidth, m_pTSWd->desktopBpp));
// Copy the data into the Transfer Buffer, reformatting it as we go.
if (m_pTSWd->desktopBpp == 8) {
for (row = 0; row < transferHeight; row++) {
memcpy(pDst, pSrc, rectWidth);
pSrc += lineWidth;
pDst -= paddedRectWidth;
}
}
#ifdef DC_HICOLOR
else if (m_pTSWd->desktopBpp == 24) {
TRC_NRM((TB, "Copy %d rows of %d pels, line w %d, prw %d",
transferHeight, rectWidth, lineWidth, paddedRectWidth));
for (row = 0; row < transferHeight; row++)
{
memcpy(pDst, pSrc, 3 * rectWidth);
pSrc += lineWidth;
pDst -= paddedRectWidth;
}
}
else if ((m_pTSWd->desktopBpp == 15) || (m_pTSWd->desktopBpp == 16)) {
TRC_NRM((TB, "Copy %d rows of %d pels, line w %d, prw %d",
transferHeight, rectWidth, lineWidth, paddedRectWidth));
for (row = 0; row < transferHeight; row++)
{
memcpy(pDst, pSrc, 2 * rectWidth);
pSrc += lineWidth;
pDst -= paddedRectWidth;
}
}
#endif
else {
for (row = 0; row < transferHeight; row++) {
pEnd4 = pDst + rectWidth;
for (pDst4 = pDst, pSrc4 = pSrc; pDst4 < pEnd4; pDst4++, pSrc4++) {
*pDst4 = (*pSrc4 >> 4) & 0xf;
pDst4++;
*pDst4 = *pSrc4 & 0xf;
}
pSrc += lineWidth;
pDst -= paddedRectWidth;
}
}
// Zero the pad bytes on the end of each row (this aids compression).
// Split each case out separately to aid performance (rather than the
// alternative of testing numPadBytes within every iteration of a for
// loop). Set pDst to the first pad byte in the first row.
#ifdef DC_HICOLOR
pDst = m_pShm->sdgTransferBuffer +
(rectWidth * ((m_pTSWd->desktopBpp + 7) / 8));
numPadBytes = (unsigned)(paddedRectWidth -
(rectWidth * ((m_pTSWd->desktopBpp + 7) / 8)));
#else
pDst = m_pShm->sdgTransferBuffer + rectWidth;
numPadBytes = (unsigned)(paddedRectWidth - rectWidth);
#endif
switch (numPadBytes) {
case 0:
// No padding required.
break;
case 1:
// 1 byte padding per row required.
for (row = 0; row < transferHeight; row++) {
*pDst = 0;
pDst += paddedRectWidth;
}
break;
case 2:
// 2 bytes padding per row required.
for (row = 0; row < transferHeight; row++) {
*((PUINT16_UA)pDst) = 0;
pDst += paddedRectWidth;
}
break;
case 3:
// 3 bytes padding per row required.
for (row = 0; row < transferHeight; row++) {
*((PUINT16_UA)pDst) = 0;
*(pDst + 2) = 0;
pDst += paddedRectWidth;
}
break;
#ifdef DC_HICOLOR
case 4:
// 4 bytes padding per row required.
for (row = 0; row < transferHeight; row++) {
*((PUINT32_UA)pDst) = 0;
pDst += paddedRectWidth;
}
break;
case 6:
// 6 bytes padding per row required.
for (row = 0; row < transferHeight; row++) {
*((PUINT32_UA)pDst) = 0;
*((PUINT16_UA)(pDst + 4)) = 0;
pDst += paddedRectWidth;
}
break;
case 9:
// 9 bytes padding per row required.
for (row = 0; row < transferHeight; row++) {
*((PUINT32_UA)pDst) = 0;
*((PUINT32_UA)(pDst+4)) = 0;
*(pDst + 8) = 0;
pDst += paddedRectWidth;
}
break;
#endif
default:
#ifdef DC_HICOLOR
TRC_ALT((TB, "Invalid numPadBytes %u, rect %u, p/rect %u",
numPadBytes, rectWidth, paddedRectWidth));
#else
TRC_ABORT((TB, "Invalid numPadBytes: %u", numPadBytes));
#endif
break;
}
// All done - update the supplied source pointer.
*ppSrc = pSrc;
DC_END_FN();
}