|
|
#include "precomp.h"
//
// RBC.CPP
// Received Bitmap Cache
//
// Copyright(c) Microsoft 1997-
//
#define MLZ_FILE_ZONE ZONE_CORE
//
// RBC_ViewStarting()
//
// For 3.0 nodes, we create the cache each time they start hosting.
// For 2.x nodes, we create the cache once and use it until they leave the
// share.
//
BOOL ASShare::RBC_ViewStarting(ASPerson * pasPerson) { BOOL rc = FALSE;
DebugEntry(ASShare::RBC_ViewStarting);
ValidatePerson(pasPerson);
if (pasPerson->prbcHost != NULL) { ASSERT(pasPerson->cpcCaps.general.version < CAPS_VERSION_30);
TRACE_OUT(("RBC_ViewStarting: Reusing rbc cache for 2.x node [%d]", pasPerson->mcsID)); rc = TRUE; DC_QUIT; }
//
// Allocate the INCOMING cache data for this host.
//
pasPerson->prbcHost = new RBC_HOST_INFO; if (!pasPerson->prbcHost) { ERROR_OUT(( "Failed to get memory for prbcHost info")); DC_QUIT; } ZeroMemory(pasPerson->prbcHost, sizeof(*(pasPerson->prbcHost))); SET_STAMP(pasPerson->prbcHost, RBCHOST);
TRACE_OUT(( "Allocated RBC root for host [%d] at 0x%08x", pasPerson->mcsID, pasPerson->prbcHost));
//
// Create the bitmap caches for the sender
//
// SMALL
if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsSmallCacheNumEntries, pasPerson->cpcCaps.bitmaps.sender.capsSmallCacheCellSize, ID_SMALL_BMP_CACHE, &(pasPerson->prbcHost->bitmapCache[ID_SMALL_BMP_CACHE]))) { DC_QUIT; }
// MEDIUM
if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsMediumCacheNumEntries, pasPerson->cpcCaps.bitmaps.sender.capsMediumCacheCellSize, ID_MEDIUM_BMP_CACHE, &(pasPerson->prbcHost->bitmapCache[ID_MEDIUM_BMP_CACHE]))) { DC_QUIT; }
// LARGE
if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsLargeCacheNumEntries, pasPerson->cpcCaps.bitmaps.sender.capsLargeCacheCellSize, ID_LARGE_BMP_CACHE, &(pasPerson->prbcHost->bitmapCache[ID_LARGE_BMP_CACHE]))) { DC_QUIT; }
//
// The host can join the share.
//
rc = TRUE;
DC_EXIT_POINT: DebugExitBOOL(ASShare::RBC_ViewStarting, rc); return(rc); }
//
// RBC_ViewEnded()
//
void ASShare::RBC_ViewEnded(ASPerson * pasPerson) { DebugEntry(ASShare::RBC_ViewEnded);
ValidatePerson(pasPerson);
//
// For 3.0 NODES, we can free the cache; 3.0 senders clear theirs
// every time they host.
// For 2.x NODES, we must keep it around while they are in the share.
//
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30) { RBCFreeIncoming(pasPerson); } else { TRACE_OUT(("RBC_ViewEnded: Keeping rbc cache for 2.x node [%d]", pasPerson->mcsID)); }
DebugExitVOID(ASShare::RBC_ViewEnded); }
//
// RBC_PartyLeftShare()
// For 2.x nodes, frees the incoming RBC data
//
void ASShare::RBC_PartyLeftShare(ASPerson * pasPerson) { DebugEntry(ASShare::RBC_PartyLeftShare);
ValidatePerson(pasPerson);
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30) { // This should be gone!
ASSERT(pasPerson->prbcHost == NULL); } else { TRACE_OUT(("RBC_PartyLeftShare: Freeing rbc cache for 2.x node [%d]", pasPerson->mcsID)); RBCFreeIncoming(pasPerson); }
DebugExitVOID(ASShare::RBC_PartyLeftShare); }
//
// RBCFreeIncoming()
// Frees the party RBC incoming structures. This happens
// * For 3.0 nodes when they stop hosting
// * For 2.x nodes when leave the share
//
void ASShare::RBCFreeIncoming(ASPerson * pasPerson) { DebugEntry(ASShare::RBCFreeIncoming);
//
// Free this host's cache bitmaps.
//
if (pasPerson->prbcHost != NULL) { UINT i;
//
// Delete all of this host's cache bitmaps.
//
for (i = 0; i < NUM_BMP_CACHES; i++) { BMCFreeCacheData(&(pasPerson->prbcHost->bitmapCache[i])); }
delete pasPerson->prbcHost; pasPerson->prbcHost = NULL; }
DebugExitVOID(ASShare::RBCFreeIncoming); }
//
// RBC_ProcessCacheOrder(..)
//
void ASShare::RBC_ProcessCacheOrder ( ASPerson * pasPerson, LPCOM_ORDER_UA pOrder ) { PBMC_ORDER_HDR pBmcOrderHdr; PBMC_COLOR_TABLE_ORDER_UA pColorOrder; PBMC_BITMAP_BITS_ORDER_R2_UA pBitsOrderR2; BOOL fCompressed = FALSE; UINT cxFixedBitmapWidth; UINT iCacheEntry; LPBYTE pBitmapBits; UINT cbBitmapBits;
DebugEntry(ASShare::RBC_ProcessCacheOrder);
ValidatePerson(pasPerson);
//
// The rectangle is not included in the header for private order data
// (see SBC_CopyPrivateOrderData) so we must take this into account
// when working out the address of the order data.
//
pBmcOrderHdr = (PBMC_ORDER_HDR) (pOrder->abOrderData - sizeof(pOrder->OrderHeader.rcsDst));
switch (pBmcOrderHdr->bmcPacketType) { case BMC_PT_COLOR_TABLE: //
// This is a new color table. Simply cache the RGB values for
// use when we come to process a memblt order
// For backlevel calls the color table is always stored at
// index 0 because the index field in the order reuses a
// zero initialized "padding" field in the old structure.
//
TRACE_OUT(("Person [%d] Caching color table", pasPerson->mcsID)); pColorOrder = (PBMC_COLOR_TABLE_ORDER_UA)pBmcOrderHdr;
PM_CacheRxColorTable(pasPerson, pColorOrder->index, EXTRACT_TSHR_UINT16_UA(&(pColorOrder->colorTableSize)), (LPTSHR_RGBQUAD)&pColorOrder->data[0]); break;
case BMC_PT_BITMAP_BITS_COMPRESSED: fCompressed = TRUE; TRACE_OUT(( "Compressed BMP")); case BMC_PT_BITMAP_BITS_UNCOMPRESSED: //
// This is some cached bitmap data. We have to store it in the
// specified slot in the specified cache.
//
//
// The width of the bitmaps we use are actually fixed as
// multiples of 16 pels wide. Work out the width that
// corresponds to the sub-bitmap width of data we are caching.
//
pBitsOrderR2 = (PBMC_BITMAP_BITS_ORDER_R2_UA)pBmcOrderHdr;
cbBitmapBits = EXTRACT_TSHR_UINT16_UA( &(pBitsOrderR2->header.cbBitmapBits));
cxFixedBitmapWidth = ((pBitsOrderR2->header.cxSubBitmapWidth +15)/16)*16;
//
// The location of cache entry field depends on the R1/R2
// protocol
//
iCacheEntry = EXTRACT_TSHR_UINT16_UA(&(pBitsOrderR2->iCacheEntryR2)); pBitmapBits = pBitsOrderR2->data;
TRACE_OUT(("Person [%d] Rx bmp: id(%d) entry(%d) size(%dx%d) " \ "fixed(%d) bpp(%d) bytes(%d) compressed(%d)", pasPerson->mcsID, pBitsOrderR2->header.cacheID, iCacheEntry, pBitsOrderR2->header.cxSubBitmapWidth, pBitsOrderR2->header.cySubBitmapHeight, cxFixedBitmapWidth, pBitsOrderR2->header.bpp, cbBitmapBits, fCompressed));
//
// Pass the BMC data to the caching code. When calculating the
// pointer to the bitmap bits remember that we did not send the
// pBitmapBits field of the BMC_BITMAP_BITS_ORDER_Rx structure
// (see SBC_CopyPrivateOrderData).
//
RBCStoreBitsInCacheBitmap(pasPerson, pBitsOrderR2->header.cacheID, iCacheEntry, pBitsOrderR2->header.cxSubBitmapWidth, cxFixedBitmapWidth, pBitsOrderR2->header.cySubBitmapHeight, pBitsOrderR2->header.bpp, pBitmapBits, cbBitmapBits, fCompressed); break;
default: ERROR_OUT(( "[%u]Invalid packet type(%d)", pasPerson, (UINT)pBmcOrderHdr->bmcPacketType)); break; }
DebugExitVOID(ASShare::RBC_ProcessCacheOrder); }
//
// RBC_MapCacheIDToBitmapHandle(..)
//
HBITMAP ASShare::RBC_MapCacheIDToBitmapHandle ( ASPerson * pasPerson, UINT cache, UINT cacheEntry, UINT colorIndex ) { PBMC_DIB_CACHE pDIBCache; PBMC_DIB_ENTRY pDIBEntry; BITMAPINFO_ours bitmapInfo; UINT cColors; HBITMAP hWorkBitmap = NULL; HPALETTE hpalOldDIB = NULL; LPBYTE pBits; UINT cacheOffset;
DebugEntry(ASShare::RBC_MapCacheIDToBitmapHandle);
ValidateView(pasPerson);
//
// Check that the supplied cache ID is valid.
//
if (cache >= NUM_BMP_CACHES) { ERROR_OUT(( "[%u]Invalid cache ID (%d)", pasPerson, cache)); cache = 0; }
//
// Get a pointer to the bitmap data
//
// Note that there are two indexes floating around. From the host's
// perspective this index is a Cache Handler token and it must be
// translated in order to address the associated data. However we
// use it as the direct index into our receive cache and so the
// slots used on host and remote will be diferent.
//
// There is no reason why the slots should be the same. This is just
// to warn you that if you try correlating cache offsets between
// host and remote you will get confused as soon as the cache fills
// up and entries are reallocated in different positions.
//
//
pDIBCache = &(pasPerson->prbcHost->bitmapCache[cache]); TRACE_OUT(( "Local person [%d] cache id %d pointer %lx", pasPerson->mcsID, cache, pDIBCache)); cacheOffset = cacheEntry * pDIBCache->cSize; pDIBEntry = (PBMC_DIB_ENTRY)(pDIBCache->data + cacheOffset);
TRACE_OUT(( "Bits for index %u are at offset %ld, pointer 0x%08x", cacheEntry, (cacheEntry * pDIBCache->cSize), pDIBEntry));
//
// Set up the BitmapInfo structure.
//
USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&bitmapInfo, pDIBEntry->bpp); bitmapInfo.bmiHeader.biWidth = pDIBEntry->cxFixed; bitmapInfo.bmiHeader.biHeight = pDIBEntry->cy;
//
// Copy the Rx color table into the bitmap header.
//
if ( (pDIBEntry->bpp == 1) || (pDIBEntry->bpp == 4) || (pDIBEntry->bpp == 8) ) { cColors = COLORS_FOR_BPP(pDIBEntry->bpp);
PM_GetColorTable( pasPerson, colorIndex, &cColors, (LPTSHR_RGBQUAD)(&bitmapInfo.bmiColors) ); TRACE_OUT(( "Got %u colors from table",cColors)); bitmapInfo.bmiHeader.biClrUsed = cColors; } else if (pDIBEntry->bpp == 24) { ASSERT(colorIndex == COLORCACHEINDEX_NONE); } else { ERROR_OUT(("RBC: Unexpected bpp %d from [%d]", pDIBEntry->bpp, pasPerson->mcsID)); DC_QUIT; }
//
// Select which fixed width bitmap we are going to use to store the
// incoming DIB bits.
//
switch (pDIBEntry->cxFixed) { case 16: hWorkBitmap = m_usrBmp16; break;
case 32: hWorkBitmap = m_usrBmp32; break;
case 48: hWorkBitmap = m_usrBmp48; break;
case 64: hWorkBitmap = m_usrBmp64; break;
case 80: hWorkBitmap = m_usrBmp80; break;
case 96: hWorkBitmap = m_usrBmp96; break;
case 112: hWorkBitmap = m_usrBmp112; break;
case 128: hWorkBitmap = m_usrBmp128; break;
case 256: hWorkBitmap = m_usrBmp256; break;
default: ERROR_OUT(("RBC_MapCacheIDToBitmapHandle: invalid size from [%d]", pDIBEntry->cxFixed, pasPerson->mcsID)); hWorkBitmap = m_usrBmp256; break; }
ASSERT(hWorkBitmap != NULL);
//
// If the cached bitmap bits are compressed, we first have to
// decompress them.
//
if (pDIBEntry->bCompressed) { ASSERT(pDIBEntry->bpp <= 8);
//
// Use the decompression buffer to decompress the bitmap data.
//
if (!BD_DecompressBitmap(pDIBEntry->bits, m_usrPBitmapBuffer, pDIBEntry->cCompressed, pDIBEntry->cxFixed, pDIBEntry->cy, pDIBEntry->bpp)) { ERROR_OUT(( "Failed to decompress bitmap pBits(%lx)" " pBuf(%lx) cb(%x) cx(%d) cy(%d) bpp(%d)", pDIBEntry->bits, m_usrPBitmapBuffer, pDIBEntry->cCompressed, pDIBEntry->cxFixed, pDIBEntry->cy, pDIBEntry->bpp)); DC_QUIT; }
pBits = m_usrPBitmapBuffer; } else { //
// For uncompressed data just use direct from the cache
//
TRACE_OUT(( "Bitmap bits are uncompressed")); pBits = pDIBEntry->bits; }
//
// Set the bits into the bitmap we are about to return to the caller
//
hpalOldDIB = SelectPalette(pasPerson->m_pView->m_usrWorkDC, pasPerson->pmPalette, FALSE); RealizePalette(pasPerson->m_pView->m_usrWorkDC);
if (!SetDIBits(pasPerson->m_pView->m_usrWorkDC, hWorkBitmap, 0, pDIBEntry->cy, pBits, (BITMAPINFO *)&bitmapInfo, DIB_RGB_COLORS)) { ERROR_OUT(("SetDIBits failed in RBC_MapCacheIDToBitmapHandle")); }
SelectPalette(pasPerson->m_pView->m_usrWorkDC, hpalOldDIB, FALSE );
TRACE_OUT(( "Returning bitmap for person [%d] cache %u index %u color %u", pasPerson->mcsID, cache, cacheEntry, colorIndex));
DC_EXIT_POINT: DebugExitVOID(ASShare::RBC_MapCacheIDToBitmapHandle); return(hWorkBitmap); }
//
// FUNCTION: RBCStoreBitsInCacheBitmap(..)
//
// DESCRIPTION:
//
// Stores received bitmap bits into one of the receiver's cache bitmaps.
//
// PARAMETERS:
//
// pasPerson - pasPerson of host the bits came from.
//
// cache - the id of the cache bitmap to store the bits in.
//
// iCacheEntry - the cache entry number (index).
//
// cxSubBitmapWidth - the width in pels of the actual sub-bitmap (ie.
// excluding padding)
//
// cxFixedWidth - the fixed width in pels of the supplied bits (ie.
// including padding)
//
// cySubBitmapHeight - the height in pels of the sub-bitmap.
//
// pBitmapBits - a pointer to the actual bitmap bits. These may or may
// not be compressed (determined by the value of the fCompressed
// flag).
//
// cbBitmapBits - the size of the bitmap bits pointed to by pBitmapBits.
//
// fCompressed - a flag specifying whether the supplied bitmap
// bits are compressed.
//
// RETURNS:
//
// Nothing.
//
//
void ASShare::RBCStoreBitsInCacheBitmap ( ASPerson * pasPerson, UINT cache, UINT iCacheEntry, UINT cxSubBitmapWidth, UINT cxFixedWidth, UINT cySubBitmapHeight, UINT bpp, LPBYTE pBitmapBits, UINT cbBitmapBits, BOOL fCompressed ) { PBMC_DIB_ENTRY pDIBEntry;
DebugEntry(ASShare::RBCStoreBitsInCacheBitmap);
ValidatePerson(pasPerson);
//
// Do some error checking.
//
if (cache >= NUM_BMP_CACHES) { ERROR_OUT(("Invalid cache ID %d from [%d]", cache, pasPerson->mcsID)); DC_QUIT; }
//
// Now store the bits in the cache
// The cache is a huge chunk of memory comprising cache slots of cSize
// bytes each. cSize is rounded to a power of 2 to ensure the array
// spans segment boundaries cleanly for segmented architecture OSs.
//
pDIBEntry = (PBMC_DIB_ENTRY) (((LPBYTE)(pasPerson->prbcHost->bitmapCache[cache].data) + (iCacheEntry * pasPerson->prbcHost->bitmapCache[cache].cSize))); TRACE_OUT(( "Selected cache entry 0x%08x",pDIBEntry));
pDIBEntry->inUse = TRUE; pDIBEntry->cx = (TSHR_UINT16)cxSubBitmapWidth; pDIBEntry->cxFixed = (TSHR_UINT16)cxFixedWidth; pDIBEntry->cy = (TSHR_UINT16)cySubBitmapHeight; pDIBEntry->bpp = (TSHR_UINT16)bpp; pDIBEntry->bCompressed = (fCompressed != FALSE); pDIBEntry->cCompressed = cbBitmapBits;
//
// Now copy the bits into the cache entry
//
memcpy(pDIBEntry->bits, pBitmapBits, cbBitmapBits);
//
// THIS FIELD IS NEVER ACCESSED.
//
pDIBEntry->cBits = BYTES_IN_BITMAP(cxFixedWidth, cySubBitmapHeight, pDIBEntry->bpp);
DC_EXIT_POINT: DebugExitVOID(ASShare::RBCStoreBitsInCacheBitmap); }
//
// BMCAllocateCacheData()
//
// DESCRIPTION:
//
// Allocates memory for a bitmap cache
//
// PARAMETERS:
//
// cellSize
//
// RETURNS:
//
// Area needed
//
//
BOOL BMCAllocateCacheData ( UINT numEntries, UINT cellSize, UINT cacheID, PBMC_DIB_CACHE pCache ) { BOOL rc = TRUE; UINT memoryNeeded; UINT workSize; PBMC_DIB_ENTRY pCacheEntry; UINT i;
DebugEntry(BMCAllocateCacheData);
//
// First we must free up any data, if it has been allocated
//
BMCFreeCacheData(pCache);
//
// For 2.x compat, we have SEND caps of 1 entry, 1 byte since 2.x
// remotes fail for zero entries. But we don't want a small cache
// at all, and for W95 nodes that don't have a cache at all, we don't
// want viewers to alloc memory which will never be used.
//
if ((cellSize > 1) && (numEntries > 1)) { //
// Calculate the cell area
//
workSize = cellSize + sizeof(BMC_DIB_ENTRY) - 1; memoryNeeded = numEntries * workSize;
TRACE_OUT(("Need 0x%08x bytes for cache %d, %d cells of size 0x%08x", memoryNeeded, cacheID, numEntries, cellSize));
//
// Malloc the huge space
//
pCache->data = new BYTE[memoryNeeded]; if (pCache->data == NULL) { ERROR_OUT(( "Failed to alloc bitmap cache %d", cacheID)); rc = FALSE; DC_QUIT; }
pCache->cCellSize = cellSize; pCache->cEntries = numEntries; pCache->cSize = workSize; pCache->freeEntry = NULL; pCacheEntry = (PBMC_DIB_ENTRY)(pCache->data);
for (i = 0; i < numEntries; i++) { pCacheEntry->inUse = FALSE; pCacheEntry = (PBMC_DIB_ENTRY)(((LPBYTE)pCacheEntry) + workSize); }
TRACE_OUT(( "Allocated cache %d size %d, pointer 0x%08x stored at 0x%08x", cacheID, memoryNeeded, pCache->data, &pCache->data)); }
DC_EXIT_POINT: DebugExitBOOL(BMCAllocateCacheData, rc); return(rc); }
//
// FUNCTION: BMCFreeCacheData()
//
// DESCRIPTION:
//
// Deletes selected cache's memory
//
// PARAMETERS:
//
// cacheID - id of cache for free
// pCache - pointer to memory to be freed
//
//
// RETURNS:
//
// Nothing.
//
//
void BMCFreeCacheData(PBMC_DIB_CACHE pCache) { DebugEntry(BMCFreeCacheData);
if (pCache->data) { delete[] pCache->data; pCache->data = NULL; }
pCache->cCellSize = 0; pCache->cEntries = 0;
DebugExitVOID(BMCFreeCacheData); }
|