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.
2644 lines
99 KiB
2644 lines
99 KiB
/****************************************************************************/
|
|
// nsbcdisp.c
|
|
//
|
|
// RDP Send Bitmap Cache display driver code
|
|
//
|
|
// Copyright (C) 1997-2000 Microsoft Corporation
|
|
/****************************************************************************/
|
|
|
|
#include <precmpdd.h>
|
|
#define hdrstop
|
|
|
|
#define TRC_FILE "nsbcdisp"
|
|
#include <adcg.h>
|
|
#include <atrcapi.h>
|
|
|
|
#define DC_INCLUDE_DATA
|
|
#include <ndddata.c>
|
|
#include <noedata.c>
|
|
#undef DC_INCLUDE_DATA
|
|
|
|
#include <asbcapi.h>
|
|
#include <nsbcdisp.h>
|
|
#include <noadisp.h>
|
|
#include <abcapi.h>
|
|
#include <nprcount.h>
|
|
#include <nschdisp.h>
|
|
#include <nchdisp.h>
|
|
#include <noedisp.h>
|
|
|
|
#include <nsbcinl.h>
|
|
|
|
#include <nsbcddat.c>
|
|
|
|
|
|
#ifdef DC_DEBUG
|
|
BOOL SBC_VerifyBitmapBits(PBYTE pBitmapData, unsigned cbBitmapSize, UINT iCacheID, UINT iCacheIndex);
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBC_DDInit: SBC display driver initialization function.
|
|
/****************************************************************************/
|
|
void RDPCALL SBC_DDInit(PDD_PDEV pPDev)
|
|
{
|
|
DC_BEGIN_FN("SBC_DDInit");
|
|
|
|
// Initializes all the global data for this component.
|
|
#define DC_INIT_DATA
|
|
#include <nsbcddat.c>
|
|
#undef DC_INIT_DATA
|
|
|
|
#ifndef DC_HICOLOR
|
|
sbcClientBitsPerPel = pPDev->cClientBitsPerPel;
|
|
#endif
|
|
|
|
TRC_NRM((TB, "Completed SBC_DDInit"));
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBC_InitShm(): Inits the SBC shm component on connect/reconnect.
|
|
/****************************************************************************/
|
|
void RDPCALL SBC_InitShm(void)
|
|
{
|
|
DC_BEGIN_FN("SBC_InitShm");
|
|
|
|
// Zero only the parts which need to be zeroed.
|
|
memset(&pddShm->sbc, 0, sizeof(SBC_SHARED_DATA));
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCProcessBitmapKeyDatabase
|
|
//
|
|
// Given persistent bitmap key database, populates caches.
|
|
/****************************************************************************/
|
|
__inline void RDPCALL SBCProcessBitmapKeyDatabase(
|
|
SBC_BITMAP_CACHE_KEY_INFO *pKeyDatabase)
|
|
{
|
|
unsigned i, j;
|
|
|
|
#ifdef DC_DEBUG
|
|
unsigned BitmapHdrSize;
|
|
SBC_BITMAP_CACHE_EXTRA_INFO *pBitmapHdr;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("SBCProcessBitmapKeyDatabase");
|
|
|
|
// This call should not be made if the database ptr is NULL.
|
|
TRC_ASSERT((pKeyDatabase != NULL), (TB,"NULL pKeyDatabase"));
|
|
|
|
for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++) {
|
|
|
|
TRC_NRM((TB,"Cache %d: %d keys", i, pKeyDatabase->NumKeys[i]));
|
|
|
|
// Place each persistent key in its corresponding index
|
|
// in the cache. Note that the MRU sequence is implicit in the
|
|
// order in the database -- CH_ForceCacheKeyAtIndex() appends the
|
|
// entry to the MRU.
|
|
for (j = 0; j < pKeyDatabase->NumKeys[i]; j++) {
|
|
if ((&(pKeyDatabase->Keys[pKeyDatabase->KeyStart[i]]))[j].Key1 !=
|
|
TS_BITMAPCACHE_NULL_KEY ||
|
|
(&(pKeyDatabase->Keys[pKeyDatabase->KeyStart[i]]))[j].Key2 !=
|
|
TS_BITMAPCACHE_NULL_KEY) {
|
|
|
|
#ifdef DC_DEBUG
|
|
// We have no cache bits, so set the header data size to zero
|
|
// on debug.
|
|
BitmapHdrSize = sizeof(SBC_BITMAP_CACHE_EXTRA_INFO) +
|
|
SBC_CellSizeFromCacheID(i);
|
|
if (pddShm->sbc.bitmapCacheInfo[i].pExtraEntryInfo != NULL) {
|
|
pBitmapHdr = (SBC_BITMAP_CACHE_EXTRA_INFO *)(pddShm->sbc.
|
|
bitmapCacheInfo[i].pExtraEntryInfo +
|
|
(&(pKeyDatabase->Keys[pKeyDatabase->KeyStart[i]]))[j].CacheIndex *
|
|
BitmapHdrSize);
|
|
pBitmapHdr->DataSize = 0;
|
|
}
|
|
#endif
|
|
|
|
// We have to set the UserDefined to NULL since we have no
|
|
// associated fast-path cache entry pointer.
|
|
CH_ForceCacheKeyAtIndex(
|
|
pddShm->sbc.bitmapCacheInfo[i].cacheHandle,
|
|
(&(pKeyDatabase->Keys[pKeyDatabase->KeyStart[i]]))[j].CacheIndex,
|
|
(&(pKeyDatabase->Keys[pKeyDatabase->KeyStart[i]]))[j].Key1,
|
|
(&(pKeyDatabase->Keys[pKeyDatabase->KeyStart[i]]))[j].Key2,
|
|
NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCAllocBitmapCache; Allocates bitmap cache data buffers according to the
|
|
// current negotiated capabilities.
|
|
//
|
|
// Returns: SBC_BITMAP_CACHE_ENABLED if successful, 0 otherwise.
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SBCAllocBitmapCache(PCHCACHEHANDLE pCacheHandle)
|
|
{
|
|
SIZEL TileSize;
|
|
BOOLEAN rc;
|
|
unsigned i, j;
|
|
unsigned TotalCacheEntries;
|
|
unsigned iFormat;
|
|
PSBC_BITMAP_CACHE_INFO pInfo;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
#if DC_DEBUG
|
|
unsigned BitmapHdrSize;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("SBCAllocBitmapCache");
|
|
|
|
TRC_NRM((TB, "Alloc bitmap cache data and work bitmaps"));
|
|
|
|
rc = FALSE;
|
|
i = j = 0;
|
|
|
|
// Cell caching is disabled if NumCellCaches is zero. It is set to
|
|
// zero by the WD caps negotiation code if the client indicated zero,
|
|
// if any of the requested cell cache NumEntries is zero, or if the rev1
|
|
// caps returned a CacheNMaximumCellSize that was not the required tile
|
|
// size.
|
|
if (pddShm->sbc.NumBitmapCaches > 0) {
|
|
// Work tile bitmap format type, and translation buffer for 4bpp to
|
|
// 8bpp conversions. The translation buffer must be as large as the
|
|
// largest tile size.
|
|
if (sbcClientBitsPerPel != 4) {
|
|
#ifdef DC_HICOLOR
|
|
if (sbcClientBitsPerPel == 24)
|
|
{
|
|
iFormat = BMF_24BPP;
|
|
}
|
|
else if ((sbcClientBitsPerPel == 16) || (sbcClientBitsPerPel == 15))
|
|
{
|
|
iFormat = BMF_16BPP;
|
|
}
|
|
else
|
|
{
|
|
iFormat = BMF_8BPP;
|
|
}
|
|
#else
|
|
iFormat = BMF_8BPP;
|
|
#endif
|
|
}
|
|
else {
|
|
iFormat = BMF_4BPP;
|
|
sbcXlateBuf = EngAllocMem(0, SBC_CellSizeFromCacheID(
|
|
pddShm->sbc.NumBitmapCaches - 1), DD_ALLOC_TAG);
|
|
if (sbcXlateBuf == NULL) {
|
|
TRC_ERR((TB,"Failed to create 4bpp to 8bpp translate buf"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
TotalCacheEntries = 0;
|
|
|
|
for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++) {
|
|
pInfo = &(pddShm->sbc.bitmapCacheInfo[i]);
|
|
|
|
// Create a square work tile bitmap.
|
|
// We set the last parameter to NULL, to allow GDI to allocate
|
|
// memory for the bits. We can get a pointer to the bits later
|
|
// when we have a SURFOBJ for the bitmap.
|
|
TileSize.cx = TileSize.cy = (SBC_CACHE_0_DIMENSION << i);
|
|
pddShm->sbc.bitmapCacheInfo[i].hWorkBitmap = (HSURF)
|
|
EngCreateBitmap(TileSize,
|
|
TS_BYTES_IN_SCANLINE(TileSize.cx, sbcClientBitsPerPel),
|
|
iFormat, 0, NULL);
|
|
if (pddShm->sbc.bitmapCacheInfo[i].hWorkBitmap == NULL) {
|
|
TRC_ERR((TB, "Failed to create work bitmap %d", i));
|
|
DC_QUIT;
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
// Alloc set of SBC_BITMAP_DATA_HEADERs and space for bitmap
|
|
// bits to be kept for comparison in debug builds.
|
|
BitmapHdrSize = sizeof(SBC_BITMAP_CACHE_EXTRA_INFO) +
|
|
SBC_CellSizeFromCacheID(i);
|
|
pInfo->pExtraEntryInfo = EngAllocMem(0,
|
|
pInfo->Info.NumEntries * BitmapHdrSize, DD_ALLOC_TAG);
|
|
// If persistent cache is enabled and in high-color, we will ask for big memory (~20MB)
|
|
// from session space and memory allocation will fail.
|
|
// We don't quit here if memory allocation fails since this memory is only for
|
|
// comparison use in debug build. We'll check the NULL pointer in every usage of this memory (not many)
|
|
if (pInfo->pExtraEntryInfo == NULL) {
|
|
TRC_ERR((TB, "Failed to alloc save-bitmap-data memory "
|
|
"(cell cache %u)", i));
|
|
//DC_QUIT;
|
|
}
|
|
#endif
|
|
|
|
// We create the bitmap caches with their indices (cache IDs) in
|
|
// the pContext value so we can backtrack the cache ID when
|
|
// using the fast-path cache.
|
|
if (pInfo->Info.NumEntries) {
|
|
pCacheData = (PCHCACHEDATA)(*pCacheHandle);
|
|
|
|
// Bitmap cache list handle
|
|
CH_InitCache(pCacheData, pInfo->Info.NumEntries,
|
|
(void *)ULongToPtr(i), TRUE, FALSE, SBCBitmapCacheCallback);
|
|
|
|
pInfo->cacheHandle = pCacheData;
|
|
|
|
(BYTE *)(*pCacheHandle) += CH_CalculateCacheSize(
|
|
pInfo->Info.NumEntries);
|
|
|
|
TRC_NRM((TB, "Created cell cache %u: hCache=%p, NumEntries=%u", i,
|
|
pInfo->cacheHandle, pInfo->Info.NumEntries));
|
|
|
|
TotalCacheEntries += pInfo->Info.NumEntries;
|
|
|
|
// Waiting list cache handle
|
|
if (pddShm->sbc.fAllowCacheWaitingList) {
|
|
pCacheData = (PCHCACHEDATA)(*pCacheHandle);
|
|
|
|
CH_InitCache(pCacheData, pInfo->Info.NumEntries,
|
|
(void *)ULongToPtr(i), FALSE, FALSE, NULL);
|
|
|
|
pInfo->waitingListHandle = pCacheData;
|
|
|
|
(BYTE *)(*pCacheHandle) += CH_CalculateCacheSize(
|
|
pInfo->Info.NumEntries);
|
|
}
|
|
else {
|
|
pInfo->waitingListHandle = NULL;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Zero entry Cache %d", i));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
// Allocate fast path cache.
|
|
pCacheData = (PCHCACHEDATA)(*pCacheHandle);
|
|
CH_InitCache(pCacheData, TotalCacheEntries,
|
|
NULL, TRUE, FALSE, SBCFastPathCacheCallback);
|
|
|
|
pddShm->sbc.hFastPathCache = pCacheData;
|
|
|
|
TRC_NRM((TB, "Fast Path Cache created(%p) entries(%u)",
|
|
pddShm->sbc.hFastPathCache, TotalCacheEntries));
|
|
|
|
(BYTE*)(*pCacheHandle) += CH_CalculateCacheSize(TotalCacheEntries);
|
|
|
|
//
|
|
// Color table cache is only required for lo color sessions
|
|
// But we need to allocate for shadow case, when a 256 color
|
|
// client shadows a high color client or console.
|
|
//
|
|
|
|
// Allocate color table cache. This is required for bitmap caching.
|
|
pCacheData = (PCHCACHEDATA)(*pCacheHandle);
|
|
|
|
CH_InitCache(pCacheData,
|
|
SBC_NUM_COLOR_TABLE_CACHE_ENTRIES, NULL, FALSE, FALSE, NULL);
|
|
|
|
sbcColorTableCacheHandle = pCacheData;
|
|
|
|
(BYTE *)(*pCacheHandle) += CH_CalculateCacheSize(
|
|
SBC_NUM_COLOR_TABLE_CACHE_ENTRIES);
|
|
|
|
//
|
|
// This is only needed for 256 client case.
|
|
//
|
|
if (sbcClientBitsPerPel <= 8)
|
|
{
|
|
|
|
// Make sure we send a first color table to the client. This is important
|
|
// to do here because on a server-initiated sync we no longer force
|
|
// the color table to be sent again to save bandwidth. On 8-bit clients
|
|
// this is not a problem since the palette is always set with
|
|
// DrvSetPalette. However, on 4-bit clients, the client's color tables
|
|
// are never initialized until we send one across.
|
|
sbcPaletteChanged = TRUE;
|
|
}
|
|
|
|
rc = TRUE;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
// If we failed to allocate some or all of the required resources then
|
|
// free up any that we did allocate before we return the failure code.
|
|
if (rc == FALSE) {
|
|
SBCFreeBitmapCacheData();
|
|
|
|
// Don't waste space for bitmap cache. back it up
|
|
for (j = 0; j < i; j++) {
|
|
pInfo = &(pddShm->sbc.bitmapCacheInfo[j]);
|
|
|
|
(BYTE *)(*pCacheHandle) -= CH_CalculateCacheSize(
|
|
pInfo->Info.NumEntries);
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return (rc ? SBC_BITMAP_CACHE_ENABLED : 0);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCCreateGlyphCache
|
|
//
|
|
// Creates a single bitmap cache of a given size. Returns FALSE on failure.
|
|
/****************************************************************************/
|
|
__inline BOOLEAN RDPCALL SBCCreateGlyphCache(
|
|
unsigned cEntries,
|
|
unsigned cbCellSize,
|
|
PCHCACHEDATA pCacheData)
|
|
{
|
|
BOOLEAN rc;
|
|
|
|
DC_BEGIN_FN("SBC_CreateGlyphCache");
|
|
|
|
if (cEntries != 0 && cbCellSize != 0) {
|
|
// Allocate glyph cache.
|
|
CH_InitCache(pCacheData, cEntries, NULL, FALSE, TRUE,
|
|
SBCGlyphCallback);
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Zero: cEntries(%u) cbCellSize(%u)", cEntries,
|
|
cbCellSize));
|
|
rc = FALSE;
|
|
}
|
|
|
|
TRC_NRM((TB, "Created glyph cache: pCacheData(%p), cEntries(%u) "
|
|
"cbCellSize(%u)", pCacheData, cEntries, cbCellSize));
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCCreateFragCache
|
|
//
|
|
// Creates a single bitmap cache of a given size. Returns FALSE on failure.
|
|
/****************************************************************************/
|
|
__inline BOOLEAN RDPCALL SBCCreateFragCache(
|
|
unsigned cEntries,
|
|
unsigned cbCellSize,
|
|
PCHCACHEDATA pCacheData)
|
|
{
|
|
BOOLEAN rc;
|
|
|
|
DC_BEGIN_FN("SBCCreateFragCache");
|
|
|
|
if (cEntries != 0 && cbCellSize != 0) {
|
|
CH_InitCache(pCacheData, cEntries, NULL, FALSE, FALSE, NULL);
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, "Zero: cEntries(%u) cbCellSize(%u)", cEntries,
|
|
cbCellSize));
|
|
rc = FALSE;
|
|
}
|
|
|
|
TRC_NRM((TB, "Created frag cache: pCacheData(%p), cEntries(%u) "
|
|
"cbCellSize(%u)", pCacheData, cEntries, cbCellSize));
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCAllocGlyphCache: Allocates glyph cache data buffers according to the
|
|
// current negotiated capabilities.
|
|
//
|
|
// Returns: SBC_GLYPH_CACHE_ENABLED if successful, 0 otherwise.
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SBCAllocGlyphCache(PCHCACHEHANDLE pCacheHandle)
|
|
{
|
|
BOOLEAN rc;
|
|
unsigned i;
|
|
PSBC_GLYPH_CACHE_INFO pGlyphCacheInfo;
|
|
PSBC_FRAG_CACHE_INFO pFragCacheInfo;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBCAllocGlyphCache");
|
|
|
|
TRC_NRM((TB, "Alloc glyph cache data"));
|
|
|
|
rc = FALSE;
|
|
|
|
// Create glyph cache(s).
|
|
if (pddShm->sbc.caps.GlyphSupportLevel > 0) {
|
|
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
|
|
pGlyphCacheInfo = &(pddShm->sbc.glyphCacheInfo[i]);
|
|
|
|
pCacheData = (PCHCACHEDATA)(*pCacheHandle);
|
|
if (SBCCreateGlyphCache(
|
|
pddShm->sbc.caps.glyphCacheSize[i].cEntries,
|
|
pddShm->sbc.caps.glyphCacheSize[i].cbCellSize,
|
|
pCacheData)) {
|
|
TRC_NRM((TB,
|
|
"Created glyph cache %u: cEntries(%u), cbCellSize(%u)",
|
|
i,
|
|
pddShm->sbc.caps.glyphCacheSize[i].cEntries,
|
|
pddShm->sbc.caps.glyphCacheSize[i].cbCellSize));
|
|
|
|
pGlyphCacheInfo->cbCellSize =
|
|
pddShm->sbc.caps.glyphCacheSize[i].cbCellSize;
|
|
|
|
pGlyphCacheInfo->cacheHandle = pCacheData;
|
|
|
|
(BYTE *)(*pCacheHandle) += CH_CalculateCacheSize(
|
|
pddShm->sbc.caps.glyphCacheSize[i].cEntries);
|
|
|
|
sbcFontCacheInfoListSize += pddShm->sbc.caps.glyphCacheSize[i].cEntries;
|
|
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
TRC_ERR((TB,
|
|
"Failed to create glyph cache %u: cEntries(%u), cbCellSize(%u)",
|
|
i,
|
|
pddShm->sbc.caps.glyphCacheSize[i].cEntries,
|
|
pddShm->sbc.caps.glyphCacheSize[i].cbCellSize));
|
|
|
|
pGlyphCacheInfo->cbCellSize = 0;
|
|
}
|
|
}
|
|
|
|
// Create fragment cache.
|
|
if (rc) {
|
|
pFragCacheInfo = pddShm->sbc.fragCacheInfo;
|
|
|
|
pCacheData = (PCHCACHEDATA)(*pCacheHandle);
|
|
|
|
if (SBCCreateFragCache(pddShm->sbc.caps.fragCacheSize[0].cEntries,
|
|
pddShm->sbc.caps.fragCacheSize[0].cbCellSize,
|
|
pCacheData)) {
|
|
pFragCacheInfo->cbCellSize = pddShm->sbc.caps.fragCacheSize[0].
|
|
cbCellSize;
|
|
pFragCacheInfo->cacheHandle = pCacheData;
|
|
|
|
(BYTE*)(*pCacheHandle) += CH_CalculateCacheSize(
|
|
pddShm->sbc.caps.fragCacheSize[0].cEntries);
|
|
}
|
|
else {
|
|
pFragCacheInfo->cbCellSize = 0;
|
|
}
|
|
}
|
|
|
|
// Create the list to store font context info data
|
|
if (rc ) {
|
|
sbcFontCacheInfoList = (PFONTCACHEINFO *) EngAllocMem(0,
|
|
sizeof(PFONTCACHEINFO) * sbcFontCacheInfoListSize,
|
|
DD_ALLOC_TAG);
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return (rc ? SBC_GLYPH_CACHE_ENABLED : 0);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SBCAllocBrushCache */
|
|
/* */
|
|
/* Purpose: Allocates brush cache data buffers according to the */
|
|
/* current negotiated capabilities. */
|
|
/* */
|
|
/* Returns: TRUE if successful, FALSE otherwise. */
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SBCAllocBrushCache(PCHCACHEHANDLE pCacheHandle)
|
|
{
|
|
BOOLEAN rc = FALSE;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBCAllocBrushCache");
|
|
|
|
TRC_NRM((TB, "Alloc brush cache data"));
|
|
|
|
if (pddShm->sbc.caps.brushSupportLevel > TS_BRUSH_DEFAULT)
|
|
{
|
|
/********************************************************************/
|
|
/* Allocate brush caches */
|
|
/********************************************************************/
|
|
// small brush cache
|
|
pCacheData = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(pCacheData, SBC_NUM_BRUSH_CACHE_ENTRIES, NULL,
|
|
FALSE, FALSE, NULL);
|
|
sbcSmallBrushCacheHandle = pCacheData;
|
|
(BYTE *)(*pCacheHandle) += CH_CalculateCacheSize(SBC_NUM_BRUSH_CACHE_ENTRIES);
|
|
|
|
// large brush cache
|
|
pCacheData = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(pCacheData, SBC_NUM_BRUSH_CACHE_ENTRIES, NULL,
|
|
FALSE, FALSE, NULL);
|
|
sbcLargeBrushCacheHandle = pCacheData;
|
|
(BYTE *)(*pCacheHandle) += CH_CalculateCacheSize(SBC_NUM_BRUSH_CACHE_ENTRIES);
|
|
|
|
rc = TRUE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return (rc ? SBC_BRUSH_CACHE_ENABLED : 0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
// SBCAllocOffscreenBitmapCache
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SBCAllocOffscreenBitmapCache(PCHCACHEHANDLE pCacheHandle)
|
|
{
|
|
BOOLEAN rc = FALSE;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBCAllocOffscreenBitmapCache");
|
|
|
|
if (pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) {
|
|
// Allocate memory for offscreen bitmap delete list
|
|
sbcOffscrBitmapsDelList = (PSBC_OFFSCR_BITMAP_DEL_INFO) EngAllocMem(0,
|
|
sizeof(SBC_OFFSCR_BITMAP_DEL_INFO) *
|
|
pddShm->sbc.offscreenCacheInfo.cacheEntries,
|
|
DD_ALLOC_TAG);
|
|
|
|
if (sbcOffscrBitmapsDelList) {
|
|
pCacheData = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(pCacheData, pddShm->sbc.offscreenCacheInfo.cacheEntries, NULL,
|
|
TRUE, FALSE, SBCOffscreenCallback);
|
|
sbcOffscreenBitmapCacheHandle = pCacheData;
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.offscreenCacheInfo.cacheEntries);
|
|
|
|
rc = TRUE;
|
|
} else {
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return (rc ? SBC_OFFSCREEN_CACHE_ENABLED : 0);
|
|
}
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
/****************************************************************************/
|
|
// SBCAllocDrawNineGridBitmapCache
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SBCAllocDrawNineGridBitmapCache(PCHCACHEHANDLE pCacheHandle)
|
|
{
|
|
BOOLEAN rc = FALSE;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBCAllocDrawNineGridBitmapCache");
|
|
|
|
if (pddShm->sbc.drawNineGridCacheInfo.supportLevel > TS_DRAW_NINEGRID_DEFAULT) {
|
|
pCacheData = (PCHCACHEDATA) (*pCacheHandle);
|
|
|
|
CH_InitCache(pCacheData, pddShm->sbc.drawNineGridCacheInfo.cacheEntries, NULL,
|
|
FALSE, FALSE, NULL);
|
|
sbcDrawNineGridBitmapCacheHandle = pCacheData;
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.drawNineGridCacheInfo.cacheEntries);
|
|
|
|
rc = TRUE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return (rc ? SBC_DRAWNINEGRID_CACHE_ENABLED : 0);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DRAW_GDIPLUS
|
|
/****************************************************************************/
|
|
// SBCAllocDrawGdiplusCache
|
|
/****************************************************************************/
|
|
unsigned RDPCALL SBCAllocDrawGdiplusCache(PCHCACHEHANDLE pCacheHandle)
|
|
{
|
|
BOOLEAN rc = FALSE;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBCAllocDrawGdiplusCache");
|
|
|
|
if ((pddShm->sbc.drawGdiplusInfo.supportLevel > TS_DRAW_GDIPLUS_DEFAULT) &&
|
|
(pddShm->sbc.drawGdiplusInfo.GdipCacheLevel > TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT)) {
|
|
pCacheData = (PCHCACHEDATA) (*pCacheHandle);
|
|
|
|
sbcGdipGraphicsCacheHandle = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(sbcGdipGraphicsCacheHandle, pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries, NULL,
|
|
FALSE, FALSE, NULL);
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries);
|
|
|
|
sbcGdipObjectBrushCacheHandle = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(sbcGdipObjectBrushCacheHandle, pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries, NULL,
|
|
FALSE, FALSE, NULL);
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries);
|
|
|
|
sbcGdipObjectPenCacheHandle = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(sbcGdipObjectPenCacheHandle, pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries, NULL,
|
|
FALSE, FALSE, NULL);
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries);
|
|
|
|
sbcGdipObjectImageCacheHandle = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(sbcGdipObjectImageCacheHandle, pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries, NULL,
|
|
FALSE, FALSE, NULL);
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries);
|
|
|
|
sbcGdipObjectImageAttributesCacheHandle = (PCHCACHEDATA) (*pCacheHandle);
|
|
CH_InitCache(sbcGdipObjectImageAttributesCacheHandle, pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries, NULL,
|
|
FALSE, FALSE, NULL);
|
|
(BYTE *)(*pCacheHandle) +=
|
|
CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries);
|
|
|
|
sbcGdipGraphicsCacheChunkSize = pddShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipGraphicsCacheChunkSize;
|
|
sbcGdipObjectBrushCacheChunkSize = pddShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize;
|
|
sbcGdipObjectPenCacheChunkSize = pddShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipObjectPenCacheChunkSize;
|
|
sbcGdipObjectImageAttributesCacheChunkSize = pddShm->sbc.drawGdiplusInfo.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize;
|
|
sbcGdipObjectImageCacheChunkSize = pddShm->sbc.drawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheChunkSize;
|
|
sbcGdipObjectImageCacheMaxSize = pddShm->sbc.drawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheMaxSize;
|
|
sbcGdipObjectImageCacheTotalSize = pddShm->sbc.drawGdiplusInfo.GdipImageCacheProperties.GdipObjectImageCacheTotalSize;
|
|
sbcGdipObjectImageCacheSizeUsed = 0;
|
|
|
|
sbcGdipObjectImageCacheSizeList = (UINT16 *)EngAllocMem(0,
|
|
pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries * sizeof(UINT16), DD_ALLOC_TAG);
|
|
if (sbcGdipObjectImageCacheSizeList == NULL) {
|
|
rc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
|
|
rc = TRUE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
DC_EXIT_POINT:
|
|
return (rc ? SBC_DRAWGDIPLUS_CACHE_ENABLED : 0);
|
|
}
|
|
#endif // DRAW_GDIPLUS
|
|
|
|
void RDPCALL SBCAllocCaches(void)
|
|
{
|
|
UINT i;
|
|
ULONG cacheSize;
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBCAllocCaches");
|
|
|
|
TRC_NRM((TB, "Alloc SBC cache data"));
|
|
|
|
// Initialize cacheSize;
|
|
cacheSize = 0;
|
|
|
|
// Calculate glyph fragment cache sizes.
|
|
if (pddShm->sbc.caps.GlyphSupportLevel > 0) {
|
|
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++)
|
|
cacheSize += CH_CalculateCacheSize(
|
|
pddShm->sbc.caps.glyphCacheSize[i].cEntries);
|
|
|
|
cacheSize += CH_CalculateCacheSize(
|
|
pddShm->sbc.caps.fragCacheSize[0].cEntries);
|
|
}
|
|
|
|
if (pddShm->sbc.NumBitmapCaches > 0) {
|
|
UINT totalEntries = 0;
|
|
|
|
// Calculate bitmap cache sizes
|
|
for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++) {
|
|
// one for the cache, another for the waiting list
|
|
if (pddShm->sbc.fAllowCacheWaitingList) {
|
|
cacheSize += CH_CalculateCacheSize(
|
|
pddShm->sbc.bitmapCacheInfo[i].Info.NumEntries) * 2;
|
|
}
|
|
else {
|
|
cacheSize += CH_CalculateCacheSize(
|
|
pddShm->sbc.bitmapCacheInfo[i].Info.NumEntries);
|
|
}
|
|
|
|
totalEntries += pddShm->sbc.bitmapCacheInfo[i].Info.NumEntries;
|
|
}
|
|
|
|
// fast path cache
|
|
cacheSize += CH_CalculateCacheSize(totalEntries);
|
|
|
|
// Calculate color table cache
|
|
cacheSize += CH_CalculateCacheSize(
|
|
SBC_NUM_COLOR_TABLE_CACHE_ENTRIES);
|
|
}
|
|
|
|
// Calculate brush cache size
|
|
if (pddShm->sbc.caps.brushSupportLevel > TS_BRUSH_DEFAULT) {
|
|
// both large brush cache and small brush cache
|
|
cacheSize += CH_CalculateCacheSize(SBC_NUM_BRUSH_CACHE_ENTRIES) * 2;
|
|
}
|
|
|
|
// Calculate offscreen cache size
|
|
if (pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) {
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.offscreenCacheInfo.cacheEntries);
|
|
}
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
// Calculate drawstream cache size
|
|
if (pddShm->sbc.drawNineGridCacheInfo.supportLevel > TS_DRAW_NINEGRID_DEFAULT) {
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.drawNineGridCacheInfo.cacheEntries);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DRAW_GDIPLUS
|
|
// Calculate drawgdiplus cache size
|
|
if ((pddShm->sbc.drawGdiplusInfo.supportLevel > TS_DRAW_GDIPLUS_DEFAULT) &&
|
|
(pddShm->sbc.drawGdiplusInfo.GdipCacheLevel > TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT)) {
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipGraphicsCacheEntries);
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectBrushCacheEntries);
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectPenCacheEntries);
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries);
|
|
cacheSize += CH_CalculateCacheSize(pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageAttributesCacheEntries);
|
|
}
|
|
#endif
|
|
|
|
// Allocate memory for the cache
|
|
if (cacheSize)
|
|
sbcCacheData = (PCHCACHEDATA)EngAllocMem(0, cacheSize, DD_ALLOC_TAG);
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBC_Update: Allocate and initialize data structures according to the
|
|
// current negotiated capabilities.
|
|
/****************************************************************************/
|
|
void RDPCALL SBC_Update(SBC_BITMAP_CACHE_KEY_INFO *pKeyDatabase)
|
|
{
|
|
PCHCACHEDATA pCacheData;
|
|
|
|
DC_BEGIN_FN("SBC_Update");
|
|
|
|
SBCFreeCacheData();
|
|
|
|
#ifdef DC_HICOLOR
|
|
// Update the client bits per pel
|
|
sbcClientBitsPerPel = pddShm->sbc.clientBitsPerPel;
|
|
switch (sbcClientBitsPerPel)
|
|
{
|
|
case 24:
|
|
{
|
|
sbcCacheFlags = TS_CacheBitmapRev2_24BitsPerPel;
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
{
|
|
sbcCacheFlags = TS_CacheBitmapRev2_16BitsPerPel;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
sbcCacheFlags = TS_CacheBitmapRev2_8BitsPerPel;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
if (pddShm->sbc.fCachingEnabled) {
|
|
TRC_NRM((TB, "Alloc cache data"));
|
|
|
|
sbcEnabled = SBC_NO_CACHE_ENABLED;
|
|
|
|
SBCAllocCaches();
|
|
if (sbcCacheData) {
|
|
pCacheData = sbcCacheData;
|
|
|
|
// Create glyph and fragment cache(s).
|
|
sbcEnabled |= SBCAllocGlyphCache(&pCacheData);
|
|
|
|
// Create bitmap cache(s), work bitmaps, and color table cache.
|
|
sbcEnabled |= SBCAllocBitmapCache(&pCacheData);
|
|
|
|
// We expect the key database to have come to us by the time we get
|
|
// here.
|
|
if (sbcEnabled & SBC_BITMAP_CACHE_ENABLED) {
|
|
if (pKeyDatabase != NULL)
|
|
SBCProcessBitmapKeyDatabase(pKeyDatabase);
|
|
}
|
|
|
|
// Create brush cache.
|
|
sbcEnabled |= SBCAllocBrushCache(&pCacheData);
|
|
if (!(sbcEnabled & SBC_BRUSH_CACHE_ENABLED))
|
|
pddShm->sbc.caps.brushSupportLevel = TS_BRUSH_DEFAULT;
|
|
|
|
sbcEnabled |= SBCAllocOffscreenBitmapCache(&pCacheData);
|
|
|
|
if (!(sbcEnabled & SBC_OFFSCREEN_CACHE_ENABLED)) {
|
|
pddShm->sbc.offscreenCacheInfo.supportLevel =
|
|
TS_OFFSCREEN_DEFAULT;
|
|
}
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
sbcEnabled |= SBCAllocDrawNineGridBitmapCache(&pCacheData);
|
|
|
|
if (!(sbcEnabled & SBC_DRAWNINEGRID_CACHE_ENABLED)) {
|
|
pddShm->sbc.drawNineGridCacheInfo.supportLevel =
|
|
TS_DRAW_NINEGRID_DEFAULT;
|
|
}
|
|
#endif
|
|
#ifdef DRAW_GDIPLUS
|
|
sbcEnabled |= SBCAllocDrawGdiplusCache(&pCacheData);
|
|
|
|
if (!(sbcEnabled & SBC_DRAWGDIPLUS_CACHE_ENABLED)) {
|
|
pddShm->sbc.drawGdiplusInfo.GdipCacheLevel = TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
// Force brush cache disabled to prevent use of the caches.
|
|
pddShm->sbc.caps.brushSupportLevel = TS_BRUSH_DEFAULT;
|
|
|
|
// Force offscreen cache disabled
|
|
pddShm->sbc.offscreenCacheInfo.supportLevel =
|
|
TS_OFFSCREEN_DEFAULT;
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
// Force drawstream cache disabled
|
|
pddShm->sbc.drawNineGridCacheInfo.supportLevel =
|
|
TS_DRAW_NINEGRID_DEFAULT;
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
// Force brush cache disabled to prevent use of the caches.
|
|
pddShm->sbc.caps.brushSupportLevel = TS_BRUSH_DEFAULT;
|
|
|
|
// Force offscreen cache disabled
|
|
pddShm->sbc.offscreenCacheInfo.supportLevel =
|
|
TS_OFFSCREEN_DEFAULT;
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
// Force drawstream cache disabled
|
|
pddShm->sbc.drawNineGridCacheInfo.supportLevel =
|
|
TS_DRAW_NINEGRID_DEFAULT;
|
|
#endif
|
|
|
|
}
|
|
|
|
pddShm->sbc.newCapsData = FALSE;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCFreeGlyphCacheData: Free glyph cache data buffers.
|
|
/****************************************************************************/
|
|
__inline void RDPCALL SBCFreeGlyphCacheData(void)
|
|
{
|
|
unsigned i;
|
|
PSBC_GLYPH_CACHE_INFO pGlyphCacheInfo;
|
|
PSBC_FRAG_CACHE_INFO pFragCacheInfo;
|
|
|
|
DC_BEGIN_FN("SBCFreeGlyphCacheData");
|
|
|
|
TRC_NRM((TB, "Free glyph cache data"));
|
|
|
|
// Free glyph cache(s).
|
|
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
|
|
pGlyphCacheInfo = &(pddShm->sbc.glyphCacheInfo[i]);
|
|
|
|
if (pGlyphCacheInfo->cacheHandle != NULL) {
|
|
CH_ClearCache(pGlyphCacheInfo->cacheHandle);
|
|
pGlyphCacheInfo->cacheHandle = NULL;
|
|
pGlyphCacheInfo->cbCellSize = 0;
|
|
}
|
|
}
|
|
|
|
// Free fragment cache.
|
|
pFragCacheInfo = pddShm->sbc.fragCacheInfo;
|
|
|
|
if (pFragCacheInfo->cacheHandle != NULL) {
|
|
CH_ClearCache(pFragCacheInfo->cacheHandle);
|
|
pFragCacheInfo->cacheHandle = NULL;
|
|
pFragCacheInfo->cbCellSize = 0;
|
|
}
|
|
|
|
// Free the font cache info list
|
|
if (sbcFontCacheInfoList != 0) {
|
|
// Reset all the font cache info to 0.
|
|
for (i = 0; i < sbcFontCacheInfoListIndex; i++) {
|
|
if (sbcFontCacheInfoList[i] != 0) {
|
|
memset(sbcFontCacheInfoList[i], 0, sizeof(FONTCACHEINFO));
|
|
}
|
|
}
|
|
|
|
// Free the font cache info list
|
|
EngFreeMem(sbcFontCacheInfoList);
|
|
sbcFontCacheInfoList = 0;
|
|
sbcFontCacheInfoListSize = 0;
|
|
sbcFontCacheInfoListIndex = 0;
|
|
}
|
|
|
|
sbcEnabled &= ~SBC_GLYPH_CACHE_ENABLED;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: SBCFreeBrushCacheData */
|
|
/* */
|
|
/* Purpose: Free brush cache data buffers. */
|
|
/****************************************************************************/
|
|
void RDPCALL SBCFreeBrushCacheData(void)
|
|
{
|
|
DC_BEGIN_FN("SBCFreeBrushCacheData");
|
|
|
|
TRC_NRM((TB, "Free brush cache data"));
|
|
|
|
/************************************************************************/
|
|
/* Free brush cache */
|
|
/************************************************************************/
|
|
if (sbcSmallBrushCacheHandle != 0)
|
|
{
|
|
CH_ClearCache(sbcSmallBrushCacheHandle);
|
|
sbcSmallBrushCacheHandle = 0;
|
|
}
|
|
|
|
if (sbcLargeBrushCacheHandle != 0)
|
|
{
|
|
CH_ClearCache(sbcLargeBrushCacheHandle);
|
|
sbcLargeBrushCacheHandle = 0;
|
|
}
|
|
|
|
sbcEnabled &= ~SBC_BRUSH_CACHE_ENABLED;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
/****************************************************************************/
|
|
// SBCFreeOffscreenBitmapCacheData
|
|
/****************************************************************************/
|
|
void RDPCALL SBCFreeOffscreenBitmapCacheData(void)
|
|
{
|
|
DC_BEGIN_FN("SBCFreeOffscreenBitmapCacheData");
|
|
|
|
TRC_NRM((TB, "Free offscreen Bitmap cache data"));
|
|
|
|
/************************************************************************/
|
|
/* Free Offscreen cache */
|
|
/************************************************************************/
|
|
if (pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT)
|
|
{
|
|
CH_ClearCache(sbcOffscreenBitmapCacheHandle);
|
|
}
|
|
|
|
sbcOffscreenBitmapCacheHandle = 0;
|
|
|
|
// Free the offscreen bitmap delete list
|
|
if (sbcOffscrBitmapsDelList != 0) {
|
|
EngFreeMem(sbcOffscrBitmapsDelList);
|
|
sbcOffscrBitmapsDelList = 0;
|
|
sbcNumOffscrBitmapsToDelete = 0;
|
|
sbcOffscrBitmapsToDeleteSize = 0;
|
|
}
|
|
|
|
sbcEnabled &= ~SBC_OFFSCREEN_CACHE_ENABLED;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
/****************************************************************************/
|
|
// SBCFreeDrawNineGridBitmapCacheData
|
|
/****************************************************************************/
|
|
void RDPCALL SBCFreeDrawNineGridBitmapCacheData(void)
|
|
{
|
|
DC_BEGIN_FN("SBCFreeDrawNineGridBitmapCacheData");
|
|
|
|
TRC_NRM((TB, "Free drawsninegrid Bitmap cache data"));
|
|
|
|
/************************************************************************/
|
|
// Free DrawNineGrid cache
|
|
/************************************************************************/
|
|
if (pddShm->sbc.drawNineGridCacheInfo.supportLevel > TS_DRAW_NINEGRID_DEFAULT)
|
|
{
|
|
CH_ClearCache(sbcDrawNineGridBitmapCacheHandle);
|
|
}
|
|
|
|
sbcDrawNineGridBitmapCacheHandle = 0;
|
|
|
|
sbcEnabled &= ~SBC_DRAWNINEGRID_CACHE_ENABLED;
|
|
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
#ifdef DRAW_GDIPLUS
|
|
/****************************************************************************/
|
|
// SBCFreeDrawGdiplusCacheData
|
|
/****************************************************************************/
|
|
void RDPCALL SBCFreeDrawGdiplusCacheData(void)
|
|
{
|
|
DC_BEGIN_FN("SBCFreeDrawGdiplusCacheData");
|
|
|
|
TRC_NRM((TB, "Free drawgdiplus cache data"));
|
|
|
|
/************************************************************************/
|
|
// Free DrawGdiplus cache
|
|
/************************************************************************/
|
|
if ((pddShm->sbc.drawGdiplusInfo.supportLevel > TS_DRAW_GDIPLUS_DEFAULT) &&
|
|
(pddShm->sbc.drawGdiplusInfo.GdipCacheLevel > TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT))
|
|
{
|
|
CH_ClearCache(sbcGdipGraphicsCacheHandle);
|
|
CH_ClearCache(sbcGdipObjectBrushCacheHandle);
|
|
CH_ClearCache(sbcGdipObjectPenCacheHandle);
|
|
CH_ClearCache(sbcGdipObjectImageCacheHandle);
|
|
CH_ClearCache(sbcGdipObjectImageAttributesCacheHandle);
|
|
EngFreeMem(sbcGdipObjectImageCacheSizeList);
|
|
}
|
|
|
|
sbcGdipGraphicsCacheHandle = 0;
|
|
|
|
sbcEnabled &= ~SBC_DRAWGDIPLUS_CACHE_ENABLED;
|
|
|
|
DC_END_FN();
|
|
}
|
|
#endif // DRAW_GDIPLUS
|
|
|
|
/****************************************************************************/
|
|
// SBCFreeBitmapCacheData: Free bitmap cache data buffers.
|
|
/****************************************************************************/
|
|
__inline void RDPCALL SBCFreeBitmapCacheData(void)
|
|
{
|
|
unsigned i;
|
|
PSBC_BITMAP_CACHE_INFO pBitmapCacheInfo;
|
|
|
|
DC_BEGIN_FN("SBCFreeBitmapCacheData");
|
|
|
|
TRC_NRM((TB, "Free bitmap cache data"));
|
|
|
|
// Free cell caches.
|
|
for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++) {
|
|
pBitmapCacheInfo = &(pddShm->sbc.bitmapCacheInfo[i]);
|
|
|
|
// Destroy the work bitmap.
|
|
if (pBitmapCacheInfo->hWorkBitmap != NULL) {
|
|
// The bitmap has been created, so now destroy it. Despite its
|
|
// name, EngDeleteSurface is the correct function to do this.
|
|
if (EngDeleteSurface(pBitmapCacheInfo->hWorkBitmap))
|
|
{
|
|
TRC_NRM((TB, "Deleted work bitmap %d", i));
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, "Failed to delete work bitmap %d", i));
|
|
}
|
|
pBitmapCacheInfo->hWorkBitmap = NULL;
|
|
}
|
|
|
|
if (pBitmapCacheInfo->cacheHandle != NULL) {
|
|
CH_ClearCache(pBitmapCacheInfo->cacheHandle);
|
|
pBitmapCacheInfo->cacheHandle = NULL;
|
|
}
|
|
|
|
if (pBitmapCacheInfo->waitingListHandle != NULL) {
|
|
CH_ClearCache(pBitmapCacheInfo->waitingListHandle);
|
|
pBitmapCacheInfo->waitingListHandle = NULL;
|
|
}
|
|
|
|
#ifdef DC_DEBUG
|
|
// Free the bitmap header buffer.
|
|
if (pBitmapCacheInfo->pExtraEntryInfo != NULL) {
|
|
EngFreeMem(pBitmapCacheInfo->pExtraEntryInfo);
|
|
pBitmapCacheInfo->pExtraEntryInfo = NULL;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
if (pddShm->sbc.hFastPathCache != NULL) {
|
|
CH_ClearCache(pddShm->sbc.hFastPathCache);
|
|
pddShm->sbc.hFastPathCache = NULL;
|
|
}
|
|
|
|
// Free colortable cache.
|
|
if (sbcColorTableCacheHandle != NULL) {
|
|
CH_ClearCache(sbcColorTableCacheHandle);
|
|
sbcColorTableCacheHandle = NULL;
|
|
}
|
|
|
|
// Destroy the 4bpp to 8bpp translation buffer, if present.
|
|
if (sbcXlateBuf != NULL) {
|
|
EngFreeMem(sbcXlateBuf);
|
|
sbcXlateBuf = NULL;
|
|
}
|
|
|
|
sbcEnabled &= ~SBC_BITMAP_CACHE_ENABLED;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCFreeCacheData: Free cache data buffers.
|
|
/****************************************************************************/
|
|
void RDPCALL SBCFreeCacheData(void)
|
|
{
|
|
DC_BEGIN_FN("SBCFreeCacheData");
|
|
|
|
TRC_NRM((TB, "Free cache data"));
|
|
|
|
if (sbcEnabled != SBC_NO_CACHE_ENABLED) {
|
|
// Free glyph and fragment caches.
|
|
if (sbcEnabled & SBC_GLYPH_CACHE_ENABLED)
|
|
SBCFreeGlyphCacheData();
|
|
|
|
// Free bitmap cache(s) and color table cache.
|
|
if (sbcEnabled & SBC_BITMAP_CACHE_ENABLED)
|
|
SBCFreeBitmapCacheData();
|
|
|
|
// Free brush caches.
|
|
if (sbcEnabled & SBC_BRUSH_CACHE_ENABLED) {
|
|
SBCFreeBrushCacheData();
|
|
}
|
|
|
|
// Free offscreen cache
|
|
if (sbcEnabled & SBC_OFFSCREEN_CACHE_ENABLED) {
|
|
SBCFreeOffscreenBitmapCacheData();
|
|
}
|
|
|
|
#ifdef DRAW_NINEGRID
|
|
// Free drawstream cache
|
|
if (sbcEnabled & SBC_DRAWNINEGRID_CACHE_ENABLED) {
|
|
SBCFreeDrawNineGridBitmapCacheData();
|
|
}
|
|
#endif
|
|
|
|
#ifdef DRAW_GDIPLUS
|
|
// Free drawgdiplus cache
|
|
if (sbcEnabled & SBC_DRAWGDIPLUS_CACHE_ENABLED) {
|
|
SBCFreeDrawGdiplusCacheData();
|
|
}
|
|
#endif
|
|
|
|
if (sbcCacheData) {
|
|
EngFreeMem(sbcCacheData);
|
|
sbcCacheData = NULL;
|
|
}
|
|
|
|
TRC_ASSERT((sbcEnabled == SBC_NO_CACHE_ENABLED),
|
|
(TB, "sbcEnabled should be disabled: %lx", sbcEnabled));
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBC_DDSync
|
|
//
|
|
// Performs a server-initiated sync, which occurs during the client connection
|
|
// sequence after the client responds with a ConfirmActivePDU, the persistent
|
|
// bitmap keys, and the font list PDUs. In RDP 4.0 a server-side sync would
|
|
// have reset all the caches. In this version we have to be more careful since
|
|
// we absolutely do not want to lose any of the current bitmap cache
|
|
// information, which includes persistent as well as new keys added since
|
|
// connection time.
|
|
//
|
|
// bMustSync is currently used by DrvShadowConnect() only
|
|
/****************************************************************************/
|
|
void RDPCALL SBC_DDSync(BOOLEAN bMustSync)
|
|
{
|
|
unsigned i;
|
|
|
|
DC_BEGIN_FN("SBC_DDSync");
|
|
|
|
if ((sbcEnabled != SBC_NO_CACHE_ENABLED) && bMustSync) {
|
|
TRC_ALT((TB, "Sync: resetting caches"));
|
|
|
|
// Reset the glyph and fragment caches.
|
|
if (sbcEnabled & SBC_GLYPH_CACHE_ENABLED) {
|
|
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
|
|
if (pddShm->sbc.glyphCacheInfo[i].cacheHandle != NULL)
|
|
CH_ClearCache(pddShm->sbc.glyphCacheInfo[i].cacheHandle);
|
|
}
|
|
TRC_NRM((TB, "Sync: reset glyph info caches"));
|
|
|
|
if (pddShm->sbc.fragCacheInfo[0].cacheHandle != NULL) {
|
|
CH_ClearCache(pddShm->sbc.fragCacheInfo[0].cacheHandle);
|
|
TRC_NRM((TB, "Sync: reset glyph fragment cache"));
|
|
}
|
|
}
|
|
|
|
// Reset the brush caches.
|
|
if (sbcEnabled & SBC_BRUSH_CACHE_ENABLED)
|
|
{
|
|
if (sbcSmallBrushCacheHandle) {
|
|
TRC_NRM((TB, "Sync: reset small brush cache"));
|
|
CH_ClearCache(sbcSmallBrushCacheHandle);
|
|
}
|
|
if (sbcLargeBrushCacheHandle) {
|
|
TRC_NRM((TB, "Sync: reset large brush cache"));
|
|
CH_ClearCache(sbcLargeBrushCacheHandle);
|
|
}
|
|
}
|
|
|
|
// Reset the bitmap, fastpath, and color table caches.
|
|
if (sbcEnabled & SBC_BITMAP_CACHE_ENABLED) {
|
|
for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++)
|
|
if (pddShm->sbc.bitmapCacheInfo[i].cacheHandle != NULL) {
|
|
TRC_NRM((TB, "Sync: reset bitmap cache[%ld]", i));
|
|
CH_ClearCache(pddShm->sbc.bitmapCacheInfo[i].cacheHandle);
|
|
}
|
|
|
|
if (pddShm->sbc.hFastPathCache != NULL) {
|
|
TRC_NRM((TB, "Sync: reset fast path bitmap"));
|
|
CH_ClearCache(pddShm->sbc.hFastPathCache);
|
|
}
|
|
|
|
// Reset the color table cache.
|
|
if (sbcColorTableCacheHandle != NULL) {
|
|
CH_ClearCache(sbcColorTableCacheHandle);
|
|
TRC_NRM((TB, "Sync: reset color table cache"));
|
|
}
|
|
}
|
|
|
|
// Pretend that the palette has changed, so we send a color table
|
|
// before our next MemBlt.
|
|
SBC_PaletteChanged();
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "Nothing to do sbcEnabled(%lx), bMustSync(%ld)",
|
|
sbcEnabled, bMustSync));
|
|
}
|
|
|
|
// Reset the sync flag.
|
|
pddShm->sbc.syncRequired = FALSE;
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCSelectGlyphCache: Decides which cache a given max font glyph size
|
|
// should go in.
|
|
//
|
|
// Returns: TRUE if the glyph size can be cached
|
|
// *pCache is updated with the index of the selected cache
|
|
//
|
|
// FALSE if the glyph size cannot be cached
|
|
// *pCache is -1
|
|
//
|
|
// Params: cbSize - size in bytes of the data to be cached
|
|
//
|
|
// pCache - pointer to variable that receives the cache index
|
|
// to use
|
|
/****************************************************************************/
|
|
BOOLEAN RDPCALL SBCSelectGlyphCache(unsigned cbSize, PINT32 pCache)
|
|
{
|
|
int i;
|
|
INT32 cacheId;
|
|
BOOLEAN rc;
|
|
unsigned cbCellSize;
|
|
unsigned cbUseCount;
|
|
|
|
DC_BEGIN_FN("SBCSelectGlyphCache");
|
|
|
|
*pCache = -1;
|
|
|
|
cbUseCount = 0;
|
|
cbCellSize = 65535;
|
|
|
|
for (i = 0; i < SBC_NUM_GLYPH_CACHES; i++) {
|
|
if (pddShm->sbc.glyphCacheInfo[i].cbCellSize >= cbSize) {
|
|
if (pddShm->sbc.glyphCacheInfo[i].cbCellSize < cbCellSize) {
|
|
*pCache = i;
|
|
|
|
cbCellSize = pddShm->sbc.glyphCacheInfo[i].cbCellSize;
|
|
cbUseCount = pddShm->sbc.glyphCacheInfo[i].cbUseCount;
|
|
}
|
|
else if (pddShm->sbc.glyphCacheInfo[i].cbCellSize == cbCellSize) {
|
|
if (pddShm->sbc.glyphCacheInfo[i].cbUseCount <= cbUseCount) {
|
|
*pCache = i;
|
|
|
|
cbCellSize = pddShm->sbc.glyphCacheInfo[i].cbCellSize;
|
|
cbUseCount = pddShm->sbc.glyphCacheInfo[i].cbUseCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*pCache != -1) {
|
|
rc = TRUE;
|
|
}
|
|
else {
|
|
TRC_ALT((TB, "Failed to find cache for cbSize(%u)", cbSize));
|
|
rc = FALSE;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCDDGetTickCount: Get a system tick count.
|
|
//
|
|
// Returns: The number of centi-seconds since the system was started.
|
|
// This number will wrap after approximately 497 days!
|
|
/****************************************************************************/
|
|
__inline UINT32 RDPCALL SBCDDGetTickCount(void)
|
|
{
|
|
LONGLONG perfTickCount;
|
|
|
|
/************************************************************************/
|
|
/* Get the number of system ticks since the system was started. */
|
|
/************************************************************************/
|
|
EngQueryPerformanceCounter(&perfTickCount);
|
|
|
|
/************************************************************************/
|
|
/* Now convert this into a number of centi-seconds. sbcPerfFrequency */
|
|
/* contains the number of system ticks per second. */
|
|
/************************************************************************/
|
|
return (UINT32)(perfTickCount & 0xFFFFFFFF);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCBitmapCacheCallback
|
|
//
|
|
// Called whenever an entry is evicted from the bitmap cache.
|
|
//
|
|
// Params: hCache - cache handle
|
|
//
|
|
// event - the cache event that has occurred.
|
|
//
|
|
// iCacheEntry - index of the cache entry that the event is affecting
|
|
//
|
|
// pData - pointer to the cache data associated with the given
|
|
// cache entry
|
|
//
|
|
// UserDefined - user-supplied value from CH_CacheKey
|
|
/****************************************************************************/
|
|
BOOLEAN __fastcall SBCBitmapCacheCallback(
|
|
CHCACHEHANDLE hCache,
|
|
unsigned Event,
|
|
unsigned iCacheEntry,
|
|
void *UserDefined)
|
|
{
|
|
DC_BEGIN_FN("SBCBitmapCacheCallback");
|
|
|
|
if (Event == CH_EVT_ENTRYREMOVED) {
|
|
TRC_NRM((TB, "Cache entry removed hCache(%p) iCacheEntry(%u)",
|
|
hCache, iCacheEntry));
|
|
|
|
// Keep the fast path cache in sync by removing the
|
|
// corresponding fast path entry.
|
|
if (UserDefined != NULL) {
|
|
CH_SetNodeUserDefined((CHNODE *)UserDefined, NULL);
|
|
CH_RemoveCacheEntry(pddShm->sbc.hFastPathCache,
|
|
CH_GetCacheIndexFromNode((CHNODE *)UserDefined));
|
|
|
|
TRC_NRM((TB, "Remove fastpath entry %u",
|
|
CH_GetCacheIndexFromNode((CHNODE *)UserDefined)));
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCFastPathCacheCallback
|
|
//
|
|
// Called whenever an entry is evicted from the cache.
|
|
//
|
|
// Params: hCache - cache handle
|
|
//
|
|
// Event - the cache event that has occured
|
|
//
|
|
// iCacheEntry - index of the cache entry that the event is affecting
|
|
//
|
|
// UserDefined - value passed in when entry was placed in cache.
|
|
/****************************************************************************/
|
|
BOOLEAN __fastcall SBCFastPathCacheCallback(
|
|
CHCACHEHANDLE hCache,
|
|
unsigned Event,
|
|
unsigned iCacheEntry,
|
|
void *UserDefined)
|
|
{
|
|
DC_BEGIN_FN("SBCFastPathCacheCallback");
|
|
|
|
if (Event == CH_EVT_ENTRYREMOVED) {
|
|
TRC_NRM((TB, "Fastpath cache entry removed hCache(%p) "
|
|
"iCacheEntry(%u)", hCache, iCacheEntry));
|
|
|
|
if (UserDefined != NULL) {
|
|
// We are losing a fast-path cache entry. UserDefined is a
|
|
// pointer to the node in the main cache corresponding to this
|
|
// fast path entry. Update the main cache entry with a NULL
|
|
// UserDefined to indicate there is no longer an associated
|
|
// fast-path entry.
|
|
CH_SetNodeUserDefined((CHNODE *)UserDefined, NULL);
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCGlyphCallback
|
|
//
|
|
// Called whenever an entry is to be evicted from the cache.
|
|
//
|
|
// Params: hCache - cache handle
|
|
//
|
|
// Event - the cache event that has occured
|
|
//
|
|
// iCacheEntry - index of the cache entry that the event is affecting
|
|
//
|
|
// UserDefined - value passed in when entry was placed in cache.
|
|
/****************************************************************************/
|
|
BOOLEAN __fastcall SBCGlyphCallback(
|
|
CHCACHEHANDLE hCache,
|
|
unsigned event,
|
|
unsigned iCacheEntry,
|
|
void *UserDefined)
|
|
{
|
|
BOOLEAN rc;
|
|
unsigned i;
|
|
PGLYPHCONTEXT pglc;
|
|
|
|
DC_BEGIN_FN("SBCGlyphCallback");
|
|
|
|
rc = TRUE;
|
|
|
|
switch (event) {
|
|
/********************************************************************/
|
|
/* We are being asked if the given entry can be evicted from the */
|
|
/* cache. */
|
|
/********************************************************************/
|
|
case CH_EVT_QUERYREMOVEENTRY:
|
|
pglc = (PGLYPHCONTEXT)CH_GetCacheContext(hCache);
|
|
if (pglc != NULL && (UINT_PTR)UserDefined == pglc->cacheTag)
|
|
rc = FALSE;
|
|
break;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCOffscreenCallback
|
|
//
|
|
// Called whenever an entry is to be evicted from the cache.
|
|
//
|
|
// Params: hCache - cache handle
|
|
//
|
|
// Event - the cache event that has occured
|
|
//
|
|
// iCacheEntry - index of the cache entry that the event is affecting
|
|
//
|
|
// UserDefined - value passed in when entry was placed in cache.
|
|
/****************************************************************************/
|
|
BOOLEAN __fastcall SBCOffscreenCallback(
|
|
CHCACHEHANDLE hCache,
|
|
unsigned event,
|
|
unsigned iCacheEntry,
|
|
void *UserDefined)
|
|
{
|
|
BOOLEAN rc;
|
|
unsigned bitmapSize;
|
|
PGLYPHCONTEXT pglc;
|
|
|
|
DC_BEGIN_FN("SBCOffscreenCallback");
|
|
|
|
if (event == CH_EVT_ENTRYREMOVED) {
|
|
TRC_NRM((TB, "Offscreen cache entry removed hCache(%p) "
|
|
"iCacheEntry(%u)", hCache, iCacheEntry));
|
|
|
|
if (UserDefined != NULL) {
|
|
// We are losing an offscreen cache entry. UserDefined is a
|
|
// handle to the offscreen bitmap that's going to be evicted.
|
|
// We need to set the flag to noOffscreen for this bitmap
|
|
((PDD_DSURF)UserDefined)->flags |= DD_NO_OFFSCREEN;
|
|
|
|
// Get the bitmap size
|
|
// The assumption here is that iFormat is > 1BPP, i << iFormat
|
|
// gives the actual bits per pel. bitmapSize is in bytes.
|
|
if (((PDD_DSURF)UserDefined)->iBitmapFormat < 5) {
|
|
bitmapSize = ((PDD_DSURF)UserDefined)->sizl.cx *
|
|
((PDD_DSURF)UserDefined)->sizl.cy *
|
|
(1 << ((PDD_DSURF)UserDefined)->iBitmapFormat) / 8;
|
|
}
|
|
else if (((PDD_DSURF)UserDefined)->iBitmapFormat == 5) {
|
|
bitmapSize = ((PDD_DSURF)UserDefined)->sizl.cx *
|
|
((PDD_DSURF)UserDefined)->sizl.cy * 24 / 8;
|
|
}
|
|
else {
|
|
bitmapSize = ((PDD_DSURF)UserDefined)->sizl.cx *
|
|
((PDD_DSURF)UserDefined)->sizl.cy * 32 / 8;
|
|
}
|
|
|
|
// Current cache size
|
|
oeCurrentOffscreenCacheSize -= bitmapSize;
|
|
|
|
// Add this bitmap to the offscreen bitmap delete list
|
|
sbcOffscrBitmapsDelList[sbcNumOffscrBitmapsToDelete].bitmapId = iCacheEntry;
|
|
sbcOffscrBitmapsDelList[sbcNumOffscrBitmapsToDelete].bitmapSize = bitmapSize;
|
|
|
|
// Update the delete list data
|
|
sbcNumOffscrBitmapsToDelete++;
|
|
sbcOffscrBitmapsToDeleteSize += bitmapSize;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN RDPCALL SBC_CopyToWorkBitmap(
|
|
SURFOBJ *pWorkSurf,
|
|
PMEMBLT_ORDER_EXTRA_INFO pMemBltInfo,
|
|
unsigned cxSubBitmapWidth,
|
|
unsigned cySubBitmapHeight,
|
|
PPOINTL ptileOrigin,
|
|
RECTL *pDestRect)
|
|
{
|
|
BOOLEAN rc = FALSE;
|
|
RECTL destRectl;
|
|
unsigned yLastSrcRow;
|
|
|
|
DC_BEGIN_FN("SBC_CopyToWorkBitmap");
|
|
|
|
// Do the Blt to our work bitmap to perform any color/format
|
|
// conversions to get to screen format.
|
|
//
|
|
// We fiddle with the coords so that the data we want begins at
|
|
// the first byte of the work bitmap (which is the BOTTOM, as the
|
|
// bitmap is stored in bottom-up format).
|
|
//
|
|
// Note that destRectl is in exclusive coords.
|
|
destRectl.top = pMemBltInfo->TileSize - cySubBitmapHeight;
|
|
destRectl.left = 0;
|
|
destRectl.right = cxSubBitmapWidth;
|
|
destRectl.bottom = pMemBltInfo->TileSize;
|
|
|
|
// Clip the operation so that EngBitBlt does not try to copy any
|
|
// data from outside the source bitmap (it crashes if you try it!).
|
|
TRC_ASSERT((ptileOrigin->y <
|
|
pMemBltInfo->pSource->sizlBitmap.cy),
|
|
(TB, "Invalid tileOrigin.y(%d) sizlBitmap.cy(%d)",
|
|
ptileOrigin->y, pMemBltInfo->pSource->sizlBitmap.cy));
|
|
yLastSrcRow = ptileOrigin->y + (cySubBitmapHeight - 1);
|
|
if ((int)yLastSrcRow > (pMemBltInfo->pSource->sizlBitmap.cy - 1)) {
|
|
destRectl.bottom -= ((int)yLastSrcRow -
|
|
(pMemBltInfo->pSource->sizlBitmap.cy - 1));
|
|
TRC_ALT((TB, "Clip source from (%d) to (%d)",
|
|
cySubBitmapHeight, destRectl.bottom));
|
|
}
|
|
|
|
TRC_NRM((TB, "Blt to work bitmap from src point (%d,%d)",
|
|
ptileOrigin->x, ptileOrigin->y));
|
|
|
|
// Reset the work bitmap bits that we will be using if the copied
|
|
// data will not completely fill the area that we are going to
|
|
// cache (there may be some empty space to the right of the bitmap).
|
|
// This ensures that every time a bitmap is cached it has the
|
|
// same (zero) pad bytes and will match previously cached entries.
|
|
// It also aids compression (if enabled).
|
|
if ((destRectl.right - destRectl.left) < (int)pMemBltInfo->TileSize) {
|
|
unsigned cbResetBytes;
|
|
|
|
// The lDelta field in the SURFOBJ is negative because the
|
|
// bitmap is a "bottom-up" DIB.
|
|
cbResetBytes = (unsigned)((-pWorkSurf->lDelta) *
|
|
(destRectl.bottom - destRectl.top));
|
|
|
|
TRC_NRM((TB, "Reset %u bytes in work bitmap", cbResetBytes));
|
|
|
|
TRC_ASSERT((cbResetBytes <= pWorkSurf->cjBits),
|
|
(TB, "cbResetBytes(%u) too big (> %u) lDelta(%d)",
|
|
cbResetBytes, pWorkSurf->cjBits, pWorkSurf->lDelta));
|
|
|
|
memset(pWorkSurf->pvBits, 0, cbResetBytes);
|
|
}
|
|
|
|
TRC_ASSERT(((destRectl.left >= 0) &&
|
|
(destRectl.top >= 0) &&
|
|
(destRectl.right <= pWorkSurf->sizlBitmap.cx) &&
|
|
(destRectl.bottom <= pWorkSurf->sizlBitmap.cy)),
|
|
(TB, "destRect(%d, %d, %d, %d) exceeds bitmap(%d, %d)",
|
|
destRectl.left, destRectl.top, destRectl.right,
|
|
destRectl.bottom, pWorkSurf->sizlBitmap.cx,
|
|
pWorkSurf->sizlBitmap.cy));
|
|
|
|
// Now we have to fill in the backdrop bits for delta RLE bitmaps.
|
|
// We just grab screen bits from the screen bitmap to fill in the
|
|
// extents of the incoming bitmap.
|
|
if (pMemBltInfo->bDeltaRLE) {
|
|
POINTL ScrOrigin;
|
|
|
|
ScrOrigin.x = pDestRect->left;
|
|
ScrOrigin.y = pDestRect->top;
|
|
|
|
// Need to adjust the coordinates
|
|
if (ScrOrigin.y < 0) {
|
|
destRectl.top += (0 - ScrOrigin.y);
|
|
ScrOrigin.y = 0;
|
|
}
|
|
|
|
destRectl.bottom = min(destRectl.bottom,
|
|
(pMemBltInfo->pDest->sizlBitmap.cy -
|
|
ScrOrigin.y + destRectl.top));
|
|
|
|
// SRCCOPY screen to work bitmap. Note we use no XlateObj since
|
|
// the color schemes should be the same.
|
|
if (EngCopyBits(pWorkSurf, pMemBltInfo->pDest, NULL, NULL,
|
|
&destRectl, &ScrOrigin)) {
|
|
TRC_NRM((TB,"Blt screen->tile for RLE delta backdrop, "
|
|
"scr src=(%d,%d)", pDestRect->left,
|
|
pDestRect->top));
|
|
}
|
|
else {
|
|
TRC_ERR((TB,"Failed to blt screen data for RLE delta"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
// SRCCOPY the final bits to the work bitmap.
|
|
if (!EngCopyBits(pWorkSurf, pMemBltInfo->pSource, NULL,
|
|
pMemBltInfo->pXlateObj, &destRectl, ptileOrigin)) {
|
|
TRC_ERR((TB, "Failed to Blt to work bitmap"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_DBG((TB, "Completed CopyBits"));
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBC_CacheBitmapTile
|
|
//
|
|
// Caches the tiled bitmap data for the provided blt info. Returns: TRUE if
|
|
// the data is already cached, or successfully cached and a Cache Bitmap order
|
|
// sent. SrcRect and DestRect are in exclusive coordinates. Returns FALSE
|
|
// if the Cache Bitmap order allocation fails.
|
|
/****************************************************************************/
|
|
BOOLEAN RDPCALL SBC_CacheBitmapTile(
|
|
PDD_PDEV ppdev,
|
|
PMEMBLT_ORDER_EXTRA_INFO pMemBltInfo,
|
|
RECTL *pSrcRect,
|
|
RECTL *pDestRect)
|
|
{
|
|
BOOLEAN rc = FALSE;
|
|
BOOLEAN fSearchFastPath;
|
|
BOOLEAN fFastPathMatch;
|
|
POINTL tileOrigin;
|
|
unsigned cxSubBitmapWidth, cySubBitmapHeight;
|
|
unsigned fastPathIndex;
|
|
SURFOBJ *pWorkSurf = NULL;
|
|
void *UserDefined;
|
|
CHDataKeyContext CHContext;
|
|
|
|
DC_BEGIN_FN("SBC_CacheBitmapTile");
|
|
|
|
pddCacheStats[BITMAP].CacheReads++;
|
|
|
|
TRC_NRM((TB, "Request to cache MemBlt (%d, %d), %d x %d -> (%d, %d), "
|
|
"src %p", pSrcRect->left, pSrcRect->top,
|
|
pSrcRect->right - pSrcRect->left,
|
|
pSrcRect->bottom - pSrcRect->top,
|
|
pDestRect->left, pDestRect->top,
|
|
pMemBltInfo->pSource->hsurf));
|
|
TRC_NRM((TB, "bmpWidth(%u) bmpHeight(%u) TileSize(%u)",
|
|
pMemBltInfo->pSource->sizlBitmap.cx,
|
|
pMemBltInfo->pSource->sizlBitmap.cy,
|
|
pMemBltInfo->TileSize));
|
|
|
|
// In stress, we have seen cases where fCachingEnabled is NULL when called
|
|
// in this code path from OEEncodeMemBlt
|
|
if (!pddShm->sbc.fCachingEnabled) {
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Calculate the tile origin within the source bitmap coordinates and
|
|
// the size of the remaining bitmap. Origin is rounded down to the
|
|
// nearest tile. Actual size of bitmap to cache may be smaller than
|
|
// tile size if the tile runs off the right/bottom of the bitmap.
|
|
// Note that since TileSize is a power of 2, we can accelerate the
|
|
// modulo operation.
|
|
tileOrigin.x = pSrcRect->left - (pSrcRect->left &
|
|
(pMemBltInfo->TileSize - 1));
|
|
tileOrigin.y = pSrcRect->top - (pSrcRect->top &
|
|
(pMemBltInfo->TileSize - 1));
|
|
|
|
// Actual size of bitmap to cache may be smaller than tile size if the
|
|
// tile runs off the right/bottom of the bitmap. To see why this
|
|
// calculation is correct, realize that (bmpWidth - tileOrigin.x) is
|
|
// the remaining width of the bitmap after the start of this tile.
|
|
cxSubBitmapWidth = min(pMemBltInfo->TileSize,
|
|
(unsigned)(pMemBltInfo->pSource->sizlBitmap.cx - tileOrigin.x));
|
|
cySubBitmapHeight = min(pMemBltInfo->TileSize,
|
|
(unsigned)(pMemBltInfo->pSource->sizlBitmap.cy - tileOrigin.y));
|
|
|
|
// We need not search the fast-path cache if we've forced fastpath off.
|
|
fSearchFastPath = !pMemBltInfo->bNoFastPathCaching;
|
|
fFastPathMatch = FALSE;
|
|
|
|
// The BMF_DONTCACHE flag indicates that the source surface is an
|
|
// application-controlled DIB. The iUniq flag can therefore not be
|
|
// used to determine if/when the bitmap is updated, and we
|
|
// cannot use fastpathing to handle this surface.
|
|
if (pMemBltInfo->pSource->iType == STYPE_BITMAP &&
|
|
pMemBltInfo->pSource->fjBitmap & BMF_DONTCACHE) {
|
|
TRC_NRM((TB, "Source hsurf(%p) has BMF_DONTCACHE set",
|
|
pMemBltInfo->pSource->hsurf));
|
|
fSearchFastPath = FALSE;
|
|
}
|
|
|
|
if (fSearchFastPath) {
|
|
SBC_FAST_PATH_INFO fastPathInfo;
|
|
|
|
fastPathInfo.hsurf = pMemBltInfo->pSource->hsurf;
|
|
fastPathInfo.iUniq = pMemBltInfo->pSource->iUniq;
|
|
fastPathInfo.iDeviceUniq = pMemBltInfo->iDeviceUniq;
|
|
fastPathInfo.pXlateObj = pMemBltInfo->pXlateObj;
|
|
fastPathInfo.iUniqXlate = ((pMemBltInfo->pXlateObj != NULL) ?
|
|
pMemBltInfo->pXlateObj->iUniq : 0);
|
|
fastPathInfo.tileOrigin = tileOrigin;
|
|
fastPathInfo.TileSize = pMemBltInfo->TileSize;
|
|
fastPathInfo.bDeltaRLE = pMemBltInfo->bDeltaRLE;
|
|
|
|
CH_CreateKeyFromFirstData(&CHContext, &fastPathInfo,
|
|
sizeof(fastPathInfo));
|
|
if (CH_SearchCache(pddShm->sbc.hFastPathCache, CHContext.Key1,
|
|
CHContext.Key2, &UserDefined, &fastPathIndex)) {
|
|
CHCACHEHANDLE hCache;
|
|
|
|
// Found match in fast path. UserDefined is a pointer to the
|
|
// real CHNODE for the bitmap.
|
|
hCache = CH_GetCacheHandleFromNode((CHNODE *)UserDefined);
|
|
pMemBltInfo->CacheID = (unsigned)(UINT_PTR)CH_GetCacheContext(
|
|
hCache);
|
|
pMemBltInfo->CacheIndex = CH_GetCacheIndexFromNode(
|
|
(CHNODE *)UserDefined);
|
|
|
|
TRC_NRM((TB, "FP hit: cacheId(%u) cacheIndex(%u) FPIndex(%u)"
|
|
"hsurf(%p) iUniq(%u) pXlate(%p) iUniqX(%u) "
|
|
"tileOrigin.x(%d) tileOrigin.y(%d) "
|
|
"TileSize(%d), bDeltaRLE(%u)",
|
|
pMemBltInfo->CacheID, pMemBltInfo->CacheIndex,
|
|
fastPathIndex, fastPathInfo.hsurf,
|
|
fastPathInfo.iUniq, fastPathInfo.pXlateObj,
|
|
fastPathInfo.iUniqXlate,
|
|
fastPathInfo.tileOrigin.x, fastPathInfo.tileOrigin.y,
|
|
fastPathInfo.TileSize, fastPathInfo.bDeltaRLE));
|
|
fFastPathMatch = TRUE;
|
|
|
|
#ifdef DC_DEBUG
|
|
// Verify that the bits for this are identical to the real bits
|
|
pWorkSurf = EngLockSurface(pddShm->sbc.bitmapCacheInfo[
|
|
pMemBltInfo->TileID].hWorkBitmap);
|
|
if (pWorkSurf)
|
|
{
|
|
if (SBC_CopyToWorkBitmap(pWorkSurf, pMemBltInfo, cxSubBitmapWidth,
|
|
cySubBitmapHeight, &tileOrigin, pDestRect))
|
|
{
|
|
SBC_VerifyBitmapBits(pWorkSurf->pvBits,
|
|
TS_BYTES_IN_BITMAP(pMemBltInfo->TileSize, cySubBitmapHeight, sbcClientBitsPerPel),
|
|
pMemBltInfo->CacheID,
|
|
pMemBltInfo->CacheIndex);
|
|
}
|
|
|
|
EngUnlockSurface(pWorkSurf);
|
|
pWorkSurf = NULL;
|
|
}
|
|
#endif //DC_DEBUG
|
|
|
|
pddCacheStats[BITMAP].CacheHits++;
|
|
}
|
|
else {
|
|
TRC_NRM((TB, "FP miss: hsurf(%p) iUniq(%u) pXlate(%p) "
|
|
"iUniqX(%u) tileOrigin.x(%d) tileOrigin.y(%d) "
|
|
"TileSize(%d), bDeltaRLE(%u)",
|
|
fastPathInfo.hsurf, fastPathInfo.iUniq,
|
|
fastPathInfo.pXlateObj, fastPathInfo.iUniqXlate,
|
|
fastPathInfo.tileOrigin.x, fastPathInfo.tileOrigin.y,
|
|
fastPathInfo.TileSize, fastPathInfo.bDeltaRLE));
|
|
}
|
|
}
|
|
|
|
if (!fFastPathMatch) {
|
|
// We know how large a tile we have - we now have to Blt it into
|
|
// the work bitmap corresponding to the TileID.
|
|
|
|
// Lock the work bitmap to get a surface to pass to EngBitBlt.
|
|
pWorkSurf = EngLockSurface(pddShm->sbc.bitmapCacheInfo[
|
|
pMemBltInfo->TileID].hWorkBitmap);
|
|
if (pWorkSurf == NULL) {
|
|
TRC_ERR((TB, "Failed to lock work surface"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_DBG((TB, "Locked surface"));
|
|
|
|
if (!SBC_CopyToWorkBitmap(pWorkSurf, pMemBltInfo, cxSubBitmapWidth,
|
|
cySubBitmapHeight, &tileOrigin, pDestRect))
|
|
{
|
|
TRC_ERR((TB, "Failed to copy bitmap to work surface"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Cache the bits in the main cache, including sending a Cache
|
|
// Bitmap seondary order if need be.
|
|
if (!SBCCacheBits(ppdev, pWorkSurf->pvBits, cxSubBitmapWidth,
|
|
pMemBltInfo->TileSize, cySubBitmapHeight,
|
|
TS_BYTES_IN_BITMAP(pMemBltInfo->TileSize,
|
|
cySubBitmapHeight, sbcClientBitsPerPel),
|
|
pMemBltInfo->TileID,
|
|
#ifdef PERF_SPOILING
|
|
&pMemBltInfo->CacheID, &pMemBltInfo->CacheIndex,
|
|
pMemBltInfo->bIsPrimarySurface)) {
|
|
#else
|
|
&pMemBltInfo->CacheID, &pMemBltInfo->CacheIndex)) {
|
|
#endif
|
|
TRC_ERR((TB, "Failed to cache bits"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
// If we could search for this bitmap in the fast-path cache, add
|
|
// it to the fast-path.
|
|
// However, skip this step if the bitmap is in the waiting list only
|
|
if (fSearchFastPath &&
|
|
pMemBltInfo->CacheIndex != BITMAPCACHE_WAITING_LIST_INDEX) {
|
|
CHNODE *pFastPathNode;
|
|
CHCACHEHANDLE hCache;
|
|
|
|
// Get the handle of the cache into which we just placed the
|
|
// bitmap.
|
|
hCache = pddShm->sbc.bitmapCacheInfo[pMemBltInfo->CacheID].
|
|
cacheHandle;
|
|
|
|
// Check if there is already a fast-path cache entry for this
|
|
// node. If so, we need to remove it before adding this new
|
|
// fast path entry. We maintain a one-to-one correspondence to
|
|
// save memory and time, and because the old fast-path entry is
|
|
// probably stale and won't be seen again.
|
|
//
|
|
// UserDefined in free builds is a pointer to the CHNODE in the
|
|
// real bitmap cache; otherwise it is an indirect pointer
|
|
// to the CHNODE contained in a blob of memory used to hold the
|
|
// bitmap data corresponding to the key to verify that the key
|
|
// generation algorithm is working okay.
|
|
pFastPathNode = (CHNODE *)CH_GetUserDefined(hCache,
|
|
pMemBltInfo->CacheIndex);
|
|
if (pFastPathNode != NULL)
|
|
CH_RemoveCacheEntry(pddShm->sbc.hFastPathCache,
|
|
CH_GetCacheIndexFromNode(pFastPathNode));
|
|
|
|
// Reuse the key created before for fast search.
|
|
// We do not care if we evict a fast-path cache entry
|
|
// when adding a new one -- the cache callbacks ensure that
|
|
// both sets of cache entries are updated with respect to each
|
|
// other.
|
|
fastPathIndex = CH_CacheKey(pddShm->sbc.hFastPathCache,
|
|
CHContext.Key1, CHContext.Key2,
|
|
(void *)CH_GetNodeFromCacheIndex(hCache,
|
|
pMemBltInfo->CacheIndex));
|
|
|
|
// Now change the UserDefined for the entry in the main cache.
|
|
// This allows us to remove the fast-path entry when main cache
|
|
// entry goes away.
|
|
CH_SetUserDefined(hCache, pMemBltInfo->CacheIndex,
|
|
CH_GetNodeFromCacheIndex(pddShm->sbc.hFastPathCache,
|
|
fastPathIndex));
|
|
|
|
TRC_NRM((TB, "FP add: cacheId(%u) cacheIndex(%u) FPIndex(%u)"
|
|
"hsurf(%p) iUniq(%u) pXlate(%p) iUniqX(%u) "
|
|
"tileOrigin.x(%d) tileOrigin.y(%d) TileSize(%d) "
|
|
"bDeltaRLE(%u)",
|
|
pMemBltInfo->CacheID, pMemBltInfo->CacheIndex,
|
|
fastPathIndex, pMemBltInfo->pSource->hsurf,
|
|
pMemBltInfo->pSource->iUniq, pMemBltInfo->pXlateObj,
|
|
((pMemBltInfo->pXlateObj != NULL) ?
|
|
pMemBltInfo->pXlateObj->iUniq : 0),
|
|
tileOrigin.x, tileOrigin.y,
|
|
pMemBltInfo->TileSize, pMemBltInfo->bDeltaRLE));
|
|
}
|
|
}
|
|
|
|
TRC_ASSERT((pMemBltInfo->CacheID < pddShm->sbc.NumBitmapCaches),
|
|
(TB, "Invalid bm cacheid %u (max %u)", pMemBltInfo->CacheID,
|
|
pddShm->sbc.NumBitmapCaches - 1));
|
|
TRC_NRM((TB, "cacheId(%u) cacheIndex(%u)", pMemBltInfo->CacheID,
|
|
pMemBltInfo->CacheIndex));
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
if (NULL != pWorkSurf)
|
|
{
|
|
EngUnlockSurface(pWorkSurf);
|
|
TRC_DBG((TB, "Unlocked surface"));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCSelectBitmapCache
|
|
//
|
|
// Determines the destination cell for a tiled bitmap based on the size and
|
|
// the TileID. Since all bitmaps are derived from tiles, this function cannot
|
|
// fail -- at worst we have to use the same CacheID as the TileID.
|
|
/****************************************************************************/
|
|
__inline unsigned RDPCALL SBCSelectBitmapCache(
|
|
unsigned BitmapSize,
|
|
unsigned TileID)
|
|
{
|
|
unsigned CacheID;
|
|
|
|
DC_BEGIN_FN("SBCSelectBitmapCache");
|
|
|
|
// We scan from the smallest tile size to the TileID size to try to find
|
|
// the smallest possible size that will hold the bitmap.
|
|
for (CacheID = 0; CacheID < TileID; CacheID++) {
|
|
if (BitmapSize <= (unsigned)SBC_CellSizeFromCacheID(CacheID)) {
|
|
TRC_DBG((TB,"Selected CacheID %u for BitmapSize %u", CacheID,
|
|
BitmapSize));
|
|
break;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return CacheID;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBCCacheBits: This function ensures that on return the supplied bitmap is
|
|
// in the bitmap cache. If the data is not already in the cache it is added
|
|
// (possibly evicting another entry).
|
|
//
|
|
// 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.
|
|
/****************************************************************************/
|
|
|
|
// Encode a value in one or two bytes. The high bit of the first byte is 0 if
|
|
// there is only one byte, 1 if there are 2 (with the 7 low bits of the first
|
|
// byte being most significant).
|
|
__inline void Encode2ByteField(
|
|
BYTE *pEncode,
|
|
unsigned Val,
|
|
unsigned *pOrderSize)
|
|
{
|
|
if (Val <= 127) {
|
|
*pEncode = (BYTE)Val;
|
|
(*pOrderSize)++;
|
|
}
|
|
else {
|
|
*pEncode = (BYTE)(((Val & 0x7F00) >> 8) | 0x80);
|
|
*(pEncode + 1) = (BYTE)(Val & 0x00FF);
|
|
(*pOrderSize) += 2;
|
|
}
|
|
}
|
|
|
|
// Encode a value in up to 4 bytes. The high 2 bits of the first byte indicate
|
|
// the length of the encoding -- 00 is 1 byte, 01 is 2 bytes, 10 is 3 bytes,
|
|
// 11 is 4 bytes. The bytes are encoded with the most significant bits in the
|
|
// low 6 bits of the first byte, the least signifiant bits in the last byte.
|
|
__inline void Encode4ByteField(
|
|
BYTE *pEncode,
|
|
unsigned Val,
|
|
unsigned *pOrderSize)
|
|
{
|
|
if (Val <= 0x3F) {
|
|
*pEncode = (BYTE)Val;
|
|
(*pOrderSize)++;
|
|
}
|
|
else if (Val <= 0x3FFF) {
|
|
*pEncode = (BYTE)(((Val & 0x3F00) >> 8) | 0x40);
|
|
*(pEncode + 1) = (BYTE)(Val & 0x00FF);
|
|
(*pOrderSize) += 2;
|
|
}
|
|
else if (Val <= 0x3FFFFF) {
|
|
*pEncode = (BYTE)(((Val & 0x3F0000) >> 16) | 0x80);
|
|
*(pEncode + 1) = (BYTE)((Val & 0x00FF00) >> 8);
|
|
*(pEncode + 2) = (BYTE)(Val & 0x0000FF);
|
|
(*pOrderSize) += 3;
|
|
}
|
|
else {
|
|
*pEncode = (BYTE)(((Val & 0x3F000000) >> 24) | 0xC0);
|
|
*(pEncode + 1) = (BYTE)((Val & 0x00FF0000) >> 16);
|
|
*(pEncode + 2) = (BYTE)((Val & 0x0000FF00) >> 8);
|
|
*(pEncode + 3) = (BYTE)(Val & 0x000000FF);
|
|
(*pOrderSize) += 4;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef DC_DEBUG
|
|
BOOL SBC_VerifyBitmapBits(PBYTE pBitmapData, unsigned cbBitmapSize, UINT iCacheID, UINT iCacheIndex)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
SBC_BITMAP_CACHE_EXTRA_INFO *pBitmapHdr;
|
|
unsigned BitmapHdrSize;
|
|
BYTE *pStoredBitmapData;
|
|
|
|
DC_BEGIN_FN("SBC_VerifyBitmapBits");
|
|
|
|
// In debug builds we look for a collision after checking the key
|
|
// and checksum, by comparing the bitmap bits.
|
|
BitmapHdrSize = sizeof(SBC_BITMAP_CACHE_EXTRA_INFO) +
|
|
SBC_CellSizeFromCacheID(iCacheID);
|
|
|
|
if (pddShm->sbc.bitmapCacheInfo[iCacheID].pExtraEntryInfo != NULL) {
|
|
pBitmapHdr = (SBC_BITMAP_CACHE_EXTRA_INFO *)(pddShm->sbc.
|
|
bitmapCacheInfo[iCacheID].pExtraEntryInfo +
|
|
BitmapHdrSize * iCacheIndex);
|
|
pStoredBitmapData = (BYTE *)pBitmapHdr +
|
|
sizeof(SBC_BITMAP_CACHE_EXTRA_INFO);
|
|
|
|
if (pBitmapHdr->DataSize != 0) {
|
|
TRC_NRM((TB,"Hit non-persistent cell entry, cache=%d, "
|
|
"index=%d", iCacheID, iCacheIndex));
|
|
|
|
if (pBitmapHdr->DataSize != cbBitmapSize)
|
|
{
|
|
TRC_ERR((TB,"Size mismatch between stored and new bitmap "
|
|
"data! (stored=0x%X, new=0x%X)", pBitmapHdr->DataSize,
|
|
cbBitmapSize));
|
|
|
|
fRetVal = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (memcmp(pStoredBitmapData, pBitmapData, cbBitmapSize))
|
|
{
|
|
TRC_ERR((TB,"Key-data mismatch - pStoredData=%p, "
|
|
"pNewData=%p, size=0x%X", pStoredBitmapData,
|
|
pBitmapData, cbBitmapSize));
|
|
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB,"Persistent cell bitmap entry hit, cache=%d, "
|
|
"index=%d", *pCacheID, *pCacheIndex));
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fRetVal;
|
|
}
|
|
#endif //DC_DEBUG
|
|
|
|
|
|
BOOLEAN RDPCALL SBCCacheBits(
|
|
PDD_PDEV ppdev,
|
|
PBYTE pBitmapData,
|
|
unsigned bitmapWidth,
|
|
unsigned paddedBitmapWidth,
|
|
unsigned bitmapHeight,
|
|
unsigned cbBitmapSize,
|
|
unsigned TileID,
|
|
PUINT pCacheID,
|
|
#ifdef PERF_SPOILING
|
|
PUINT pCacheIndex,
|
|
BOOL bIsPrimarySurface)
|
|
#else
|
|
PUINT pCacheIndex)
|
|
#endif
|
|
{
|
|
BOOLEAN rc = TRUE;
|
|
BOOLEAN bOnWaitingList = FALSE;
|
|
unsigned compressedSize;
|
|
PSBC_BITMAP_CACHE_INFO pCacheInfo;
|
|
INT_ORDER *pOrder;
|
|
unsigned BitmapSpace;
|
|
unsigned OrderSize;
|
|
PTS_SECONDARY_ORDER_HEADER pHdr;
|
|
unsigned cbActualOrderSize;
|
|
unsigned waitingListCacheEntry;
|
|
BYTE *pRev2BitmapSizeField;
|
|
void *UserDefined, *UserDefined2;
|
|
CHDataKeyContext CHContext;
|
|
UINT32 ExtraKeyInfo[2];
|
|
|
|
#ifdef DC_DEBUG
|
|
SBC_BITMAP_CACHE_EXTRA_INFO *pBitmapHdr;
|
|
unsigned BitmapHdrSize;
|
|
BYTE *pStoredBitmapData;
|
|
#endif
|
|
|
|
DC_BEGIN_FN("SBCCacheBits");
|
|
|
|
// Select the cache based on the data size. Note that for 4bpp bitmaps
|
|
// the size is doubled because we split the colors into individual 8bpp
|
|
// bytes indexed on a 16-color palette.
|
|
#ifdef DC_HICOLOR
|
|
// The logic regarding 4bpp holds for high color as the supplied bitmap
|
|
// size already correctly takes into account higher color depths.
|
|
*pCacheID = SBCSelectBitmapCache(
|
|
(sbcClientBitsPerPel == 4 ?
|
|
(2 * cbBitmapSize) : cbBitmapSize),
|
|
TileID);
|
|
#else
|
|
*pCacheID = SBCSelectBitmapCache((sbcClientBitsPerPel == 8 ? cbBitmapSize :
|
|
(2 * cbBitmapSize)), TileID);
|
|
#endif
|
|
TRC_NRM((TB, "Selected cache %u", *pCacheID));
|
|
|
|
pCacheInfo = &(pddShm->sbc.bitmapCacheInfo[*pCacheID]);
|
|
|
|
// Generate a key for the bitmap data. Add in the width and height of the
|
|
// blt as extra keyed data, since we don't want to collide when
|
|
// displaying blts of different dimensions but the same number of bytes
|
|
// and same contents. Also add in the checksum gathered from the bitmap
|
|
// bits to decrease the fail rate.
|
|
CH_CreateKeyFromFirstData(&CHContext, pBitmapData, cbBitmapSize);
|
|
ExtraKeyInfo[0] = (paddedBitmapWidth << 16) | bitmapHeight;
|
|
ExtraKeyInfo[1] = CHContext.Checksum;
|
|
CH_CreateKeyFromNextData(&CHContext, ExtraKeyInfo, sizeof(ExtraKeyInfo));
|
|
|
|
// If the key is already present, and its extra checksum matches,
|
|
// no need to cache.
|
|
if (CH_SearchCache(pCacheInfo->cacheHandle, CHContext.Key1,
|
|
CHContext.Key2, &UserDefined, pCacheIndex)) {
|
|
TRC_NRM((TB, "Bitmap already cached %u:%u cx(%u) cy(%u)",
|
|
*pCacheID, *pCacheIndex, bitmapWidth, bitmapHeight));
|
|
pddCacheStats[BITMAP].CacheHits++;
|
|
|
|
#ifdef DC_DEBUG
|
|
SBC_VerifyBitmapBits(pBitmapData, cbBitmapSize, *pCacheID, *pCacheIndex);
|
|
#endif
|
|
|
|
DC_QUIT;
|
|
}
|
|
|
|
// The bitmap is not in the cache list, check if it's in the waiting list
|
|
// First check if the client supports waiting list cache
|
|
if (pddShm->sbc.fAllowCacheWaitingList) {
|
|
// The bitmap is in the waiting list, so cache it now, first remove
|
|
// it from the waiting list
|
|
if (CH_SearchCache(pCacheInfo->waitingListHandle, CHContext.Key1,
|
|
CHContext.Key2, &UserDefined2, &waitingListCacheEntry)) {
|
|
CH_RemoveCacheEntry(pCacheInfo->waitingListHandle, waitingListCacheEntry);
|
|
goto CacheBitmap;
|
|
}
|
|
else {
|
|
// The bitmap is not in the waiting list, put it in the waiting list
|
|
// don't cache for this round, if we see it again, then we'll cache it
|
|
waitingListCacheEntry = CH_CacheKey(pCacheInfo->waitingListHandle,
|
|
CHContext.Key1, CHContext.Key2, NULL);
|
|
*pCacheIndex = BITMAPCACHE_WAITING_LIST_INDEX;
|
|
|
|
#ifdef PERF_SPOILING
|
|
// We waitlisted this tile. We don't need to send it as
|
|
// cache order. We will try to send it as screen data.
|
|
if (bIsPrimarySurface) {
|
|
rc = FALSE;
|
|
DC_QUIT;
|
|
}
|
|
#endif
|
|
|
|
bOnWaitingList = TRUE;
|
|
|
|
}
|
|
}
|
|
else {
|
|
goto CacheBitmap;
|
|
}
|
|
|
|
CacheBitmap:
|
|
|
|
// Allocate an order in the order heap big enough to hold the entire
|
|
// tile. We will relinquish any extra space we don't use because of
|
|
// compression. Size is also dependent on the color depth of the client
|
|
// since for 4bpp we unpack the colors into 8 bits for the protocol.
|
|
#ifdef DC_HICOLOR
|
|
// Again, the logic holds for high color as the supplied bitmap size
|
|
// already correctly takes into account higher color depths.
|
|
BitmapSpace = cbBitmapSize * (sbcClientBitsPerPel == 4 ? 2 : 1);
|
|
TRC_DBG((TB, "Bitmap is %ux%u, size %u bytes",
|
|
paddedBitmapWidth, bitmapHeight, BitmapSpace));
|
|
#else
|
|
BitmapSpace = cbBitmapSize * (sbcClientBitsPerPel == 8 ? 1 : 2);
|
|
#endif
|
|
OrderSize = max(TS_CACHE_BITMAP_ORDER_REV2_MAX_SIZE,
|
|
(sizeof(TS_CACHE_BITMAP_ORDER) -
|
|
FIELDSIZE(TS_CACHE_BITMAP_ORDER, bitmapData))) +
|
|
BitmapSpace;
|
|
pOrder = OA_AllocOrderMem(ppdev, OrderSize);
|
|
if (pOrder != NULL) {
|
|
// We have to add the key to the cache. Note we use NULL for the
|
|
// UserDefined until we know the cache index to get the
|
|
// BITMAP_DATA_HEADER.
|
|
if (!bOnWaitingList) {
|
|
*pCacheIndex = CH_CacheKey(pCacheInfo->cacheHandle,
|
|
CHContext.Key1, CHContext.Key2, NULL);
|
|
|
|
#ifdef DC_DEBUG
|
|
// We need to store the bitmap data after the BITMAP_DATA_HEADER.
|
|
BitmapHdrSize = sizeof(SBC_BITMAP_CACHE_EXTRA_INFO) +
|
|
SBC_CellSizeFromCacheID(*pCacheID);
|
|
|
|
if (pddShm->sbc.bitmapCacheInfo[*pCacheID].pExtraEntryInfo != NULL) {
|
|
pBitmapHdr = (SBC_BITMAP_CACHE_EXTRA_INFO *)(pddShm->sbc.
|
|
bitmapCacheInfo[*pCacheID].pExtraEntryInfo +
|
|
BitmapHdrSize * *pCacheIndex);
|
|
pStoredBitmapData = (BYTE *)pBitmapHdr +
|
|
sizeof(SBC_BITMAP_CACHE_EXTRA_INFO);
|
|
pBitmapHdr->DataSize = cbBitmapSize;
|
|
memcpy(pStoredBitmapData, pBitmapData, cbBitmapSize);
|
|
}
|
|
#endif //DC_DEBUG
|
|
}
|
|
|
|
TRC_NRM((TB,"Creating new cache entry, cache=%d, index=%d\n",
|
|
*pCacheID, *pCacheIndex));
|
|
|
|
// Fill in cache bitmap order. Differentiate based on the
|
|
// order revision.
|
|
pHdr = (TS_SECONDARY_ORDER_HEADER *)pOrder->OrderData;
|
|
pHdr->orderHdr.controlFlags = TS_STANDARD | TS_SECONDARY;
|
|
// Fill in pHdr->orderType when we know it below.
|
|
|
|
if (pddShm->sbc.bUseRev2CacheBitmapOrder) {
|
|
TS_CACHE_BITMAP_ORDER_REV2_HEADER *pCacheOrderHdr;
|
|
|
|
// Revision 2 order.
|
|
pCacheOrderHdr = (TS_CACHE_BITMAP_ORDER_REV2_HEADER *)
|
|
pOrder->OrderData;
|
|
|
|
// Set up the CacheID and BitsPerPelID in header.extraFlags.
|
|
// If the client supports noBitmapCompression Header, we have to
|
|
// turn on the no-compression-header flag to indicate that
|
|
// this order doesn't contain the header. This is necessary in
|
|
// addition to capability negotiation because shadow can turn
|
|
// this cap off.
|
|
#ifdef DC_HICOLOR
|
|
if (!bOnWaitingList) {
|
|
pCacheOrderHdr->header.extraFlags = *pCacheID | sbcCacheFlags |
|
|
pddShm->bc.noBitmapCompressionHdr;
|
|
}
|
|
else {
|
|
pCacheOrderHdr->header.extraFlags = *pCacheID | sbcCacheFlags |
|
|
pddShm->bc.noBitmapCompressionHdr |
|
|
TS_CacheBitmapRev2_bNotCacheFlag;
|
|
}
|
|
|
|
#else
|
|
pCacheOrderHdr->header.extraFlags = *pCacheID |
|
|
TS_CacheBitmapRev2_8BitsPerPel |
|
|
pddShm->bc.noBitmapCompressionHdr;
|
|
#endif
|
|
|
|
// We'll write over the key values if the cache is tagged
|
|
// as non-persistent.
|
|
pCacheOrderHdr->Key1 = CHContext.Key1;
|
|
pCacheOrderHdr->Key2 = CHContext.Key2;
|
|
|
|
// Now add the variable-sized fields.
|
|
|
|
// Bitmap key.
|
|
if (pCacheInfo->Info.bSendBitmapKeys) {
|
|
cbActualOrderSize =
|
|
sizeof(TS_CACHE_BITMAP_ORDER_REV2_HEADER);
|
|
pCacheOrderHdr->header.extraFlags |=
|
|
TS_CacheBitmapRev2_bKeyPresent_Mask;
|
|
}
|
|
else {
|
|
cbActualOrderSize =
|
|
sizeof(TS_CACHE_BITMAP_ORDER_REV2_HEADER) -
|
|
2 * sizeof(UINT32);
|
|
}
|
|
|
|
// Real width of the bits in this tile.
|
|
Encode2ByteField((BYTE *)pCacheOrderHdr + cbActualOrderSize,
|
|
paddedBitmapWidth, &cbActualOrderSize);
|
|
|
|
// Height, if not same as width.
|
|
if (paddedBitmapWidth == bitmapHeight) {
|
|
pCacheOrderHdr->header.extraFlags |=
|
|
TS_CacheBitmapRev2_bHeightSameAsWidth_Mask;
|
|
}
|
|
else {
|
|
Encode2ByteField((BYTE *)pCacheOrderHdr + cbActualOrderSize,
|
|
bitmapHeight, &cbActualOrderSize);
|
|
}
|
|
|
|
// Bitmap size: Here we have to lose a bit of performance.
|
|
// We have not yet compressed the bitmap and so cannot determine
|
|
// size of this field (see Encode4ByteField() above). Since we
|
|
// know that the size is never bigger than 4K (64x64 tile), we
|
|
// can just set up to always encode a 2-byte size even if the
|
|
// compressed size is less than 128 (this can cause a bit of a
|
|
// wire performance hit).
|
|
//TODO: If we add tile sizes above 64x64 we will need to modify this logic to
|
|
// handle the potential 3-byte sizes.
|
|
pRev2BitmapSizeField = (BYTE *)pCacheOrderHdr + cbActualOrderSize;
|
|
cbActualOrderSize += 2;
|
|
//TODO: Not encoding the streaming bitmap size field here, needs to be added if
|
|
// bitmap streaming is enabled.
|
|
|
|
Encode2ByteField((BYTE *)pCacheOrderHdr + cbActualOrderSize,
|
|
*pCacheIndex, &cbActualOrderSize);
|
|
}
|
|
else {
|
|
PTS_CACHE_BITMAP_ORDER pCacheOrder;
|
|
|
|
// Revision 1 order.
|
|
pCacheOrder = (PTS_CACHE_BITMAP_ORDER)pOrder->OrderData;
|
|
|
|
// If the client supports noBitmapCompression Header, we have to
|
|
// turn on the no-compression-header flag to indicate that
|
|
// this order doesn't contain the header. This is necessary in
|
|
// addition to capability negotiation because shadow can turn
|
|
// this cap off
|
|
pCacheOrder->header.extraFlags = pddShm->bc.noBitmapCompressionHdr;
|
|
pCacheOrder->cacheId = (BYTE)*pCacheID;
|
|
pCacheOrder->pad1octet = 0;
|
|
pCacheOrder->bitmapWidth = (BYTE)paddedBitmapWidth;
|
|
pCacheOrder->bitmapHeight = (BYTE)bitmapHeight;
|
|
#ifdef DC_HICOLOR
|
|
pCacheOrder->bitmapBitsPerPel = (BYTE)sbcClientBitsPerPel;
|
|
#else
|
|
pCacheOrder->bitmapBitsPerPel = (BYTE)SBC_PROTOCOL_BPP;
|
|
#endif
|
|
// We fill in pCacheOrder->bitmapLength when we have it below.
|
|
pCacheOrder->cacheIndex = (UINT16)*pCacheIndex;
|
|
cbActualOrderSize = sizeof(TS_CACHE_BITMAP_ORDER) -
|
|
FIELDSIZE(TS_CACHE_BITMAP_ORDER, bitmapData);
|
|
}
|
|
|
|
#ifdef DC_HICOLOR
|
|
if (sbcClientBitsPerPel != 4)
|
|
#else
|
|
if (sbcClientBitsPerPel == 8)
|
|
#endif
|
|
{
|
|
|
|
compressedSize = cbBitmapSize;
|
|
}
|
|
else {
|
|
BYTE *pEnd, *pSrc, *pDst;
|
|
|
|
compressedSize = cbBitmapSize * 2;
|
|
|
|
// Expand the 4bpp packing into full bytes -- protocol is 8bpp
|
|
// and we need to have these bits before compressing.
|
|
pEnd = pBitmapData + cbBitmapSize;
|
|
pSrc = pBitmapData;
|
|
pDst = sbcXlateBuf;
|
|
while (pSrc < pEnd) {
|
|
*pDst = (*pSrc >> 4) & 0xF;
|
|
pDst++;
|
|
*pDst = *pSrc & 0xF;
|
|
pDst++;
|
|
pSrc++;
|
|
}
|
|
|
|
pBitmapData = sbcXlateBuf;
|
|
}
|
|
|
|
// Try to compress the bitmap data, or copy it if the
|
|
// compression will do no good.
|
|
#ifdef DC_HICOLOR
|
|
if (BC_CompressBitmap(pBitmapData,
|
|
pOrder->OrderData + cbActualOrderSize,
|
|
NULL,
|
|
compressedSize,
|
|
&compressedSize,
|
|
paddedBitmapWidth,
|
|
bitmapHeight,
|
|
sbcClientBitsPerPel))
|
|
#else
|
|
if (BC_CompressBitmap(pBitmapData, pOrder->OrderData +
|
|
cbActualOrderSize, compressedSize,
|
|
&compressedSize, paddedBitmapWidth, bitmapHeight))
|
|
#endif
|
|
{
|
|
TRC_NRM((TB, "Compressed to %u bytes", compressedSize));
|
|
if (pddShm->sbc.bUseRev2CacheBitmapOrder) {
|
|
pHdr->orderType = TS_CACHE_BITMAP_COMPRESSED_REV2;
|
|
|
|
// Encode 2 bytes for size within 4-byte encoding.
|
|
TRC_ASSERT((compressedSize <= 0x3FFF),
|
|
(TB,"compressedSize too large for 2 bytes!"));
|
|
*pRev2BitmapSizeField = (BYTE)(compressedSize >> 8) | 0x40;
|
|
*(pRev2BitmapSizeField + 1) = (BYTE)(compressedSize &
|
|
0x00FF);
|
|
}
|
|
else {
|
|
pHdr->orderType = TS_CACHE_BITMAP_COMPRESSED;
|
|
((PTS_CACHE_BITMAP_ORDER)pOrder->OrderData)->
|
|
bitmapLength = (UINT16)compressedSize;
|
|
}
|
|
}
|
|
else {
|
|
// Failed to compress bitmap data, so just copy it
|
|
// uncompressed.
|
|
TRC_NRM((TB, "Failed to compress %u bytes, copying",
|
|
compressedSize));
|
|
memcpy(pOrder->OrderData + cbActualOrderSize,
|
|
pBitmapData, compressedSize);
|
|
|
|
if (pddShm->sbc.bUseRev2CacheBitmapOrder) {
|
|
pHdr->orderType = TS_CACHE_BITMAP_UNCOMPRESSED_REV2;
|
|
|
|
// Encode 2 bytes for size within 4-byte encoding.
|
|
TRC_ASSERT((compressedSize <= 0x3FFF),
|
|
(TB,"compressedSize too large for 2 bytes!"));
|
|
*pRev2BitmapSizeField = (BYTE)(compressedSize >> 8) | 0x40;
|
|
*(pRev2BitmapSizeField + 1) = (BYTE)(compressedSize &
|
|
0x00FF);
|
|
}
|
|
else {
|
|
pHdr->orderType = TS_CACHE_BITMAP_UNCOMPRESSED;
|
|
((PTS_CACHE_BITMAP_ORDER)pOrder->OrderData)->
|
|
bitmapLength = (UINT16)compressedSize;
|
|
}
|
|
}
|
|
|
|
pHdr->orderLength = (UINT16)
|
|
TS_CALCULATE_SECONDARY_ORDER_ORDERLENGTH(
|
|
cbActualOrderSize + compressedSize);
|
|
|
|
// Return any extra space to the order heap.
|
|
OA_TruncateAllocatedOrder(pOrder, cbActualOrderSize +
|
|
compressedSize);
|
|
|
|
// Add the order.
|
|
OA_AppendToOrderList(pOrder);
|
|
INC_OUTCOUNTER(OUT_CACHEBITMAP);
|
|
ADD_OUTCOUNTER(OUT_CACHEBITMAP_BYTES, cbActualOrderSize +
|
|
compressedSize);
|
|
}
|
|
else {
|
|
TRC_ALT((TB, "Failed to alloc cache bitmap order size %d", OrderSize));
|
|
INC_OUTCOUNTER(OUT_CACHEBITMAP_FAILALLOC);
|
|
rc = FALSE;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
// SBC_SendCacheColorTableOrder
|
|
//
|
|
// Queues a color table order if the palette has
|
|
// changed since the last call to this function.
|
|
//
|
|
// Returns: TRUE if no action required, or color table successfully
|
|
// queued. FALSE otherwise.
|
|
//
|
|
// Params: pPDev - pointer to PDev
|
|
// pCacheIndex - pointer to variable that receives cache index
|
|
/****************************************************************************/
|
|
BOOLEAN RDPCALL SBC_SendCacheColorTableOrder(
|
|
PDD_PDEV pPDev,
|
|
unsigned *pCacheIndex)
|
|
{
|
|
int orderSize;
|
|
void *UserDefined;
|
|
CHDataKeyContext CHContext;
|
|
BOOLEAN rc = TRUE;
|
|
unsigned numColors;
|
|
unsigned i;
|
|
PINT_ORDER pOrder;
|
|
PTS_CACHE_COLOR_TABLE_ORDER pColorTableOrder;
|
|
|
|
DC_BEGIN_FN("SBC_SendCacheColorTableOrder");
|
|
|
|
// Currently only support 8bpp protocol.
|
|
TRC_ASSERT((pPDev->cProtocolBitsPerPel == SBC_PROTOCOL_BPP),
|
|
(TB, "Unexpected bpp: %u", pPDev->cProtocolBitsPerPel));
|
|
|
|
numColors = SBC_NUM_8BPP_COLORS;
|
|
|
|
// Check the boolean in our PDEV to see if the palette has changed
|
|
// since the last time we sent a color table order.
|
|
// In high color case, no color table is needed
|
|
if (!sbcPaletteChanged || (sbcClientBitsPerPel > 8)) {
|
|
*pCacheIndex = sbcCurrentColorTableCacheIndex;
|
|
DC_QUIT;
|
|
}
|
|
|
|
// If the key is already present (very often the case), no need to cache.
|
|
CH_CreateKeyFromFirstData(&CHContext, (BYTE *)(pPDev->Palette),
|
|
numColors * sizeof(PALETTEENTRY));
|
|
if (CH_SearchCache(sbcColorTableCacheHandle, CHContext.Key1,
|
|
CHContext.Key2, &UserDefined, pCacheIndex)) {
|
|
TRC_NRM((TB, "Color table matched cache entry %u", *pCacheIndex));
|
|
DC_QUIT;
|
|
}
|
|
|
|
// We have to add the key to the cache.
|
|
*pCacheIndex = CH_CacheKey(sbcColorTableCacheHandle, CHContext.Key1,
|
|
CHContext.Key2, NULL);
|
|
|
|
// The palette has changed and is not currently in the color table
|
|
// cache. Allocate order memory to queue a color table order. The
|
|
// order size depends on the bpp of our device. Note that the
|
|
// allocation can fail if the order buffer is full.
|
|
orderSize = sizeof(TS_CACHE_COLOR_TABLE_ORDER) -
|
|
FIELDSIZE(TS_CACHE_COLOR_TABLE_ORDER, colorTable) +
|
|
(numColors * sizeof(TS_COLOR_QUAD));
|
|
|
|
pOrder = OA_AllocOrderMem(pPDev, orderSize);
|
|
if (pOrder != NULL) {
|
|
TRC_DBG((TB, "Allocate %u bytes for color table order", orderSize));
|
|
|
|
// We've successfully allocated the order, so fill in the details.
|
|
pColorTableOrder = (PTS_CACHE_COLOR_TABLE_ORDER)pOrder->OrderData;
|
|
pColorTableOrder->header.orderHdr.controlFlags = TS_STANDARD |
|
|
TS_SECONDARY;
|
|
pColorTableOrder->header.orderLength = (USHORT)
|
|
TS_CALCULATE_SECONDARY_ORDER_ORDERLENGTH(orderSize);
|
|
pColorTableOrder->header.extraFlags = 0;
|
|
pColorTableOrder->header.orderType = TS_CACHE_COLOR_TABLE;
|
|
|
|
pColorTableOrder->cacheIndex = (BYTE)*pCacheIndex;
|
|
pColorTableOrder->numberColors = (UINT16)numColors;
|
|
|
|
// Unfortunately we can't just copy the palette from the PDEV into the
|
|
// color table order because the PDEV has an array of PALETTEENTRY
|
|
// structures which are RGBs whereas the order has an array of
|
|
// RGBQUADs which are BGRs...
|
|
for (i = 0; i < numColors; i++) {
|
|
pColorTableOrder->colorTable[i].blue = pPDev->Palette[i].peRed;
|
|
pColorTableOrder->colorTable[i].green = pPDev->Palette[i].peGreen;
|
|
pColorTableOrder->colorTable[i].red = pPDev->Palette[i].peBlue;
|
|
pColorTableOrder->colorTable[i].pad1octet = 0;
|
|
}
|
|
|
|
// Add the order.
|
|
OA_AppendToOrderList(pOrder);
|
|
INC_OUTCOUNTER(OUT_CACHECOLORTABLE);
|
|
ADD_OUTCOUNTER(OUT_CACHECOLORTABLE_BYTES, orderSize);
|
|
TRC_NRM((TB, "Added internal color table order, size %u", orderSize));
|
|
|
|
// Reset the flag which indicates that the palette needs to be sent.
|
|
sbcPaletteChanged = FALSE;
|
|
|
|
sbcCurrentColorTableCacheIndex = *pCacheIndex;
|
|
TRC_NRM((TB, "Added new color table at index(%u)", *pCacheIndex));
|
|
|
|
#ifdef DC_HICOLOR
|
|
TRC_ASSERT((sbcCurrentColorTableCacheIndex <
|
|
SBC_NUM_COLOR_TABLE_CACHE_ENTRIES),
|
|
(TB, "Invalid ColorTableIndex(%u)",
|
|
sbcCurrentColorTableCacheIndex));
|
|
#endif
|
|
}
|
|
else {
|
|
rc = FALSE;
|
|
TRC_ERR((TB, "Failed to allocate %d bytes for color table order",
|
|
orderSize));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return rc;
|
|
}
|
|
|