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.
2357 lines
75 KiB
2357 lines
75 KiB
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// SBC.CPP
|
|
// Send Bitmap Cache
|
|
//
|
|
// Copyright(c) Microsoft 1997-
|
|
//
|
|
|
|
#define MLZ_FILE_ZONE ZONE_CORE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// SBC_HostStarting()
|
|
//
|
|
BOOL ASHost::SBC_HostStarting(void)
|
|
{
|
|
BITMAPINFO_ours bitmapInfo;
|
|
int i;
|
|
BOOL rc = FALSE;
|
|
|
|
DebugEntry(ASHost::SBC_HostStarting);
|
|
|
|
if (g_sbcEnabled)
|
|
{
|
|
//
|
|
// We create a DIB section for each tile size which we use during the
|
|
// conversion of a bitmap from the native (device) bpp to the protocol
|
|
// bpp. We create the DIB sections at the device bpp.
|
|
//
|
|
ZeroMemory(&bitmapInfo, sizeof(bitmapInfo));
|
|
m_pShare->USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&bitmapInfo, g_usrCaptureBPP);
|
|
|
|
// We only capture at 8 or 24 for NT 5.0, otherwise the screen depth
|
|
if ((g_usrCaptureBPP > 8) && (g_usrCaptureBPP != 24))
|
|
{
|
|
//
|
|
// If the device bpp is > 8 (but not 24), we have to set up the DIB
|
|
// section to use the same bitmasks as the device. This means
|
|
// setting the compression type to BI_BITFIELDS and setting the
|
|
// first 3 DWORDS of the bitmap info color table to be the bitmasks
|
|
// for R, G and B respectively.
|
|
//
|
|
// 24bpp does not use bitmasks - it must use
|
|
// regular BI_RGB format with 8 bits for each colour.
|
|
//
|
|
bitmapInfo.bmiHeader.biCompression = BI_BITFIELDS;
|
|
|
|
ASSERT(g_asbcBitMasks[0]);
|
|
ASSERT(g_asbcBitMasks[1]);
|
|
ASSERT(g_asbcBitMasks[2]);
|
|
|
|
bitmapInfo.bmiColors[0] = ((LPTSHR_RGBQUAD)g_asbcBitMasks)[0];
|
|
bitmapInfo.bmiColors[1] = ((LPTSHR_RGBQUAD)g_asbcBitMasks)[1];
|
|
bitmapInfo.bmiColors[2] = ((LPTSHR_RGBQUAD)g_asbcBitMasks)[2];
|
|
}
|
|
|
|
//
|
|
// Initialize m_asbcWorkInfo array which holds the info we use to
|
|
// convert from native bpp to protocol bpp.
|
|
//
|
|
|
|
//
|
|
// First, intialize all the fields to default values
|
|
//
|
|
for (i = 0; i < SBC_NUM_TILE_SIZES ; i++)
|
|
{
|
|
ASSERT(!m_asbcWorkInfo[i].pShuntBuffer);
|
|
ASSERT(g_asbcShuntBuffers[i]);
|
|
|
|
m_asbcWorkInfo[i].pShuntBuffer = g_asbcShuntBuffers[i];
|
|
|
|
ASSERT(m_asbcWorkInfo[i].mruIndex == 0);
|
|
ASSERT(m_asbcWorkInfo[i].workBitmap == 0);
|
|
ASSERT(m_asbcWorkInfo[i].pWorkBitmapBits == NULL);
|
|
|
|
if (i == SBC_MEDIUM_TILE_INDEX)
|
|
{
|
|
m_asbcWorkInfo[i].tileWidth = MP_MEDIUM_TILE_WIDTH;
|
|
m_asbcWorkInfo[i].tileHeight = MP_MEDIUM_TILE_HEIGHT;
|
|
}
|
|
else
|
|
{
|
|
m_asbcWorkInfo[i].tileWidth = MP_LARGE_TILE_WIDTH;
|
|
m_asbcWorkInfo[i].tileHeight = MP_LARGE_TILE_HEIGHT;
|
|
}
|
|
|
|
bitmapInfo.bmiHeader.biWidth = m_asbcWorkInfo[i].tileWidth;
|
|
bitmapInfo.bmiHeader.biHeight = m_asbcWorkInfo[i].tileHeight;
|
|
|
|
m_asbcWorkInfo[i].workBitmap = CreateDIBSection(NULL,
|
|
(BITMAPINFO*)&bitmapInfo,
|
|
DIB_RGB_COLORS,
|
|
(void **)&(m_asbcWorkInfo[i].pWorkBitmapBits),
|
|
NULL, // File mapping object
|
|
0); // Offset into file
|
|
// mapping object
|
|
if (!m_asbcWorkInfo[i].workBitmap)
|
|
{
|
|
ERROR_OUT(("Failed to create SBC DIB section %d", i));
|
|
DC_QUIT;
|
|
}
|
|
|
|
ASSERT(m_asbcWorkInfo[i].pWorkBitmapBits);
|
|
TRACE_OUT(( "Created work DIB section %d, pBits = 0x%08x",
|
|
i, m_asbcWorkInfo[i].pWorkBitmapBits));
|
|
}
|
|
|
|
//
|
|
// Initialize the fastpath
|
|
//
|
|
if (!SBCInitFastPath())
|
|
{
|
|
TRACE_OUT(( "Failed to init fastpath"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (!SBCInitInternalOrders())
|
|
{
|
|
ERROR_OUT(( "Failed to init SBC internal order struct"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
m_pShare->SBC_RecalcCaps(TRUE);
|
|
}
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(ASHost::SBC_HostStarting, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// ASShare::SBC_HostEnded()
|
|
//
|
|
void ASHost::SBC_HostEnded(void)
|
|
{
|
|
int i;
|
|
|
|
DebugEntry(ASHost::SBC_HostEnded);
|
|
|
|
if (g_sbcEnabled)
|
|
{
|
|
//
|
|
// Free up the memory associated with sbcOrderInfo.
|
|
//
|
|
SBCFreeInternalOrders();
|
|
|
|
SBCInitCacheStructures();
|
|
|
|
//
|
|
// Free our fast path info
|
|
//
|
|
if (m_sbcFastPath)
|
|
{
|
|
delete m_sbcFastPath;
|
|
m_sbcFastPath = NULL;
|
|
}
|
|
|
|
//
|
|
// Clear our cache handles.
|
|
//
|
|
for (i = 0; i < NUM_BMP_CACHES; i++)
|
|
{
|
|
if (m_asbcBmpCaches[i].handle != 0)
|
|
{
|
|
TRACE_OUT(( "Clear cache %d", i));
|
|
CH_DestroyCache(m_asbcBmpCaches[i].handle);
|
|
BMCFreeCacheData(&m_asbcBmpCaches[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free our work DIB sections
|
|
//
|
|
|
|
//
|
|
// We just have to delete the DIB sections and reset our variables.
|
|
//
|
|
for (i = 0 ; i < SBC_NUM_TILE_SIZES ; i++)
|
|
{
|
|
m_asbcWorkInfo[i].pShuntBuffer = NULL;
|
|
|
|
if (m_asbcWorkInfo[i].workBitmap != NULL)
|
|
{
|
|
DeleteBitmap(m_asbcWorkInfo[i].workBitmap);
|
|
m_asbcWorkInfo[i].workBitmap = NULL;
|
|
m_asbcWorkInfo[i].pWorkBitmapBits = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_HostEnded);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SBC_SyncOutgoing()
|
|
// Called when we're already hosting and someone new joins the share.
|
|
// Resets the OUTGOING bitmap cache for bitblt orders.
|
|
//
|
|
void ASHost::SBC_SyncOutgoing(void)
|
|
{
|
|
int i;
|
|
|
|
DebugEntry(ASHost::SBC_SyncOutgoing);
|
|
|
|
//
|
|
// Only do anything if SBC is enabled
|
|
//
|
|
if (g_sbcEnabled)
|
|
{
|
|
//
|
|
// Discard all currently cached bitmaps and set the colour table to
|
|
// zero so that the next bitmap order which arrives will trigger the
|
|
// sending of a new colour table first. Note that if the colour table
|
|
// is then full of zeros(!) it will still be OK because the RBC zeros
|
|
// out its copy of the colour table when a new host joins the share.
|
|
//
|
|
TRACE_OUT(( "Clearing all send caches"));
|
|
SBCInitCacheStructures();
|
|
|
|
//
|
|
// All we have to do here is to reset our MRU indices for each of the
|
|
// shunt buffers. Each of the entries in the shunt buffer will be
|
|
// marked as free down in the driver.
|
|
//
|
|
for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
|
|
{
|
|
m_asbcWorkInfo[i].mruIndex = 0;
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_SyncOutgoing);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// SBC_CopyPrivateOrderData()
|
|
//
|
|
//
|
|
UINT ASHost::SBC_CopyPrivateOrderData
|
|
(
|
|
LPBYTE pDst,
|
|
LPCOM_ORDER pOrder,
|
|
UINT freeBytesInBuffer
|
|
)
|
|
{
|
|
UINT orderSize;
|
|
LPBYTE pBitmapBits;
|
|
|
|
DebugEntry(ASHost::SBC_CopyPrivateOrderData);
|
|
|
|
//
|
|
// Copy the order header without the rectangle structure (which we
|
|
// do not use).
|
|
//
|
|
orderSize = sizeof(pOrder->OrderHeader)
|
|
- sizeof(pOrder->OrderHeader.rcsDst);
|
|
memcpy(pDst, pOrder, orderSize);
|
|
|
|
//
|
|
// Copy the basic order data.
|
|
//
|
|
memcpy(pDst + orderSize,
|
|
pOrder->abOrderData,
|
|
pOrder->OrderHeader.cbOrderDataLength);
|
|
orderSize += pOrder->OrderHeader.cbOrderDataLength;
|
|
|
|
if (orderSize > freeBytesInBuffer)
|
|
{
|
|
ERROR_OUT(( "Overwritten end of buffer. (%u) > (%u)",
|
|
orderSize,
|
|
freeBytesInBuffer));
|
|
}
|
|
|
|
//
|
|
// Set the length field in the order header to be the total amount of
|
|
// data we have copied (including the partial header) minus the
|
|
// size of a full header. This is horrible! - but is needed because
|
|
// the OD2 code looks at the header (which it really should not know
|
|
// about) and uses the length field to calculate the total length of
|
|
// the order. The OD2 code does not know that we have omitted some
|
|
// of the header.
|
|
//
|
|
((LPCOM_ORDER)pDst)->OrderHeader.cbOrderDataLength =
|
|
(WORD)(orderSize - sizeof(COM_ORDER_HEADER));
|
|
|
|
//
|
|
// Return the total number of bytes that we have copied.
|
|
//
|
|
DebugExitDWORD(ASHost::SBC_CopyPrivateOrderData, orderSize);
|
|
return(orderSize);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: SBCInitCacheStructures()
|
|
//
|
|
// Purpose:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Params:
|
|
//
|
|
// Operation:
|
|
//
|
|
//
|
|
void ASHost::SBCInitCacheStructures(void)
|
|
{
|
|
UINT i;
|
|
|
|
DebugEntry(ASHost::SBCInitCacheStructures);
|
|
|
|
ASSERT(g_sbcEnabled);
|
|
|
|
//
|
|
// Reset caches
|
|
//
|
|
for (i = 0; i < NUM_BMP_CACHES; i++)
|
|
{
|
|
if (m_asbcBmpCaches[i].handle)
|
|
{
|
|
CH_ClearCache(m_asbcBmpCaches[i].handle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do any OS specific processing
|
|
//
|
|
SBC_CacheCleared();
|
|
|
|
DebugExitVOID(ASHost::SBCInitCacheStructures);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SBC_CacheCleared()
|
|
//
|
|
void ASHost::SBC_CacheCleared(void)
|
|
{
|
|
int i;
|
|
|
|
DebugEntry(ASHost::SBC_CacheCleared);
|
|
|
|
ASSERT(g_sbcEnabled);
|
|
ASSERT(m_sbcFastPath);
|
|
|
|
//
|
|
// The cache has been cleared. Reset our fast path.
|
|
//
|
|
COM_BasedListInit(&m_sbcFastPath->usedList);
|
|
COM_BasedListInit(&m_sbcFastPath->freeList);
|
|
|
|
for (i = 0; i < SBC_FASTPATH_ENTRIES; i++)
|
|
{
|
|
m_sbcFastPath->entry[i].list.next = 0;
|
|
m_sbcFastPath->entry[i].list.prev = 0;
|
|
COM_BasedListInsertBefore(&m_sbcFastPath->freeList,
|
|
&m_sbcFastPath->entry[i].list);
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_CacheCleared);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// SBCSelectCache(..)
|
|
//
|
|
// Decides which cache a sub-bitmap from a source bitmap of the specified
|
|
// size should go in.
|
|
//
|
|
// To be cached, the sub-bitmap must:
|
|
// have a size, in compressed bytes, which fits in the cache
|
|
//
|
|
// The R1.1 cache selection is irrespective of the actual memory
|
|
// requirement for the cached data. This is wasteful of space, but is
|
|
// necessary for R1.1 compatibility. (The R1.1 cache paremeters mean that
|
|
// the total cache will be below about 128K in any case)
|
|
//
|
|
// For R2.0 the cache is selected by this function by comparing the
|
|
// post-compress size with the cell area of each of the caches. This gives
|
|
// us a much better space usage on both server and client.
|
|
//
|
|
// Returns:
|
|
// TRUE if the sub-bitmap can be cached.
|
|
// *pCache is updated with the index of the selected cache.
|
|
//
|
|
// FALSE if the sub-bitmap cannot be cached.
|
|
// *pCache is not updated.
|
|
//
|
|
//
|
|
BOOL ASHost::SBCSelectCache
|
|
(
|
|
UINT cSize,
|
|
UINT * pCache
|
|
)
|
|
{
|
|
BOOL fCacheSelected;
|
|
BOOL fSelectedCacheIsFull;
|
|
UINT i;
|
|
|
|
DebugEntry(ASHost::SBCSelectCache);
|
|
|
|
fCacheSelected = FALSE;
|
|
fSelectedCacheIsFull = FALSE;
|
|
|
|
//
|
|
// This loop makes the assumption that cache 0 is the smallest. If
|
|
// abmcint.h changes this assumption it will need rewriting.
|
|
//
|
|
for (i = 0; i < NUM_BMP_CACHES; i++)
|
|
{
|
|
if (m_asbcBmpCaches[i].cEntries <= 0)
|
|
{
|
|
//
|
|
// No entries in this cache, so skip to the next one
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// R2 bitmap cache - only consider total cell size.
|
|
//
|
|
// Only consider this cache if
|
|
// - we haven't yet found a cache
|
|
// OR
|
|
// - we have found a cache, but it is full (i.e. will
|
|
// require an entry to be ejected) AND this one is not
|
|
// full
|
|
//
|
|
// (Note that a cache is full if freeEntry != NULL)
|
|
//
|
|
if (!fCacheSelected ||
|
|
(fSelectedCacheIsFull &&
|
|
((m_asbcBmpCaches[i].freeEntry == NULL)
|
|
|| !m_asbcBmpCaches[i].freeEntry->inUse)))
|
|
{
|
|
if (cSize <= m_asbcBmpCaches[i].cSize)
|
|
{
|
|
if (fSelectedCacheIsFull)
|
|
{
|
|
TRACE_OUT(("Using cache %u because cache %u is full",
|
|
*pCache, i));
|
|
}
|
|
|
|
*pCache = i;
|
|
fCacheSelected = TRUE;
|
|
|
|
fSelectedCacheIsFull =
|
|
((m_asbcBmpCaches[i].freeEntry != NULL) &&
|
|
m_asbcBmpCaches[i].freeEntry->inUse);
|
|
|
|
if (!fSelectedCacheIsFull)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugExitDWORD(ASHost::SBCSelectCache, fCacheSelected);
|
|
return(fCacheSelected);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: SBC_RecreateSendCache
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// (Re)creates the send bitmap cache with a size suitable for the current
|
|
// capabilities.
|
|
//
|
|
// PARAMETERS:
|
|
// cache - index to the cache being recreated
|
|
// cOldEntries - the previous max number of entries in the cache
|
|
// oldCellSize - the previous cell size
|
|
//
|
|
// RETURNS: NONE
|
|
//
|
|
//
|
|
void ASHost::SBC_RecreateSendCache
|
|
(
|
|
UINT cache,
|
|
UINT newNumEntries,
|
|
UINT newCellSize
|
|
)
|
|
{
|
|
PBMC_DIB_CACHE pCache = &(m_asbcBmpCaches[cache]);
|
|
|
|
DebugEntry(ASHost::SBC_RecreateSendCache);
|
|
|
|
//
|
|
// Allocate the memory for the new send cache
|
|
//
|
|
ASSERT((newCellSize != pCache->cCellSize) ||
|
|
(newNumEntries != pCache->cEntries));
|
|
|
|
//
|
|
// If the cache already exists then destroy it first
|
|
//
|
|
if (pCache->handle != 0)
|
|
{
|
|
TRACE_OUT(( "Destroy SBC cache %d", cache));
|
|
|
|
CH_DestroyCache(pCache->handle);
|
|
pCache->handle = 0;
|
|
}
|
|
|
|
//
|
|
// Now reallocate the cache data. This will free any memory previously
|
|
// allocated. If the entries/cellsize is zero, it will return success.
|
|
//
|
|
if (!BMCAllocateCacheData(newNumEntries, newCellSize, cache, pCache))
|
|
{
|
|
ERROR_OUT(( "Bitmap caching disabled for cache %u", cache));
|
|
}
|
|
|
|
if (pCache->cEntries > 0)
|
|
{
|
|
//
|
|
// Allocate cache handler cache. Note that we force the cache
|
|
// handler to leave us with one entry in our hand at all times by
|
|
// decrementing its count of entries.
|
|
//
|
|
if (!CH_CreateCache(&(pCache->handle),
|
|
pCache->cEntries - 1,
|
|
SBC_NUM_CATEGORIES,
|
|
BMC_DIB_NOT_HASHED,
|
|
SBCCacheCallback ))
|
|
{
|
|
ERROR_OUT(( "Could not allocate SBC cache of (%u)",
|
|
pCache->cEntries));
|
|
pCache->cEntries = 0;
|
|
}
|
|
}
|
|
|
|
TRACE_OUT(( "Created new cache: 0x%08x, size %u",
|
|
pCache->handle,
|
|
pCache->cEntries));
|
|
|
|
//
|
|
// Copy the relevant cache information into the shared memory buffer
|
|
//
|
|
m_asbcCacheInfo[cache].cEntries = (WORD)pCache->cEntries;
|
|
m_asbcCacheInfo[cache].cCellSize = (WORD)pCache->cCellSize;
|
|
|
|
TRACE_OUT(("SBC cache %d: %d entries of size %d",
|
|
cache, m_asbcCacheInfo[cache].cEntries, m_asbcCacheInfo[cache].cCellSize));
|
|
|
|
DebugExitVOID(ASHost::SBC_RecreateSendCache);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SBC_RecalcCaps()
|
|
//
|
|
// Enumerates all the people in the share and redetermines the size of the
|
|
// bitmap cache depending on their and the local receive capabilities.
|
|
//
|
|
//
|
|
// THIS CAN GO AWAY WHEN 2.X COMPAT DOES
|
|
//
|
|
void ASShare::SBC_RecalcCaps(BOOL fJoiner)
|
|
{
|
|
SBC_NEW_CAPABILITIES newCapabilities;
|
|
UINT newSmallCellSize;
|
|
UINT newSmallMaxEntries;
|
|
UINT newMediumCellSize;
|
|
UINT newMediumMaxEntries;
|
|
UINT newLargeCellSize;
|
|
UINT newLargeMaxEntries;
|
|
PBMC_DIB_CACHE pSmall;
|
|
PBMC_DIB_CACHE pMedium;
|
|
PBMC_DIB_CACHE pLarge;
|
|
BOOL cacheChanged = FALSE;
|
|
ASPerson * pasT;
|
|
|
|
DebugEntry(ASShare::SBC_RecalcCaps);
|
|
|
|
if (!m_pHost || !g_sbcEnabled)
|
|
{
|
|
//
|
|
// Nothing to do -- we're not hosting, or there is no SBC. Note that
|
|
// 2.x always recalculated this stuff when somebody joined AND
|
|
// somebody left.
|
|
//
|
|
DC_QUIT;
|
|
}
|
|
|
|
ValidatePerson(m_pasLocal);
|
|
|
|
pSmall = &(m_pHost->m_asbcBmpCaches[ID_SMALL_BMP_CACHE]);
|
|
pMedium= &(m_pHost->m_asbcBmpCaches[ID_MEDIUM_BMP_CACHE]);
|
|
pLarge = &(m_pHost->m_asbcBmpCaches[ID_LARGE_BMP_CACHE]);
|
|
|
|
//
|
|
// Enumerate all the bitmap cache receive capabilities of the parties
|
|
// in the share. The usable size of the send bitmap cache is then the
|
|
// minimum of all the remote receive caches and the local send cache
|
|
// size.
|
|
//
|
|
|
|
//
|
|
// Start by setting the size of the local send bitmap cache to the
|
|
// local default values.
|
|
//
|
|
newSmallCellSize = m_pasLocal->cpcCaps.bitmaps.sender.capsSmallCacheCellSize;
|
|
newSmallMaxEntries = m_pasLocal->cpcCaps.bitmaps.sender.capsSmallCacheNumEntries;
|
|
|
|
newMediumCellSize = m_pasLocal->cpcCaps.bitmaps.sender.capsMediumCacheCellSize;
|
|
newMediumMaxEntries = m_pasLocal->cpcCaps.bitmaps.sender.capsMediumCacheNumEntries;
|
|
|
|
newLargeCellSize = m_pasLocal->cpcCaps.bitmaps.sender.capsLargeCacheCellSize;
|
|
newLargeMaxEntries = m_pasLocal->cpcCaps.bitmaps.sender.capsLargeCacheNumEntries;
|
|
|
|
if (m_scShareVersion < CAPS_VERSION_30)
|
|
{
|
|
TRACE_OUT(("In share with 2.x nodes, must recalc SBC caps"));
|
|
|
|
//
|
|
// Now enumerate all the REMOTE parties in the share and set our send bitmap
|
|
// size appropriately.
|
|
//
|
|
for (pasT = m_pasLocal->pasNext; pasT != NULL; pasT = pasT->pasNext)
|
|
{
|
|
//
|
|
// Set the size of the local send bitmap cache to the minimum of its
|
|
// current size and this party's receive bitmap cache size.
|
|
//
|
|
newSmallCellSize = min(newSmallCellSize,
|
|
pasT->cpcCaps.bitmaps.receiver.capsSmallCacheCellSize);
|
|
newSmallMaxEntries = min(newSmallMaxEntries,
|
|
pasT->cpcCaps.bitmaps.receiver.capsSmallCacheNumEntries);
|
|
|
|
newMediumCellSize = min(newMediumCellSize,
|
|
pasT->cpcCaps.bitmaps.receiver.capsMediumCacheCellSize);
|
|
newMediumMaxEntries = min(newMediumMaxEntries,
|
|
pasT->cpcCaps.bitmaps.receiver.capsMediumCacheNumEntries);
|
|
|
|
newLargeCellSize = min(newLargeCellSize,
|
|
pasT->cpcCaps.bitmaps.receiver.capsLargeCacheCellSize);
|
|
newLargeMaxEntries = min(newLargeMaxEntries,
|
|
pasT->cpcCaps.bitmaps.receiver.capsLargeCacheNumEntries);
|
|
}
|
|
}
|
|
|
|
TRACE_OUT(("Recalced SBC caps: Small {%d of %d}, Medium {%d of %d}, Large {%d of %d}",
|
|
newSmallMaxEntries, newSmallCellSize,
|
|
newMediumMaxEntries, newMediumCellSize,
|
|
newLargeMaxEntries, newLargeCellSize));
|
|
|
|
|
|
//
|
|
// If we've changed the size, reset the cache before continuing.
|
|
//
|
|
if ((pSmall->cCellSize != newSmallCellSize) ||
|
|
(pSmall->cEntries != newSmallMaxEntries))
|
|
{
|
|
m_pHost->SBC_RecreateSendCache(ID_SMALL_BMP_CACHE,
|
|
newSmallMaxEntries,
|
|
newSmallCellSize);
|
|
cacheChanged = TRUE;
|
|
}
|
|
|
|
if ((pMedium->cCellSize != newMediumCellSize) ||
|
|
(pMedium->cEntries != newMediumMaxEntries))
|
|
{
|
|
m_pHost->SBC_RecreateSendCache(ID_MEDIUM_BMP_CACHE,
|
|
newMediumMaxEntries,
|
|
newMediumCellSize);
|
|
cacheChanged = TRUE;
|
|
}
|
|
|
|
if ((pLarge->cCellSize != newLargeCellSize) ||
|
|
(pLarge->cEntries != newLargeMaxEntries))
|
|
{
|
|
m_pHost->SBC_RecreateSendCache(ID_LARGE_BMP_CACHE,
|
|
newLargeMaxEntries,
|
|
newLargeCellSize);
|
|
cacheChanged = TRUE;
|
|
}
|
|
|
|
//
|
|
// If we had to recreate any of the send caches, make sure that we
|
|
// clear the fast path.
|
|
//
|
|
if (cacheChanged)
|
|
{
|
|
m_pHost->SBC_CacheCleared();
|
|
}
|
|
|
|
//
|
|
// Handle new capabilities
|
|
//
|
|
|
|
//
|
|
// Set up the new capabilities structure...
|
|
//
|
|
newCapabilities.sendingBpp = m_pHost->m_usrSendingBPP;
|
|
|
|
newCapabilities.cacheInfo = m_pHost->m_asbcCacheInfo;
|
|
|
|
//
|
|
// ... and pass it through to the driver.
|
|
//
|
|
if (! OSI_FunctionRequest(SBC_ESC_NEW_CAPABILITIES,
|
|
(LPOSI_ESCAPE_HEADER)&newCapabilities,
|
|
sizeof(newCapabilities)))
|
|
{
|
|
ERROR_OUT(("SBC_ESC_NEW_CAPABILITIES failed"));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(ASShare::SBC_RecalcCaps);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// FUNCTION: SBCCacheCallback
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Send BMC Cache Manager callback function. Called whenever an entry is
|
|
// removed from the cache to allow us to free up the object.
|
|
//
|
|
// PARAMETERS:
|
|
//
|
|
// hCache - cache handle
|
|
//
|
|
// event - the cache event that has occured
|
|
//
|
|
// iCacheEntry - index of the cache entry that the event is affecting
|
|
//
|
|
// pData - pointer to the cache data associated with the given cache entry
|
|
//
|
|
// cbDataSize - size in bytes of the cached data
|
|
//
|
|
// RETURNS: Nothing
|
|
//
|
|
//
|
|
void SBCCacheCallback
|
|
(
|
|
ASHost * pHost,
|
|
PCHCACHE pCache,
|
|
UINT iCacheEntry,
|
|
LPBYTE pData
|
|
)
|
|
{
|
|
UINT cache;
|
|
|
|
DebugEntry(SBCCacheCallback);
|
|
|
|
//
|
|
// Simply release the cache entry for reuse. We must scan for
|
|
// the correct cache root
|
|
//
|
|
for (cache = 0; cache < NUM_BMP_CACHES; cache++)
|
|
{
|
|
if (pHost->m_asbcBmpCaches[cache].handle == pCache)
|
|
{
|
|
pHost->m_asbcBmpCaches[cache].freeEntry = (PBMC_DIB_ENTRY)pData;
|
|
pHost->m_asbcBmpCaches[cache].freeEntry->inUse = FALSE;
|
|
|
|
TRACE_OUT(("0x%08x SBC cache entry 0x%08x now free", pCache, pData));
|
|
|
|
pHost->SBC_CacheEntryRemoved(cache, iCacheEntry);
|
|
break;
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(SBCCacheCallback);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// SBC_ProcessMemBltOrder()
|
|
//
|
|
//
|
|
BOOL ASHost::SBC_ProcessMemBltOrder
|
|
(
|
|
LPINT_ORDER pOrder,
|
|
LPINT_ORDER * ppNextOrder
|
|
)
|
|
{
|
|
BOOL rc = FALSE;
|
|
UINT orderType;
|
|
UINT tileId;
|
|
UINT tileType;
|
|
LPSBC_TILE_DATA pTileData = NULL;
|
|
UINT bitmapWidth;
|
|
int bitmapHeight;
|
|
LPINT_ORDER pBMCOrder = NULL;
|
|
UINT colorCacheIndex;
|
|
UINT bitsCache;
|
|
UINT bitsCacheIndex;
|
|
UINT numColors;
|
|
LPLONG pXSrc;
|
|
LPLONG pYSrc;
|
|
BOOL isNewColorTableEntry;
|
|
BOOL isNewBitsEntry;
|
|
BOOL canFastPath = TRUE;
|
|
LPMEMBLT_ORDER pMemBltOrder = (LPMEMBLT_ORDER)&(pOrder->abOrderData);
|
|
LPMEM3BLT_ORDER pMem3BltOrder = (LPMEM3BLT_ORDER)pMemBltOrder;
|
|
LPMEMBLT_R2_ORDER pMemBltR2Order = (LPMEMBLT_R2_ORDER)pMemBltOrder;
|
|
LPMEM3BLT_R2_ORDER pMem3BltR2Order = (LPMEM3BLT_R2_ORDER)pMemBltOrder;
|
|
BITMAPINFO_ours sbcBitmapInfo;
|
|
|
|
DebugEntry(ASHost::SBC_ProcessMemBltOrder);
|
|
|
|
*ppNextOrder = NULL;
|
|
|
|
//
|
|
// We may already have processed this MEMBLT order and have the color
|
|
// table and bitmap bits for it, ready to go across the wire. This
|
|
// would happen if the update packager called this function to process
|
|
// the MEMBLT, but then didn't have enough room in its current network
|
|
// packet to send the color table or the bitmap bits.
|
|
//
|
|
// So, if we've already processed this order, bail out now.
|
|
//
|
|
if (m_sbcOrderInfo.pOrder == pOrder)
|
|
{
|
|
//
|
|
// We've got a match ! Do we have valid data for it ? If we don't
|
|
// we must have failed last time, so we'll probably fail again (we
|
|
// don't do any memory allocation, so it's unlikely that the error
|
|
// condition has cleared up). In any case, we should not have been
|
|
// called again if we failed last time...
|
|
//
|
|
if (m_sbcOrderInfo.validData)
|
|
{
|
|
TRACE_OUT(( "Already have valid data for this MEMBLT"));
|
|
rc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(( "Have invalid data for this MEMBLT"));
|
|
}
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Re-initialise m_sbcOrderInfo
|
|
//
|
|
m_sbcOrderInfo.pOrder = pOrder;
|
|
m_sbcOrderInfo.validData = FALSE;
|
|
m_sbcOrderInfo.sentColorTable = FALSE;
|
|
m_sbcOrderInfo.sentBitmapBits = FALSE;
|
|
m_sbcOrderInfo.sentMemBlt = FALSE;
|
|
|
|
//
|
|
// Here's on overview of what we do here...
|
|
//
|
|
// We've been given a MEMBLT order which references an entry in a shunt
|
|
// buffer containing the bits for the MEMBLT at the native bpp (the bpp
|
|
// of the display). We want to cache the bits and a color table at the
|
|
// protocol bpp. So, we
|
|
//
|
|
// - copy the bits from the shunt buffer into a work DIB section
|
|
// - call GetDIBits to get the data from the work DIB section at the
|
|
// protocol bpp
|
|
// - cache the bits and the color table
|
|
// - if we add new cache entries for the bits and / or the color table,
|
|
// we fill in m_sbcOrderInfo.pBitmapBits order and / or
|
|
// m_sbcOrderInfo.pColorTableInfo to hold the orders to be sent before
|
|
// the MEMBLT order.
|
|
//
|
|
|
|
//
|
|
// Make sure that we've been given the correct order type. Note that
|
|
// we will never be given the R2 versions of the MEMBLT orders.
|
|
//
|
|
orderType = pMemBltOrder->type;
|
|
ASSERT(((orderType == ORD_MEMBLT_TYPE) ||
|
|
(orderType == ORD_MEM3BLT_TYPE)));
|
|
|
|
//
|
|
// Get a pointer to the entry in one of the shunt buffers which matches
|
|
// this order.
|
|
//
|
|
if (orderType == ORD_MEMBLT_TYPE)
|
|
{
|
|
tileId = pMemBltOrder->cacheId;
|
|
}
|
|
else
|
|
{
|
|
tileId = pMem3BltOrder->cacheId;
|
|
}
|
|
|
|
if (!SBCGetTileData(tileId, &pTileData, &tileType))
|
|
{
|
|
ERROR_OUT(( "Failed to find entry for tile %hx in shunt buffer",
|
|
tileId));
|
|
DC_QUIT;
|
|
}
|
|
|
|
bitmapWidth = pTileData->width;
|
|
bitmapHeight = pTileData->height;
|
|
|
|
//
|
|
// Check if we should do any fast path operations on this bitmap
|
|
//
|
|
if (pTileData->majorCacheInfo == SBC_DONT_FASTPATH)
|
|
{
|
|
TRACE_OUT(( "Tile %x should not be fastpathed", tileId));
|
|
canFastPath = FALSE;
|
|
}
|
|
//
|
|
// Try to find an entry for this bitmap in the fast path (unless the
|
|
// bitmap is marked as being non-fastpathable).
|
|
//
|
|
if (canFastPath && SBCFindInFastPath(pTileData->majorCacheInfo,
|
|
pTileData->minorCacheInfo,
|
|
pTileData->majorPalette,
|
|
pTileData->minorPalette,
|
|
pTileData->srcX,
|
|
pTileData->srcY,
|
|
pTileData->tilingWidth,
|
|
pTileData->tilingHeight,
|
|
&bitsCache,
|
|
&bitsCacheIndex,
|
|
&colorCacheIndex))
|
|
{
|
|
isNewBitsEntry = FALSE;
|
|
isNewColorTableEntry = FALSE;
|
|
|
|
//
|
|
// Call the cache handler to get it to update its MRU entry for
|
|
// this cache entry
|
|
//
|
|
CH_TouchCacheEntry(m_asbcBmpCaches[bitsCache].handle, bitsCacheIndex);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There is no entry in the fast path...
|
|
//
|
|
// Copy the data from the tile in the shunt buffer into the work
|
|
// DIB section. Note that this only works correctly because both
|
|
// our work DIB and the tile data are "top down" rather than the
|
|
// default of "bottom up". i.e the data for the first scanline is
|
|
// stored first in memory. If this wasn't the case, we'd have to
|
|
// work out an offset into the work DIB to start copying to.
|
|
//
|
|
memcpy(m_asbcWorkInfo[tileType].pWorkBitmapBits,
|
|
pTileData->bitData,
|
|
pTileData->bytesUsed);
|
|
|
|
//
|
|
// Now set up the destination for the GetDIBits call. First set up
|
|
// a bitmap info header to pass to GetDIBits. Only the header part
|
|
// of the structure will be sent across the network - the color
|
|
// table is sent via the palette packets.
|
|
//
|
|
// Note that we set the height in the bitmap info header to be
|
|
// negative. This forces a convertion from our "top down" DIB
|
|
// format to the default "bottom up" format which we want to cache
|
|
// and send over the wire.
|
|
//
|
|
ZeroMemory(&sbcBitmapInfo, sizeof(sbcBitmapInfo));
|
|
m_pShare->USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&sbcBitmapInfo,
|
|
m_usrSendingBPP);
|
|
sbcBitmapInfo.bmiHeader.biWidth = m_asbcWorkInfo[tileType].tileWidth;
|
|
sbcBitmapInfo.bmiHeader.biHeight = -(int)m_asbcWorkInfo[tileType].tileHeight;
|
|
|
|
//
|
|
// OK, we've set up the source and the destination, so now get the
|
|
// data at the protocol bpp. We get the bits into the usr general
|
|
// bitmap work buffer.
|
|
//
|
|
if (GetDIBits(m_usrWorkDC,
|
|
m_asbcWorkInfo[tileType].workBitmap,
|
|
0,
|
|
bitmapHeight,
|
|
m_pShare->m_usrPBitmapBuffer,
|
|
(BITMAPINFO *)&sbcBitmapInfo,
|
|
DIB_RGB_COLORS) != (int)bitmapHeight)
|
|
{
|
|
ERROR_OUT(( "GetDIBits failed"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRACE_OUT(( "%d x %d, (fixed %d) -> (%d, %d)",
|
|
bitmapWidth,
|
|
bitmapHeight,
|
|
m_asbcWorkInfo[tileType].tileWidth,
|
|
pMemBltOrder->nLeftRect,
|
|
pMemBltOrder->nTopRect));
|
|
|
|
numColors = COLORS_FOR_BPP(m_usrSendingBPP);
|
|
|
|
//
|
|
// There is no color table to cache if there is no color table at
|
|
// all, which is the case when sending at 24BPP
|
|
//
|
|
if (numColors)
|
|
{
|
|
//
|
|
// Cache the color table. If this succeeds, colorCacheIndex will
|
|
// be set up to contain the details of the cache entry which the
|
|
// data is cached in. In addition, if isNewColorTableEntry is TRUE
|
|
// on return, psbcOrders.colorTableOrder will be fully initialized
|
|
// and ready to go across the wire.
|
|
//
|
|
if (!SBCCacheColorTable(m_sbcOrderInfo.pColorTableOrder,
|
|
sbcBitmapInfo.bmiColors,
|
|
numColors,
|
|
&colorCacheIndex,
|
|
&isNewColorTableEntry))
|
|
{
|
|
TRACE_OUT(( "Failed to cache color table"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
ASSERT(colorCacheIndex != COLORCACHEINDEX_NONE);
|
|
}
|
|
else
|
|
{
|
|
colorCacheIndex = COLORCACHEINDEX_NONE;
|
|
isNewColorTableEntry = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Cache the bits. If this succeeds, bitsCache and bitsCacheIndex
|
|
// will be set up to contain the details of the cache entry which
|
|
// the data is cached in. In addition, if isNewBitsEntry is TRUE
|
|
// on return, psbcOrders.bitmapBitsOrder will be fully initialized
|
|
// and ready to go across the wire.
|
|
//
|
|
// If this fails, the above values will be undefined.
|
|
//
|
|
if (!SBCCacheBits(m_sbcOrderInfo.pBitmapBitsOrder,
|
|
m_sbcOrderInfo.bitmapBitsDataSize,
|
|
m_pShare->m_usrPBitmapBuffer,
|
|
bitmapWidth,
|
|
m_asbcWorkInfo[tileType].tileWidth,
|
|
bitmapHeight,
|
|
BYTES_IN_BITMAP(m_asbcWorkInfo[tileType].tileWidth,
|
|
bitmapHeight,
|
|
sbcBitmapInfo.bmiHeader.biBitCount),
|
|
&bitsCache,
|
|
&bitsCacheIndex,
|
|
&isNewBitsEntry))
|
|
{
|
|
TRACE_OUT(( "Failed to cache bits"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Add the newly cached item to the fast path (unless the bitmap is
|
|
// marked as being non-fastpathable).
|
|
//
|
|
if (canFastPath)
|
|
{
|
|
SBCAddToFastPath(pTileData->majorCacheInfo,
|
|
pTileData->minorCacheInfo,
|
|
pTileData->majorPalette,
|
|
pTileData->minorPalette,
|
|
pTileData->srcX,
|
|
pTileData->srcY,
|
|
pTileData->tilingWidth,
|
|
pTileData->tilingHeight,
|
|
bitsCache,
|
|
bitsCacheIndex,
|
|
colorCacheIndex);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've now got valid cache entries for the DIB bits and the color
|
|
// table, so we should now fill them into the MEMBLT order.
|
|
//
|
|
// Set up the source co-ordinates. For R1 protocols, the x-coordinate
|
|
// includes the offset which is required to get the right cell within
|
|
// the receive bitmap cache. For R2, we set up the cache entry in a
|
|
// separate field.
|
|
//
|
|
if (orderType == ORD_MEMBLT_TYPE)
|
|
{
|
|
pXSrc = &pMemBltOrder->nXSrc;
|
|
pYSrc = &pMemBltOrder->nYSrc;
|
|
}
|
|
else
|
|
{
|
|
pXSrc = &pMem3BltOrder->nXSrc;
|
|
pYSrc = &pMem3BltOrder->nYSrc;
|
|
}
|
|
|
|
*pXSrc = *pXSrc % pTileData->tilingWidth;
|
|
*pYSrc = *pYSrc % pTileData->tilingHeight;
|
|
|
|
//
|
|
// The sub-bitmap and color table are in the cache. Store a cache
|
|
// handle and color handle. Also store the cache index for R2
|
|
// protocols (see above).
|
|
//
|
|
if (orderType == ORD_MEMBLT_TYPE)
|
|
{
|
|
pMemBltOrder->cacheId = MEMBLT_COMBINEHANDLES(colorCacheIndex,
|
|
bitsCache);
|
|
|
|
pMemBltR2Order->type = (TSHR_UINT16)ORD_MEMBLT_R2_TYPE;
|
|
pMemBltR2Order->cacheIndex = (TSHR_UINT16)bitsCacheIndex;
|
|
|
|
TRACE_OUT(( "MEMBLT color %u bitmap %u:%u",
|
|
colorCacheIndex,
|
|
bitsCache,
|
|
bitsCacheIndex));
|
|
}
|
|
else
|
|
{
|
|
pMem3BltOrder->cacheId = MEMBLT_COMBINEHANDLES(colorCacheIndex,
|
|
bitsCache);
|
|
|
|
pMem3BltR2Order->type = ORD_MEM3BLT_R2_TYPE;
|
|
pMem3BltR2Order->cacheIndex = (TSHR_UINT16)bitsCacheIndex;
|
|
|
|
TRACE_OUT(( "MEM3BLT color %u bitmap %u:%u",
|
|
colorCacheIndex,
|
|
bitsCache,
|
|
bitsCacheIndex));
|
|
}
|
|
|
|
//
|
|
// Must have successfully completed processing the order to get to
|
|
// here. Fill in the appropriate info in the m_sbcOrderInfo structure.
|
|
// If we got a cache hit on the color table or the bitmap bits then
|
|
// we've already sent the data for them.
|
|
//
|
|
m_sbcOrderInfo.validData = TRUE;
|
|
m_sbcOrderInfo.sentColorTable = !isNewColorTableEntry;
|
|
m_sbcOrderInfo.sentBitmapBits = !isNewBitsEntry;
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
if (rc)
|
|
{
|
|
//
|
|
// We've successfully processed the MEMBLT, so set up a pointer to
|
|
// the next order which should be sent by the caller.
|
|
//
|
|
// Note that if we have already sent these orders, then we return
|
|
// a NULL order.
|
|
//
|
|
if (!m_sbcOrderInfo.sentColorTable)
|
|
{
|
|
TRACE_OUT(( "Returning color table order"));
|
|
*ppNextOrder = m_sbcOrderInfo.pColorTableOrder;
|
|
}
|
|
else if (!m_sbcOrderInfo.sentBitmapBits)
|
|
{
|
|
TRACE_OUT(( "Returning bitmap bits order"));
|
|
*ppNextOrder = m_sbcOrderInfo.pBitmapBitsOrder;
|
|
}
|
|
else if (!m_sbcOrderInfo.sentMemBlt)
|
|
{
|
|
TRACE_OUT(( "Returning MemBlt order"));
|
|
*ppNextOrder = pOrder;
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(( "No order to return"));
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've finished with the entry in the shunt buffer, so reset the
|
|
// inUse flag to allow the driver to re-use it.
|
|
//
|
|
if (pTileData != NULL)
|
|
{
|
|
pTileData->inUse = FALSE;
|
|
}
|
|
|
|
DebugExitBOOL(ASHost::SBC_ProcessMemBltOrder, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// SBC_OrderSentNotification()
|
|
//
|
|
//
|
|
void ASHost::SBC_OrderSentNotification(LPINT_ORDER pOrder)
|
|
{
|
|
DebugEntry(ASHost::SBC_OrderSentNotification);
|
|
|
|
//
|
|
// pOrder should be a pointer to either our internal bitmap bits order,
|
|
// or our color table order.
|
|
//
|
|
if (pOrder == m_sbcOrderInfo.pBitmapBitsOrder)
|
|
{
|
|
TRACE_OUT(( "Bitmap bits order has been sent"));
|
|
m_sbcOrderInfo.sentBitmapBits = TRUE;
|
|
}
|
|
else if (pOrder == m_sbcOrderInfo.pColorTableOrder)
|
|
{
|
|
TRACE_OUT(( "Color table order has been sent"));
|
|
m_sbcOrderInfo.sentColorTable = TRUE;
|
|
}
|
|
else if (pOrder == m_sbcOrderInfo.pOrder)
|
|
{
|
|
TRACE_OUT(( "Memblt order has been sent"));
|
|
m_sbcOrderInfo.sentMemBlt = TRUE;
|
|
|
|
//
|
|
// All parts of the Memblt have been sent now, so reset our pointer
|
|
// to the order. This avoids a problem where
|
|
// SBC_ProcessMemBltOrder is called twice in a row with the same
|
|
// pOrder, but with different data (i.e. consecutive MemBlts
|
|
// ending up in the same point in the order heap). It can happen...
|
|
//
|
|
m_sbcOrderInfo.pOrder = NULL;
|
|
}
|
|
else
|
|
{
|
|
ERROR_OUT(( "Notification for unknown order %#.8lx", pOrder));
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_OrderSentNotification);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// SBC_ProcessInternalOrder()
|
|
//
|
|
//
|
|
void ASHost::SBC_ProcessInternalOrder(LPINT_ORDER pOrder)
|
|
{
|
|
UINT orderType;
|
|
LPINT_COLORTABLE_ORDER_1BPP pColorTableOrder;
|
|
HBITMAP oldBitmap = 0;
|
|
UINT numEntries;
|
|
int i;
|
|
|
|
DebugEntry(ASHost::SBC_ProcessInternalOrder);
|
|
|
|
//
|
|
// Make sure that we've been given an order type which we recognise.
|
|
// Currently, the only internal order we support is a color table
|
|
// order.
|
|
//
|
|
pColorTableOrder = (LPINT_COLORTABLE_ORDER_1BPP)&(pOrder->abOrderData);
|
|
orderType = pColorTableOrder->header.type;
|
|
|
|
ASSERT(orderType == INTORD_COLORTABLE_TYPE);
|
|
|
|
//
|
|
// Make sure that the color table order is the same bpp as the work DIB
|
|
// sections.
|
|
//
|
|
ASSERT(pColorTableOrder->header.bpp == g_usrCaptureBPP);
|
|
|
|
//
|
|
// All we have to do is to copy the color table from the order into our
|
|
// two work DIB sections. To do that, we have to select the DIB
|
|
// sections into a DC then set the color table for the DC - this sets
|
|
// the color table in the DIB section.
|
|
//
|
|
numEntries = COLORS_FOR_BPP(g_usrCaptureBPP);
|
|
ASSERT(numEntries);
|
|
|
|
for (i = 0 ; i < SBC_NUM_TILE_SIZES; i++)
|
|
{
|
|
oldBitmap = SelectBitmap(m_usrWorkDC, m_asbcWorkInfo[i].workBitmap);
|
|
|
|
SetDIBColorTable(m_usrWorkDC,
|
|
0, // First index
|
|
numEntries, // Number of entries
|
|
(RGBQUAD*)pColorTableOrder->colorData);
|
|
}
|
|
|
|
if (oldBitmap != NULL)
|
|
{
|
|
SelectBitmap(m_usrWorkDC, oldBitmap);
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_ProcessInternalOrder);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// SBC_PMCacheEntryRemoved()
|
|
//
|
|
//
|
|
void ASHost::SBC_PMCacheEntryRemoved(UINT cacheIndex)
|
|
{
|
|
LPSBC_FASTPATH_ENTRY pEntry;
|
|
LPSBC_FASTPATH_ENTRY pNextEntry;
|
|
|
|
DebugEntry(ASHost::SBC_PMCacheEntryRemoved);
|
|
|
|
ASSERT(m_sbcFastPath);
|
|
|
|
//
|
|
// An entry has been removed from the color cache. We have to remove
|
|
// all entries from the fast path which reference this color table.
|
|
//
|
|
TRACE_OUT(( "Color table cache entry %d removed - removing references",
|
|
cacheIndex));
|
|
|
|
pEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListFirst(&m_sbcFastPath->usedList, FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
while (pEntry != NULL)
|
|
{
|
|
pNextEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListNext(&m_sbcFastPath->usedList, pEntry,
|
|
FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
|
|
if (pEntry->colorIndex == cacheIndex)
|
|
{
|
|
COM_BasedListRemove(&pEntry->list);
|
|
COM_BasedListInsertAfter(&m_sbcFastPath->freeList, &pEntry->list);
|
|
}
|
|
|
|
pEntry = pNextEntry;
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_PMCacheEntryRemoved);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCInitInternalOrders
|
|
//
|
|
// Purpose: Allocate memory for the internal orders used during MEMBLT
|
|
// order processing.
|
|
//
|
|
// Returns: TRUE if initialized OK, FALSE otherwise.
|
|
//
|
|
// Params: None
|
|
//
|
|
// Operation: If successful, this function initializes the following
|
|
//
|
|
// g_Share->sbcOrderInfo
|
|
//
|
|
//
|
|
BOOL ASHost::SBCInitInternalOrders(void)
|
|
{
|
|
BOOL initOK = FALSE;
|
|
UINT orderSize;
|
|
LPINT_ORDER_HEADER pOrderHeader;
|
|
|
|
DebugEntry(ASHost::SBCInitInternalOrders);
|
|
|
|
//
|
|
// Start with the bitmap bits order. Calculate the number of bytes
|
|
// required to store the bits for the largest bitmap bits order we will
|
|
// ever send. This includes room for the compression header which gets
|
|
// added before the bits if the data is compressed.
|
|
//
|
|
if (g_usrCaptureBPP >= 24)
|
|
{
|
|
// Can possibly send 24bpp TRUE COLOR data
|
|
m_sbcOrderInfo.bitmapBitsDataSize =
|
|
BYTES_IN_BITMAP(MP_LARGE_TILE_WIDTH, MP_LARGE_TILE_HEIGHT, 24)
|
|
+ sizeof(CD_HEADER);
|
|
}
|
|
else
|
|
{
|
|
// Can't send 24bpp TRUE color data
|
|
m_sbcOrderInfo.bitmapBitsDataSize =
|
|
BYTES_IN_BITMAP(MP_LARGE_TILE_WIDTH, MP_LARGE_TILE_WIDTH, 8)
|
|
+ sizeof(CD_HEADER);
|
|
}
|
|
|
|
//
|
|
// Now allocate memory for the bitmap bits order. The size required
|
|
// is:
|
|
// The size of an INT_ORDER_HEADER (this is added in by OA when you
|
|
// call OA_AllocOrderMem)
|
|
// + the size of the largest BMC_BITMAP_BITS_ORDER structure
|
|
// + the number of bytes required for the bitmap bits
|
|
// + contingency for RLE compression overruns !
|
|
//
|
|
orderSize = sizeof(INT_ORDER_HEADER)
|
|
+ sizeof(BMC_BITMAP_BITS_ORDER_R2)
|
|
+ m_sbcOrderInfo.bitmapBitsDataSize
|
|
+ 4;
|
|
|
|
TRACE_OUT(( "Allocating %d bytes for SBC bitmap bits order (bits %d)",
|
|
orderSize,
|
|
m_sbcOrderInfo.bitmapBitsDataSize));
|
|
|
|
m_sbcOrderInfo.pBitmapBitsOrder = (LPINT_ORDER)new BYTE[orderSize];
|
|
if (!m_sbcOrderInfo.pBitmapBitsOrder)
|
|
{
|
|
ERROR_OUT((
|
|
"Failed to alloc %d bytes for SBC bitmap bits order (bits %d)",
|
|
orderSize,
|
|
m_sbcOrderInfo.bitmapBitsDataSize));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Initialize the INT_ORDER_HEADER - this is normally done in
|
|
// OA_AllocOrderMem(). For the bitmap bits order, we can't fill in the
|
|
// orderLength because it is not a fixed size - this has to be done
|
|
// later when we fill in the bitmap bits. Note that the order length
|
|
// excludes the size of the INT_ORDER_HEADER.
|
|
//
|
|
pOrderHeader = &m_sbcOrderInfo.pBitmapBitsOrder->OrderHeader;
|
|
pOrderHeader->additionalOrderData = 0;
|
|
pOrderHeader->cbAdditionalOrderDataLength = 0;
|
|
|
|
//
|
|
// Now the color table order. The size required is:
|
|
// The size of an INT_ORDER_HEADER (this is added in by OA when you
|
|
// call OA_AllocOrderMem)
|
|
// + the size of a BMC_COLOR_TABLE_ORDER structure
|
|
// + the number of bytes required for the color table entries (note
|
|
// that the BMC_COLOR_TABLE_ORDER structure contains the first
|
|
// color table entry, so adjust the number of extra bytes required)
|
|
//
|
|
|
|
// Color tables are only for 8bpp and less.
|
|
orderSize = sizeof(INT_ORDER_HEADER)
|
|
+ sizeof(BMC_COLOR_TABLE_ORDER)
|
|
+ (COLORS_FOR_BPP(8) - 1) * sizeof(TSHR_RGBQUAD);
|
|
|
|
TRACE_OUT(( "Allocating %d bytes for SBC color table order", orderSize));
|
|
|
|
m_sbcOrderInfo.pColorTableOrder = (LPINT_ORDER)new BYTE[orderSize];
|
|
if (!m_sbcOrderInfo.pColorTableOrder)
|
|
{
|
|
ERROR_OUT(( "Failed to alloc %d bytes for SBC color table order",
|
|
orderSize));
|
|
DC_QUIT;
|
|
}
|
|
|
|
pOrderHeader = &m_sbcOrderInfo.pColorTableOrder->OrderHeader;
|
|
pOrderHeader->additionalOrderData = 0;
|
|
pOrderHeader->cbAdditionalOrderDataLength = 0;
|
|
pOrderHeader->Common.cbOrderDataLength = (WORD)(orderSize - sizeof(INT_ORDER_HEADER));
|
|
|
|
//
|
|
// Fill in the remaining fields in m_sbcOrderInfo
|
|
//
|
|
m_sbcOrderInfo.pOrder = NULL;
|
|
m_sbcOrderInfo.validData = FALSE;
|
|
m_sbcOrderInfo.sentColorTable = FALSE;
|
|
m_sbcOrderInfo.sentBitmapBits = FALSE;
|
|
m_sbcOrderInfo.sentMemBlt = FALSE;
|
|
|
|
//
|
|
// Must be OK to get to here
|
|
//
|
|
initOK = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitDWORD(ASHost::SBCInitInternalOrders, initOK);
|
|
return(initOK);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCFreeInternalOrders
|
|
//
|
|
// Purpose: Free up the internal orders used by SBC during MEMBLT order
|
|
// processing.
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: None
|
|
//
|
|
//
|
|
void ASHost::SBCFreeInternalOrders(void)
|
|
{
|
|
DebugEntry(ASHost::SBCFreeInternalOrders);
|
|
|
|
//
|
|
// First free up the memory.
|
|
//
|
|
if (m_sbcOrderInfo.pBitmapBitsOrder)
|
|
{
|
|
delete m_sbcOrderInfo.pBitmapBitsOrder;
|
|
m_sbcOrderInfo.pBitmapBitsOrder = NULL;
|
|
}
|
|
|
|
if (m_sbcOrderInfo.pColorTableOrder)
|
|
{
|
|
delete m_sbcOrderInfo.pColorTableOrder;
|
|
m_sbcOrderInfo.pColorTableOrder = NULL;
|
|
}
|
|
|
|
//
|
|
// Now reset the remaining fields in m_sbcOrderInfo
|
|
//
|
|
m_sbcOrderInfo.pOrder = NULL;
|
|
m_sbcOrderInfo.validData = FALSE;
|
|
m_sbcOrderInfo.sentColorTable = FALSE;
|
|
m_sbcOrderInfo.sentBitmapBits = FALSE;
|
|
m_sbcOrderInfo.bitmapBitsDataSize = 0;
|
|
|
|
DebugExitVOID(ASHost::SBCFreeInternalOrders);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCInitFastPath
|
|
//
|
|
// Purpose: Initialize the SBC fast path
|
|
//
|
|
// Returns: TRUE if successful, FALSE otherwise
|
|
//
|
|
// Params: None
|
|
//
|
|
//
|
|
BOOL ASHost::SBCInitFastPath(void)
|
|
{
|
|
BOOL rc = FALSE;
|
|
|
|
DebugEntry(ASHost::SBCInitFastPath);
|
|
|
|
m_sbcFastPath = new SBC_FASTPATH;
|
|
if (!m_sbcFastPath)
|
|
{
|
|
ERROR_OUT(("Failed to alloc m_sbcFastPath"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
SET_STAMP(m_sbcFastPath, SBCFASTPATH);
|
|
|
|
//
|
|
// Initialize the structure.
|
|
//
|
|
SBC_CacheCleared();
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(ASHost::SBCInitFastPath, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCGetTileData
|
|
//
|
|
// Purpose: Given the ID of a tile data entry in one of the SBC shunt
|
|
// buffers, return a pointer to the entry with that ID.
|
|
//
|
|
// Returns: TRUE if the entry is found, FALSE otherwise
|
|
//
|
|
// Params: IN tileId - The ID of the shunt buffer entry to be
|
|
// found.
|
|
// OUT ppTileData - A pointer to the start of the shunt buffer
|
|
// entry (if found)
|
|
// OUT pTileType - The type of shunt buffer entry found. One
|
|
// of:
|
|
// SBC_MEDIUM_TILE
|
|
// SBC_LARGE_TILE
|
|
//
|
|
//
|
|
BOOL ASHost::SBCGetTileData
|
|
(
|
|
UINT tileId,
|
|
LPSBC_TILE_DATA * ppTileData,
|
|
LPUINT pTileType
|
|
)
|
|
{
|
|
BOOL gotTileData = FALSE;
|
|
UINT workTile;
|
|
LPSBC_TILE_DATA pWorkTile;
|
|
|
|
DebugEntry(ASHost::SBCGetTileData);
|
|
|
|
TRACE_OUT(( "Looking for tile Id %x", tileId));
|
|
|
|
//
|
|
// Find out which of the shunt buffers the entry should be in.
|
|
//
|
|
*pTileType = SBC_TILE_TYPE(tileId);
|
|
|
|
//
|
|
// We implement the shunt buffers as circular FIFO queues, so in
|
|
// general, we are looking for the entry following the last one which
|
|
// we found. However, this wont always be the case because we do some
|
|
// out of order processing when we do spoiling.
|
|
//
|
|
// So, get the index of the last tile we accessed.
|
|
//
|
|
workTile = m_asbcWorkInfo[*pTileType].mruIndex;
|
|
|
|
//
|
|
// OK, so lets go for it ! Start at the tile following the last one we
|
|
// accessed, and loop through the circular buffer until we get a match,
|
|
// or have circled back to the beginning.
|
|
//
|
|
// Note that this has been coded as a "do while" loop, rather than just
|
|
// a "while" loop so that we don't miss mruTile.
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// On to the next tile
|
|
//
|
|
workTile++;
|
|
if (workTile == m_asbcWorkInfo[*pTileType].pShuntBuffer->numEntries)
|
|
{
|
|
workTile = 0;
|
|
}
|
|
|
|
pWorkTile = SBCTilePtrFromIndex(m_asbcWorkInfo[*pTileType].pShuntBuffer,
|
|
workTile);
|
|
|
|
if (pWorkTile->inUse)
|
|
{
|
|
if (pWorkTile->tileId == tileId)
|
|
{
|
|
//
|
|
// We've got a match.
|
|
//
|
|
TRACE_OUT(( "Matched tile Id %x at index %d",
|
|
tileId,
|
|
workTile));
|
|
*ppTileData = pWorkTile;
|
|
gotTileData = TRUE;
|
|
m_asbcWorkInfo[*pTileType].mruIndex = workTile;
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
}
|
|
while (workTile != m_asbcWorkInfo[*pTileType].mruIndex);
|
|
|
|
//
|
|
// If we get to here, we've not found a match.
|
|
//
|
|
TRACE_OUT(( "No match for tile Id %x", tileId));
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(ASHost::SBCGetTileData, gotTileData);
|
|
return(gotTileData);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCCacheColorTable
|
|
//
|
|
// Purpose: Ensure that the given color table is cached.
|
|
//
|
|
// Returns: TRUE if the color table is cached successfully, FALSE
|
|
// otherwise.
|
|
//
|
|
// Params: IN pOrder - A pointer to a color table order to be
|
|
// filled in.
|
|
// IN pColorTable - A pointer to the start of the color table
|
|
// to be cached.
|
|
// IN numColors - The number of colors in the color table.
|
|
// OUT pCacheIndex - The index of the cached color table.
|
|
// OUT pIsNewEntry - TRUE if we added a new cache entry,
|
|
// FALSE if we matched an existing entry.
|
|
//
|
|
// Operation: pOrder is only filled in if *pIsNewEntry is FALSE.
|
|
//
|
|
//
|
|
BOOL ASHost::SBCCacheColorTable
|
|
(
|
|
LPINT_ORDER pOrder,
|
|
LPTSHR_RGBQUAD pColorTable,
|
|
UINT numColors,
|
|
UINT * pCacheIndex,
|
|
LPBOOL pIsNewEntry
|
|
)
|
|
{
|
|
BOOL cachedOK = FALSE;
|
|
UINT cacheIndex;
|
|
PBMC_COLOR_TABLE_ORDER pColorTableOrder;
|
|
|
|
DebugEntry(ASHost::SBCCacheColorTable);
|
|
|
|
//
|
|
// Call PM to do the caching.
|
|
//
|
|
if (!PM_CacheTxColorTable(&cacheIndex,
|
|
pIsNewEntry,
|
|
numColors,
|
|
pColorTable))
|
|
{
|
|
ERROR_OUT(( "Failed to cache color table"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// If the cache operation resulted in a cache update then we have to
|
|
// fill in the color table order.
|
|
//
|
|
if (*pIsNewEntry)
|
|
{
|
|
//
|
|
// The color table is new so we have to transmit it
|
|
//
|
|
TRACE_OUT(( "New color table"));
|
|
|
|
pOrder->OrderHeader.Common.fOrderFlags = OF_PRIVATE;
|
|
pColorTableOrder = (PBMC_COLOR_TABLE_ORDER)(pOrder->abOrderData);
|
|
pColorTableOrder->bmcPacketType = BMC_PT_COLOR_TABLE;
|
|
pColorTableOrder->colorTableSize = (TSHR_UINT16)numColors;
|
|
pColorTableOrder->index = (BYTE)cacheIndex;
|
|
|
|
//
|
|
// Copy the new color table into the Order Packet.
|
|
//
|
|
memcpy(pColorTableOrder->data, pColorTable,
|
|
numColors * sizeof(TSHR_RGBQUAD));
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(( "Existing color table"));
|
|
}
|
|
|
|
//
|
|
// Return the color table index to the caller
|
|
//
|
|
*pCacheIndex = cacheIndex;
|
|
cachedOK = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(ASHost::SBCCacheColorTable, cachedOK);
|
|
return(cachedOK);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCCacheBits
|
|
//
|
|
// Purpose: This function adds the supplied bitmap bits to a bitmap
|
|
// cache. The cache selected depends on the bitmap size, but
|
|
// may be different for R1 and R2. SBCSelectCache handles the
|
|
// determination of the correct cache.
|
|
//
|
|
// Returns: TRUE if the bits have been cached OK, FALSE otherwise
|
|
//
|
|
// Params: IN pOrder - A pointer to a BMC order.
|
|
// IN destBitsSize - The number of bytes available in
|
|
// pOrder to store the bitmap data.
|
|
// IN pDIBits - A pointer to the bits to be cached.
|
|
// IN bitmapWidth - The "in use" width of the bitmap
|
|
// IN fixedBitmapWidth - The actual width of the bitmap
|
|
// IN bitmapHeight - The height of the bitmap
|
|
// IN numBytes - The number of bytes in the bitmap.
|
|
// OUT pCache - The cache that we put the bits into.
|
|
// OUT pCacheIndex - The cache index within *pCache at
|
|
// which we cached the data.
|
|
// OUT pIsNewEntry - TRUE if we added a new cache entry,
|
|
// FALSE if we matched an existing entry.
|
|
//
|
|
// Operation: pOrder is only filled in if *pIsNewEntry is FALSE.
|
|
//
|
|
//
|
|
BOOL ASHost::SBCCacheBits
|
|
(
|
|
LPINT_ORDER pOrder,
|
|
UINT destBitsSize,
|
|
LPBYTE pDIBits,
|
|
UINT bitmapWidth,
|
|
UINT fixedBitmapWidth,
|
|
UINT bitmapHeight,
|
|
UINT numBytes,
|
|
UINT * pCache,
|
|
UINT * pCacheIndex,
|
|
LPBOOL pIsNewEntry
|
|
)
|
|
{
|
|
BOOL cachedOK = FALSE;
|
|
UINT cacheIndex;
|
|
UINT i;
|
|
LPBYTE pCompressed;
|
|
UINT compressedSize;
|
|
BOOL compressed;
|
|
PBMC_DIB_ENTRY pEntry;
|
|
PBMC_DIB_CACHE pCacheHdr;
|
|
PBMC_BITMAP_BITS_ORDER_R2 pBitsOrderR2;
|
|
PBMC_BITMAP_BITS_DATA pBmcData;
|
|
LPBYTE pDestBits;
|
|
|
|
DebugEntry(ASHost::SBCCacheBits);
|
|
|
|
pBmcData = (PBMC_BITMAP_BITS_DATA)(pOrder->abOrderData);
|
|
pBitsOrderR2 = (PBMC_BITMAP_BITS_ORDER_R2)pBmcData;
|
|
|
|
//
|
|
// Get a pointer to where the bitmap data starts in the order. This
|
|
// depends on whether it is an R1 or an R2 bitmap bits order.
|
|
//
|
|
pDestBits = pBitsOrderR2->data;
|
|
|
|
//
|
|
// Before we can select a cache entry we need to compress the bits.
|
|
// This therefore mandates a memcpy into the cache entry when we come
|
|
// to add it. The saving in memory by storing the bits compressed
|
|
// makes it all worthwhile.
|
|
//
|
|
// Compress the bitmap data. At this stage we don't know whether the
|
|
// bitmap will compress well or not, so allow cells that are larger
|
|
// than our maximum cell size. The largest we expect to see is 120*120*
|
|
// 24.
|
|
//
|
|
compressedSize = destBitsSize;
|
|
if (m_pShare->BC_CompressBitmap(pDIBits, pDestBits, &compressedSize,
|
|
fixedBitmapWidth, bitmapHeight, m_usrSendingBPP,
|
|
NULL ) &&
|
|
(compressedSize < numBytes))
|
|
|
|
{
|
|
TRACE_OUT(( "Compressed bmp data from %u bytes to %u bytes",
|
|
numBytes,
|
|
compressedSize));
|
|
compressed = TRUE;
|
|
pCompressed = pDestBits;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The bitmap could not be compressed, or bitmap compression is not
|
|
// enabled. Send the bitmap uncompressed.
|
|
//
|
|
compressed = FALSE;
|
|
compressedSize = numBytes;
|
|
pCompressed = pDIBits;
|
|
}
|
|
|
|
//
|
|
// Make sure that the data will fit into the order. Do this after
|
|
// compression since it is possible that the uncompressed data will not
|
|
// fit, but the compressed version will.
|
|
//
|
|
if (compressedSize > destBitsSize)
|
|
{
|
|
WARNING_OUT(( "Data (%d bytes) does not fit into order (%d bytes)",
|
|
compressedSize,
|
|
destBitsSize));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Select the cache based on the compressed size - we pass in the
|
|
// sub-bitmap dimensions for R1 caching; R2 caching just uses the
|
|
// total size of the bits.
|
|
//
|
|
if (!SBCSelectCache(compressedSize + sizeof(BMC_DIB_ENTRY) - 1, pCache))
|
|
{
|
|
TRACE_OUT(( "No cache selected"));
|
|
DC_QUIT;
|
|
}
|
|
else
|
|
{
|
|
TRACE_OUT(( "Selected cache %d", *pCache));
|
|
}
|
|
|
|
//
|
|
// Find a free cache entry in our selected cache
|
|
//
|
|
// We arrange that our transmit cache is always one greater than the
|
|
// negotiated cache size so that we should never fail to find a free
|
|
// array entry. Once we have fully populated our Tx cache we will
|
|
// always find the free entry as the one last given back to us by CH.
|
|
// Note the scan to <= sbcTxCache[pmNumTxCacheEntries is NOT a mistake.
|
|
//
|
|
pCacheHdr = &(m_asbcBmpCaches[*pCache]);
|
|
if (pCacheHdr->data == NULL)
|
|
{
|
|
ERROR_OUT(( "Asked to cache when no cache allocated"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// If the cache has returned an entry to us then use that without
|
|
// having to scan. This will be the default mode for adding entries
|
|
// to a fully populated cache.
|
|
//
|
|
if (pCacheHdr->freeEntry != NULL)
|
|
{
|
|
pEntry = pCacheHdr->freeEntry;
|
|
pCacheHdr->freeEntry = NULL;
|
|
TRACE_OUT(( "Cache fully populated - using entry 0x%08x", pEntry));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are in the process of feeding the cache so we need to search
|
|
// for a free entry
|
|
//
|
|
pEntry = (PBMC_DIB_ENTRY)(pCacheHdr->data);
|
|
for (i=0 ; i < pCacheHdr->cEntries ; i++)
|
|
{
|
|
if (!pEntry->inUse)
|
|
{
|
|
break;
|
|
}
|
|
pEntry = (PBMC_DIB_ENTRY)(((LPBYTE)pEntry) + pCacheHdr->cSize);
|
|
}
|
|
|
|
//
|
|
// We should never run out of free entries, but cope with it
|
|
//
|
|
if (i == pCacheHdr->cEntries)
|
|
{
|
|
ERROR_OUT(( "All Tx DIB cache entries in use"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set up the DIB entry for caching
|
|
//
|
|
pEntry->inUse = TRUE;
|
|
pEntry->cx = (TSHR_UINT16)bitmapWidth;
|
|
pEntry->cxFixed = (TSHR_UINT16)fixedBitmapWidth;
|
|
pEntry->cy = (TSHR_UINT16)bitmapHeight;
|
|
pEntry->bpp = (TSHR_UINT16)m_usrSendingBPP;
|
|
pEntry->cBits = numBytes;
|
|
pEntry->bCompressed = (BYTE)compressed;
|
|
pEntry->cCompressed = compressedSize;
|
|
memcpy(pEntry->bits, pCompressed, compressedSize);
|
|
|
|
//
|
|
// Now cache the data
|
|
//
|
|
if (CH_SearchAndCacheData(pCacheHdr->handle,
|
|
(LPBYTE)pEntry,
|
|
sizeof(BMC_DIB_ENTRY) + compressedSize - 1,
|
|
0,
|
|
&cacheIndex))
|
|
{
|
|
//
|
|
// The sub-bitmap is already in the cache
|
|
//
|
|
*pCacheIndex = cacheIndex;
|
|
TRACE_OUT(( "Bitmap already cached %u:%u cx(%d) cy(%d)",
|
|
*pCache,
|
|
*pCacheIndex,
|
|
bitmapWidth,
|
|
bitmapHeight));
|
|
*pIsNewEntry = FALSE;
|
|
|
|
//
|
|
// Free up the entry we just created
|
|
//
|
|
pEntry->inUse = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*pCacheIndex = cacheIndex;
|
|
TRACE_OUT(( "Cache entry at 0x%08x now in use", pEntry));
|
|
TRACE_OUT(( "New cache entry %u:%u cx(%d) cy(%d)",
|
|
*pCache,
|
|
*pCacheIndex,
|
|
bitmapWidth,
|
|
bitmapHeight));
|
|
*pIsNewEntry = TRUE;
|
|
pEntry->iCacheIndex = (TSHR_UINT16)*pCacheIndex;
|
|
}
|
|
|
|
//
|
|
// We've got the bits into the cache. If the cache attempt added a
|
|
// cache entry we must fill in the bitmap cache order.
|
|
//
|
|
if (*pIsNewEntry)
|
|
{
|
|
//
|
|
// Fill in the order details.
|
|
//
|
|
// Remember that we have to fill in the order size into the
|
|
// INT_ORDER_HEADER as well as filling in the bitmap bits order
|
|
// header. When doing this, adjust for the number of bitmap bits
|
|
// which are included in the bitmap bits order header.
|
|
//
|
|
pOrder->OrderHeader.Common.fOrderFlags = OF_PRIVATE;
|
|
|
|
if (compressed)
|
|
{
|
|
pBmcData->bmcPacketType = BMC_PT_BITMAP_BITS_COMPRESSED;
|
|
}
|
|
else
|
|
{
|
|
pBmcData->bmcPacketType = BMC_PT_BITMAP_BITS_UNCOMPRESSED;
|
|
|
|
//
|
|
// The data is not compressed, so copy the uncompressed data
|
|
// into the order. In the case where we compressed the data
|
|
// successfully, we did so directly into the order, so the
|
|
// compressed bits are already there.
|
|
//
|
|
memcpy(pDestBits, pDIBits, compressedSize);
|
|
}
|
|
|
|
pBmcData->cacheID = (BYTE)*pCache;
|
|
pBmcData->cxSubBitmapWidth = (TSHR_UINT8)fixedBitmapWidth;
|
|
pBmcData->cySubBitmapHeight = (TSHR_UINT8)bitmapHeight;
|
|
pBmcData->bpp = (TSHR_UINT8)m_usrSendingBPP;
|
|
pBmcData->cbBitmapBits = (TSHR_UINT16)compressedSize;
|
|
|
|
//
|
|
// The iCacheEntryR1 field is unused for R2 - we use
|
|
// iCacheEntryR2 instead.
|
|
//
|
|
pBmcData->iCacheEntryR1 = 0;
|
|
pBitsOrderR2->iCacheEntryR2 = (TSHR_UINT16)*pCacheIndex;
|
|
|
|
pOrder->OrderHeader.Common.cbOrderDataLength =
|
|
(compressedSize
|
|
+ sizeof(BMC_BITMAP_BITS_ORDER_R2)
|
|
- sizeof(pBitsOrderR2->data));
|
|
}
|
|
|
|
cachedOK = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(ASHost::SBCCacheBits, cachedOK);
|
|
return(cachedOK);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCAddToFastPath
|
|
//
|
|
// Purpose: Add a bitmap to the fast path
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// Params: IN majorInfo - The major caching info passed up from
|
|
// the driver (the bitmap ID)
|
|
// IN minorInfo - The minor caching info passed up from
|
|
// the driver (the bitmap revision number)
|
|
// IN majorPalette - The major palette info passed up from
|
|
// the driver (the XLATEOBJ)
|
|
// IN minorPalette - The minor palette info passed up from
|
|
// the driver (the XLATEOBJ iUniq)
|
|
// IN srcX - The x coord of the source of the Blt
|
|
// IN srcY - The y coord of the source of the Blt
|
|
// IN width - The width of the area being Blted
|
|
// IN height - The height of the area being Blted
|
|
// IN cache - The cache the bits were placed in
|
|
// IN cacheIndex - The index at which the bits were placed
|
|
// in the cache
|
|
// IN colorCacheIndex - The index in the color table cache of
|
|
// the color table associated with the bits
|
|
//
|
|
//
|
|
void ASHost::SBCAddToFastPath
|
|
(
|
|
UINT_PTR majorInfo,
|
|
UINT minorInfo,
|
|
UINT_PTR majorPalette,
|
|
UINT minorPalette,
|
|
int srcX,
|
|
int srcY,
|
|
UINT width,
|
|
UINT height,
|
|
UINT cache,
|
|
UINT cacheIndex,
|
|
UINT colorCacheIndex
|
|
)
|
|
{
|
|
LPSBC_FASTPATH_ENTRY pEntry;
|
|
|
|
DebugEntry(ASHost::SBCAddToFastPath);
|
|
|
|
//
|
|
// First get a free entry
|
|
//
|
|
pEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListFirst(&m_sbcFastPath->freeList,
|
|
FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
if (pEntry == NULL)
|
|
{
|
|
//
|
|
// There are no entries in the free list, so we have to use the
|
|
// oldest entry in the used list. The used list is stored in MRU
|
|
// order, so we just have to get the last item in the list.
|
|
//
|
|
pEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListLast(&m_sbcFastPath->usedList,
|
|
FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
TRACE_OUT(( "Evicting fast path info for %x %x (%d, %d)",
|
|
pEntry->majorInfo,
|
|
pEntry->minorInfo,
|
|
pEntry->srcX,
|
|
pEntry->srcY));
|
|
}
|
|
|
|
//
|
|
// Remove the entry from its current list
|
|
//
|
|
COM_BasedListRemove(&pEntry->list);
|
|
|
|
//
|
|
// Now fill in the details
|
|
//
|
|
pEntry->majorInfo = majorInfo;
|
|
pEntry->minorInfo = minorInfo;
|
|
pEntry->majorPalette = majorPalette;
|
|
pEntry->minorPalette = minorPalette;
|
|
pEntry->srcX = srcX;
|
|
pEntry->srcY = srcY;
|
|
pEntry->width = width;
|
|
pEntry->height = height;
|
|
pEntry->cache = (WORD)cache;
|
|
pEntry->cacheIndex = (WORD)cacheIndex;
|
|
pEntry->colorIndex = (WORD)colorCacheIndex;
|
|
|
|
//
|
|
// Finally, add the entry to the front of the used list
|
|
//
|
|
TRACE_OUT(( "Adding fast path info for %x %x (%d, %d)",
|
|
pEntry->majorInfo,
|
|
pEntry->minorInfo,
|
|
pEntry->srcX,
|
|
pEntry->srcY));
|
|
COM_BasedListInsertAfter(&m_sbcFastPath->usedList, &pEntry->list);
|
|
|
|
DebugExitVOID(ASHost::SBCAddToFastPath);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
// Name: SBCFindInFastPath
|
|
//
|
|
// Purpose: Check to see if a bitmap with the given attributes is in the
|
|
// SBC fast path. If so, return the cache info for the bitmap.
|
|
//
|
|
// Returns: TRUE if the bitmap is in the fast path, FALSE if not.
|
|
//
|
|
// Params: IN majorInfo - The major caching info passed up from
|
|
// the driver (the bitmap ID)
|
|
// IN minorInfo - The minor caching info passed up from
|
|
// the driver (the bitmap revision
|
|
// number)
|
|
// IN majorPalette - The major palette info passed up from
|
|
// the driver (the XLATEOBJ)
|
|
// IN minorPalette - The minor palette info passed up from
|
|
// the driver (the XLATEOBJ iUniq)
|
|
// IN srcX - The x coord of the source of the Blt
|
|
// IN srcY - The y coord of the source of the Blt
|
|
// IN width - The width of the area being Blted
|
|
// IN height - The height of the area being Blted
|
|
// OUT pCache - The cache the bits were placed in
|
|
// OUT pCacheIndex - The index at which the bits were
|
|
// placed in the cache
|
|
// OUT pColorCacheIndex - The index in the color table cache of
|
|
// the color table associated with the
|
|
// bits
|
|
//
|
|
// Operation: The contents of pCache, pCacheIndex and pColorCacheIndex
|
|
// are only valid on return if the function returns TRUE.
|
|
//
|
|
//
|
|
BOOL ASHost::SBCFindInFastPath
|
|
(
|
|
UINT_PTR majorInfo,
|
|
UINT minorInfo,
|
|
UINT_PTR majorPalette,
|
|
UINT minorPalette,
|
|
int srcX,
|
|
int srcY,
|
|
UINT width,
|
|
UINT height,
|
|
UINT * pCache,
|
|
UINT * pCacheIndex,
|
|
UINT * pColorCacheIndex
|
|
)
|
|
{
|
|
BOOL found = FALSE;
|
|
LPSBC_FASTPATH_ENTRY pEntry;
|
|
LPSBC_FASTPATH_ENTRY pNextEntry;
|
|
|
|
DebugEntry(ASHost::SBCFindInFastPath);
|
|
|
|
//
|
|
// Traverse the in use list looking for a match on the parameters
|
|
// passed in.
|
|
//
|
|
pEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListFirst(&m_sbcFastPath->usedList, FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
while (pEntry != NULL)
|
|
{
|
|
if ((pEntry->majorInfo == majorInfo) &&
|
|
(pEntry->minorInfo == minorInfo) &&
|
|
(pEntry->majorPalette == majorPalette) &&
|
|
(pEntry->minorPalette == minorPalette) &&
|
|
(pEntry->srcX == srcX) &&
|
|
(pEntry->srcY == srcY) &&
|
|
(pEntry->width == width) &&
|
|
(pEntry->height == height))
|
|
{
|
|
//
|
|
// We've found a match - hurrah ! Fill in the return info.
|
|
//
|
|
TRACE_OUT(( "Hit for %x %x (%d, %d) cache %d",
|
|
pEntry->majorInfo,
|
|
pEntry->minorInfo,
|
|
pEntry->srcX,
|
|
pEntry->srcY,
|
|
pEntry->cache,
|
|
pEntry->cacheIndex));
|
|
|
|
found = TRUE;
|
|
*pCache = pEntry->cache;
|
|
*pCacheIndex = pEntry->cacheIndex;
|
|
*pColorCacheIndex = pEntry->colorIndex;
|
|
|
|
//
|
|
// We order the used list in MRU order, so remove the entry
|
|
// from its current position and add it at the head of the used
|
|
// list.
|
|
//
|
|
COM_BasedListRemove(&pEntry->list);
|
|
COM_BasedListInsertAfter(&m_sbcFastPath->usedList, &pEntry->list);
|
|
|
|
//
|
|
// Got a match, so we can break out of the while loop
|
|
//
|
|
break;
|
|
}
|
|
else if ((pEntry->majorInfo == majorInfo) &&
|
|
(pEntry->minorInfo != minorInfo))
|
|
{
|
|
//
|
|
// We have been given a bitmap which we have seen before, but
|
|
// the revision number has changed i.e. the bitmap has been
|
|
// updated (majorInfo identifies the bitmap, and minorInfo
|
|
// identifies the revision number of that bitmap - it is
|
|
// incremented every time the bitmap is changed).
|
|
//
|
|
// We have to remove all entries from the used list which
|
|
// reference this bitmap. We can start from the current
|
|
// position since we know that we can't have an entry for this
|
|
// bitmap earlier in the list, but we have to be careful to get
|
|
// the next entry in the list before removing an entry.
|
|
//
|
|
TRACE_OUT(( "Bitmap %x updated - removing references",
|
|
pEntry->majorInfo));
|
|
pNextEntry = pEntry;
|
|
|
|
while (pNextEntry != NULL)
|
|
{
|
|
pEntry = pNextEntry;
|
|
|
|
pNextEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListNext(&m_sbcFastPath->usedList,
|
|
pNextEntry, FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
|
|
if (pEntry->majorInfo == majorInfo)
|
|
{
|
|
COM_BasedListRemove(&pEntry->list);
|
|
COM_BasedListInsertAfter(&m_sbcFastPath->freeList,
|
|
&pEntry->list);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We know we wont find a match, so we can break out of the
|
|
// while loop
|
|
//
|
|
break;
|
|
}
|
|
|
|
pEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListNext(&m_sbcFastPath->usedList, pEntry,
|
|
FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
}
|
|
|
|
DebugExitBOOL(ASShare::SBCFindInFastPath, found);
|
|
return(found);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// SBC_CacheEntryRemoved()
|
|
//
|
|
void ASHost::SBC_CacheEntryRemoved
|
|
(
|
|
UINT cache,
|
|
UINT cacheIndex
|
|
)
|
|
{
|
|
LPSBC_FASTPATH_ENTRY pEntry;
|
|
LPSBC_FASTPATH_ENTRY pNextEntry;
|
|
|
|
DebugEntry(ASHost::SBC_CacheEntryRemoved);
|
|
|
|
ASSERT(m_sbcFastPath);
|
|
|
|
//
|
|
// An entry has been removed from the cache. If we have this entry in
|
|
// our fast path, we have to remove it.
|
|
//
|
|
// Just traverse the used list looking for an entry with matching cache
|
|
// and cacheIndex. Note that there may be more than one entry - if the
|
|
// source bitmap has a repeating image, we will get a match on the bits
|
|
// when we cache different areas of the bitmap.
|
|
//
|
|
pNextEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListFirst(&m_sbcFastPath->usedList,
|
|
FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
while (pNextEntry != NULL)
|
|
{
|
|
pEntry = pNextEntry;
|
|
|
|
pNextEntry = (LPSBC_FASTPATH_ENTRY)COM_BasedListNext(&m_sbcFastPath->usedList,
|
|
pNextEntry, FIELD_OFFSET(SBC_FASTPATH_ENTRY, list));
|
|
|
|
if ((pEntry->cache == cache) && (pEntry->cacheIndex == cacheIndex))
|
|
{
|
|
//
|
|
// Move the entry to the free list
|
|
//
|
|
TRACE_OUT(("Fast path entry %x %x (%d, %d) evicted from cache",
|
|
pEntry->majorInfo,
|
|
pEntry->minorInfo,
|
|
pEntry->srcX,
|
|
pEntry->srcY));
|
|
COM_BasedListRemove(&pEntry->list);
|
|
COM_BasedListInsertAfter(&m_sbcFastPath->freeList,
|
|
&pEntry->list);
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(ASHost::SBC_CacheEntryRemoved);
|
|
}
|