Windows2003-3790/termsrv/drivers/rdp/rdpdd/nssidisp.c
2020-09-30 16:53:55 +02:00

943 lines
36 KiB
C

/****************************************************************************/
// nssidisp.c
//
// SaveScreenBits Interceptor API functions.
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <precmpdd.h>
#define TRC_FILE "nssidisp"
#include <winddi.h>
#include <adcg.h>
#include <adcs.h>
#include <aprot.h>
#include <aordprot.h>
#include <nddapi.h>
#include <aoaapi.h>
#include <noadisp.h>
#include <noedisp.h>
#include <acpcapi.h>
#include <ausrapi.h>
#include <nschdisp.h>
#include <nprcount.h>
#include <oe2.h>
#define DC_INCLUDE_DATA
#include <ndddata.c>
#include <oe2data.c>
#undef DC_INCLUDE_DATA
#include <assiapi.h>
#include <nssidisp.h>
#include <nssidata.c>
#include <noeinl.h>
/****************************************************************************/
// SSI_DDInit
/****************************************************************************/
void SSI_DDInit()
{
DC_BEGIN_FN("SSI_DDInit");
memset(&ssiLocalSSBState, 0, sizeof(LOCAL_SSB_STATE));
SSIResetSaveScreenBitmap();
DC_END_FN();
}
/****************************************************************************/
// SSI_InitShm
//
// Alloc-time SHM init.
/****************************************************************************/
void SSI_InitShm()
{
DC_BEGIN_FN("SSI_InitShm");
pddShm->ssi.resetInterceptor = FALSE;
pddShm->ssi.newSaveBitmapSize = FALSE;
pddShm->ssi.sendSaveBitmapSize = 0;
pddShm->ssi.newSaveBitmapSize = 0;
DC_END_FN();
}
/****************************************************************************/
// SSI_Update
//
// Called when there is an SSI update from the WD. bForce forces a reset;
// it's used by shadowing.
/****************************************************************************/
void SSI_Update(BOOL bForce)
{
DC_BEGIN_FN("SSI_Update");
if (pddShm->ssi.resetInterceptor || bForce)
SSIResetSaveScreenBitmap();
if (pddShm->ssi.saveBitmapSizeChanged || bForce) {
pddShm->ssi.sendSaveBitmapSize = pddShm->ssi.newSaveBitmapSize;
pddShm->ssi.saveBitmapSizeChanged = FALSE;
TRC_NRM((TB, "SSI caps: Size %ld", pddShm->ssi.sendSaveBitmapSize));
}
DC_END_FN();
}
/****************************************************************************/
// SSI_ClearOrderEncoding
//
// Called on share state change to reset the order state info for
// orders stored in the DD data segment.
/****************************************************************************/
void SSI_ClearOrderEncoding()
{
DC_BEGIN_FN("SSI_ClearOrderEncoding");
memset(&PrevSaveBitmap, 0, sizeof(PrevSaveBitmap));
DC_END_FN();
}
/****************************************************************************/
// SSIResetSaveScreenBitmap
//
// Resets the SaveScreenBitmap state.
/****************************************************************************/
void SSIResetSaveScreenBitmap()
{
int i;
DC_BEGIN_FN("SSIResetSaveScreenBitmap");
TRC_DBG((TB, "Reset (%d)", ssiLocalSSBState.saveLevel));
// Discard all currently saved bits.
ssiLocalSSBState.saveLevel = 0;
// Reset the number of remote pels saved.
ssiRemoteSSBState.pelsSaved = 0;
// Note that we've seen the update.
pddShm->ssi.resetInterceptor = FALSE;
// Free off any memory we may have allocated.
for (i = 0; i < SSB_MAX_SAVE_LEVEL; i++) {
if (ssiLocalSSBState.saveState[i].pSaveData != NULL) {
EngFreeMem(ssiLocalSSBState.saveState[i].pSaveData);
ssiLocalSSBState.saveState[i].pSaveData = NULL;
}
}
DC_END_FN();
}
/****************************************************************************/
// DrvSaveScreenBits - see NT DDK documentation.
/****************************************************************************/
ULONG_PTR DrvSaveScreenBits(
SURFOBJ *pso,
ULONG iMode,
ULONG_PTR ident,
RECTL *prcl)
{
ULONG_PTR rc;
unsigned ourMode;
RECTL rectTrg;
PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
PDD_DSURF pdsurf;
DC_BEGIN_FN("DrvSaveScreenBits");
// Default is FALSE: let GRE handle SaveBits if we are not in a
// position to do it ourselves - no reason for us to get in the
// business of saving off memory etc.
rc = FALSE;
// Sometimes we're called after being disconnected.
if (ddConnected && pddShm != NULL) {
// Surface is non-NULL.
pso = OEGetSurfObjBitmap(pso, &pdsurf);
INC_OUTCOUNTER(OUT_SAVESCREEN_ALL);
// Get the exclusive bounding rectangle for the operation.
RECT_FROM_RECTL(rectTrg, (*prcl));
TRC_ASSERT((pso->hsurf == ppdev->hsurfFrameBuf),
(TB, "DrvSaveScreenBits should be called for screen surface only"));
if (pso->hsurf == ppdev->hsurfFrameBuf) {
// Send a switch surface PDU if the destination surface is different
// from last drawing order. If we failed to send the PDU, we will
// just have to bail on this drawing order.
if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
TRC_ERR((TB, "failed to send the switch surface PDU"));
// We always return TRUE on SS_SAVE operations, as we
// don't want the engine saving away the bits in a bitmap
// and doing a MemBlt to restore the data (not very
// efficient). Instead we return FALSE (failure) on the
// SS_RESTORE to force User to repaint the affected area,
// which we then accumulate in the normal way.
//
// Return TRUE for SS_DISCARD too (although it shouldn't
// matter what we return).
rc = (iMode == SS_RESTORE) ? FALSE : TRUE;
DC_QUIT;
}
} else {
// We don't support DrvSaveScreenBits for offscreen
// rendering.
TRC_ERR((TB, "Offscreen blt bail"));
// We always return TRUE on SS_SAVE operations, as we
// don't want the engine saving away the bits in a bitmap
// and doing a MemBlt to restore the data (not very
// efficient). Instead we return FALSE (failure) on the
// SS_RESTORE to force User to repaint the affected area,
// which we then accumulate in the normal way.
//
// Return TRUE for SS_DISCARD too (although it shouldn't
// matter what we return).
rc = (iMode == SS_RESTORE) ? FALSE : TRUE;
DC_QUIT;
}
// Make sure we can send the order.
if (OE_SendAsOrder(TS_ENC_SAVEBITMAP_ORDER)) {
switch (iMode) {
case SS_SAVE:
TRC_DBG((TB, "SaveBits=%u", ssiLocalSSBState.saveLevel));
// Save the bits.
// Update the save level if the save was successful.
// If it was not successful then RestoreBits will not
// be called so we do not want to increment the save
// level.
rc = SSISaveBits(pso, &rectTrg);
if (rc) {
ssiLocalSSBState.saveLevel++;
// Set the returned ident value to the index of
// the save. Do this after the increment in
// order to avoid returning index 0 (0=FAIL).
rc = ssiLocalSSBState.saveLevel;
}
break;
case SS_RESTORE:
// Update the save level first.
ssiLocalSSBState.saveLevel--;
ident--;
TRC_DBG((TB, "RestoreBits (%d), ident (%u)",
ssiLocalSSBState.saveLevel, ident));
// Restore the bits.
rc = SSIRestoreBits(pso, &rectTrg, ident);
// Check for a negative save level. This will happen
// if there are outstanding saves when the share is
// started or when we get out-of-order restores/
// discards.
if (ssiLocalSSBState.saveLevel < 0) {
TRC_NRM((TB, "RestoreBits caused neg save level"));
ssiLocalSSBState.saveLevel = 0;
}
break;
case SS_FREE:
// Update the save level first.
ssiLocalSSBState.saveLevel--;
ident--;
TRC_DBG((TB, "Discard Bits (%d) ident(%d)",
ssiLocalSSBState.saveLevel, ident));
// Discard the saved bits.
rc = SSIDiscardSave(&rectTrg, ident);
// Check for a negative save level. This will happen
// if there are outstanding saves when the share is
// started or when we get out-of-order restores/
// discards.
if (ssiLocalSSBState.saveLevel < 0) {
TRC_NRM((TB, "DiscardSave caused neg save level"));
ssiLocalSSBState.saveLevel = 0;
}
break;
}
// Make an "insurance" check: If the local save level is zero
// then there should be no pels saved remotely.
if ((ssiLocalSSBState.saveLevel == 0) &&
(ssiRemoteSSBState.pelsSaved != 0)) {
TRC_ALT((TB, "Outstanding remote pels %ld",
ssiRemoteSSBState.pelsSaved ));
ssiRemoteSSBState.pelsSaved = 0;
}
TRC_DBG((TB, "RemotePelsSaved (%ld) rc %u",
ssiRemoteSSBState.pelsSaved, rc));
}
else {
// If the SaveBitmap order is not supported then return
// 0 immediately. 0 is failure for SAVE (the return value
// is a non-0 identifier for success) and FALSE is failure
// for RESTORE. If we've failed SAVEs, we can never get a
// FREE.
TRC_DBG((TB, "SaveBmp not supported"));
INC_OUTCOUNTER(OUT_SAVESCREEN_UNSUPP);
// We always return TRUE on SS_SAVE operations, as we
// don't want the engine saving away the bits in a bitmap
// and doing a MemBlt to restore the data (not very
// efficient). Instead we return FALSE (failure) on the
// SS_RESTORE to force User to repaint the affected area,
// which we then accumulate in the normal way.
//
// Return TRUE for SS_DISCARD too (although it shouldn't
// matter what we return).
rc = (iMode == SS_RESTORE) ? FALSE : TRUE;
}
}
else {
TRC_ERR((TB, "Called when disconnected"));
rc = (iMode == SS_RESTORE) ? FALSE : TRUE;
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
// SSIRemotePelsRequired
//
// Returns the number of remote pels required to store the supplied
// rectangle, taking account of the Save Bitmap granularity.
/****************************************************************************/
__inline UINT32 SSIRemotePelsRequired(PRECTL pRect)
{
UINT32 rectWidth, rectHeight;
UINT32 rc;
DC_BEGIN_FN("SSIRemotePelsRequired");
// Calculate the supplied rectangle size (it is in EXCLUSIVE coords).
rectWidth = pRect->right - pRect->left;
rectHeight = pRect->bottom - pRect->top;
// Required width and height are rounded up to next granularity level for
// that dimension.
rc = (UINT32)(((rectWidth + SAVE_BITMAP_X_GRANULARITY - 1) /
SAVE_BITMAP_X_GRANULARITY * SAVE_BITMAP_X_GRANULARITY) *
((rectHeight + SAVE_BITMAP_Y_GRANULARITY - 1) /
SAVE_BITMAP_Y_GRANULARITY * SAVE_BITMAP_Y_GRANULARITY));
DC_END_FN();
return rc;
}
/****************************************************************************/
// SSISendSaveBitmapOrder
//
// Sends a SaveBitmap order. Returns FALSE on failure.
/****************************************************************************/
BOOL SSISendSaveBitmapOrder(
PDD_PDEV ppdev,
PRECTL pRect,
unsigned SavePosition,
unsigned Operation)
{
SAVEBITMAP_ORDER *pSaveBitmapOrder;
PINT_ORDER pOrder;
BOOL rc;
DC_BEGIN_FN("SSISendSaveBitmapOrder");
TRC_NRM((TB, "Rect before conversion (%d,%d)(%d,%d)", pRect->left,
pRect->bottom, pRect->right, pRect->top));
// 1 field flag byte. Note that SaveBitmap orders are not clipped,
// so set zero for the number of clip rects.
pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(0, 1,
MAX_SAVEBITMAP_FIELD_SIZE));
if (pOrder != NULL) {
// Target rect is in exclusive coords, convert to inclusive
// for the wire format.
pSaveBitmapOrder = (SAVEBITMAP_ORDER *)oeTempOrderBuffer;
pSaveBitmapOrder->SavedBitmapPosition = SavePosition;
pSaveBitmapOrder->nLeftRect = pRect->left;
pSaveBitmapOrder->nTopRect = pRect->top;
pSaveBitmapOrder->nRightRect = pRect->right - 1;
pSaveBitmapOrder->nBottomRect = pRect->bottom - 1;
pSaveBitmapOrder->Operation = Operation;
// Slow-field-encode the order. NULL for clip rect since we don't clip
// SaveBitmaps.
pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
TS_ENC_SAVEBITMAP_ORDER, NUM_SAVEBITMAP_FIELDS,
(BYTE *)pSaveBitmapOrder, (BYTE *)&PrevSaveBitmap, etable_SV,
NULL);
INC_OUTCOUNTER(OUT_SAVEBITMAP_ORDERS);
ADD_INCOUNTER(IN_SAVEBITMAP_BYTES, pOrder->OrderLength);
OA_AppendToOrderList(pOrder);
// All done: consider sending the output.
SCH_DDOutputAvailable(ppdev, FALSE);
rc = TRUE;
TRC_NRM((TB, "SaveBitmap op %d pos %ld rect %d %d %d %d",
Operation, SavePosition, pRect->left, pRect->top,
pRect->right - 1, pRect->bottom - 1));
}
else {
TRC_ERR((TB, "Failed to alloc order mem"));
rc= FALSE;
}
DC_END_FN();
return rc;
}
/****************************************************************************/
// SSISaveBits
//
// Saves the specified screen rectangle bits and sends a SaveBitmap order.
// pRect is in exclusive coords. We return FALSE only on low-bounds errors;
// this indicates to GDI that it must simulate the SaveBits using a
// BitBlt without corresponding RestoreBits calls, which is not desirable.
// Instead, if we cannot send a SaveBitmap order or other problems, we return
// TRUE and note that we need to return FALSE on the Restore call, which
// causes a less expensive repaint of the target area.
/****************************************************************************/
BOOL SSISaveBits(SURFOBJ *pso, PRECTL pRect)
{
BOOL rc = TRUE;
DC_BEGIN_FN("SSISaveBits");
TRC_DBG((TB, "SaveScreenBits (%d, %d, %d, %d) level %d",
pRect->left, pRect->bottom, pRect->right, pRect->top,
ssiLocalSSBState.saveLevel));
// The saveLevel should never be negative.
if (ssiLocalSSBState.saveLevel >= 0) {
// If the save level is greater than the number of levels that we
// support we just return TRUE. The corresponding RestoreBits call
// will return FALSE, causing Windows to repaint the area.
// Our maximum save level is such that we should very rarely (if ever)
// go through this path.
if (ssiLocalSSBState.saveLevel < SSB_MAX_SAVE_LEVEL) {
CURRENT_LOCAL_SSB_STATE.pSaveData = NULL;
CURRENT_LOCAL_SSB_STATE.rect = *pRect;
CURRENT_LOCAL_SSB_STATE.fSavedRemotely = FALSE;
// If the rectangle to be saved intersects the current SDA then
// we will have to force a repaint on the restore. This is
// because orders are always sent before Screen Data, so if we
// sent a SAVEBITS order at this point, we would not save the
// intersecting Screen Data.
if (!OE_RectIntersectsSDA(pRect)) {
UINT32 cRemotePelsRequired;
// Calculate the number of pels required in the remote Save
// Bitmap to handle this rectangle.
cRemotePelsRequired = SSIRemotePelsRequired(pRect);
// If there aren't enough pels in the remote Save Bitmap to
// handle this rectangle then return immediately.
if ((ssiRemoteSSBState.pelsSaved + cRemotePelsRequired) <=
pddShm->ssi.sendSaveBitmapSize) {
// Try to send the SaveBits as an order.
CURRENT_LOCAL_SSB_STATE.fSavedRemotely =
SSISendSaveBitmapOrder((PDD_PDEV)(pso->dhpdev),
pRect, ssiRemoteSSBState.pelsSaved, SV_SAVEBITS);
if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely) {
// Store the relevant details in the current entry of
// the local SSB structure.
CURRENT_LOCAL_SSB_STATE.remoteSavedPosition =
ssiRemoteSSBState.pelsSaved;
CURRENT_LOCAL_SSB_STATE.remotePelsRequired =
cRemotePelsRequired;
// Update the count of remote pels saved.
ssiRemoteSSBState.pelsSaved += cRemotePelsRequired;
// Store the rectangle saved. Note that we still claim
// success, even if the copy fails. The result of this
// is that
// - we send save and restore orders to the client
// (gives bandwidth saving and client
// responsiveness)
// - we fail the restore, causing a less efficient
// repaint at the server.
// Other compromise options also available if this
// proves inappropriate.
SSICopyRect(pso, TRUE);
}
}
else {
TRC_NRM((TB, "no space for %lu pels", cRemotePelsRequired));
}
}
else {
// Note we do not save the rect via SSICopyRect -- we only
// restore when fSavedRemotely is TRUE.
TRC_DBG((TB, "SSI intersects SDA, storing failed save"));
CURRENT_LOCAL_SSB_STATE.fSavedRemotely = FALSE;
}
}
else {
// We return TRUE. On Restore, we'll get the same out-of-bounds
// value and return FALSE to repaint.
TRC_ALT((TB, "saveLevel(%d) exceeds maximum",
ssiLocalSSBState.saveLevel));
}
}
else {
// This is a real problem, so we tell GDI to to what it needs to.
TRC_ERR((TB, "SSISaveBits called with negative saveLevel"));
rc = FALSE;
}
DC_END_FN();
return rc;
}
/****************************************************************************/
/* FUNCTION: SSIFindSlotAndDiscardAbove */
/* */
/* Finds the top slot in the SSB stack which matches pRect and updates */
/* ssiLocalSSBState.saveLevel to index it. */
/* RETURNS: TRUE if a match was found, FALSE otherwise */
/****************************************************************************/
BOOL SSIFindSlotAndDiscardAbove(PRECTL pRect, ULONG_PTR ident)
{
int i;
BOOL rc = FALSE;
DC_BEGIN_FN("SSIFindSlotAndDiscardAbove");
// Find the bits we are trying to restore.
for (i = ssiLocalSSBState.saveLevel; i >= 0; i--) {
if (i == (int)ident) {
// We're at the right level in the saveState.
TRC_NRM((TB, "found match at level %d", i));
TRC_DBG((TB, "Rect matched (%d, %d, %d, %d)",
ssiLocalSSBState.saveState[i].rect.left,
ssiLocalSSBState.saveState[i].rect.bottom,
ssiLocalSSBState.saveState[i].rect.right,
ssiLocalSSBState.saveState[i].rect.top));
ssiLocalSSBState.saveLevel = i;
rc = TRUE;
DC_QUIT;
}
else {
// Discard this entry on the stack.
ssiRemoteSSBState.pelsSaved -=
ssiLocalSSBState.saveState[i].remotePelsRequired;
if (ssiLocalSSBState.saveState[i].pSaveData != NULL) {
TRC_DBG((TB, "Freeing memory at %p",
ssiLocalSSBState.saveState[i].pSaveData));
EngFreeMem(ssiLocalSSBState.saveState[i].pSaveData);
ssiLocalSSBState.saveState[i].pSaveData = NULL;
}
}
}
// If we get here we failed to match on any of the entries.
TRC_NRM((TB, "no match on stack"));
ssiLocalSSBState.saveLevel = 0;
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
// SSIRestoreBits
//
// Restores the specified screen rectangle. If the bits were saved remotely
// we make sure to send a SaveBitmap order. We return TRUE if we restored
// the bits at the client, else we return FALSE to have GDI repaint the
// target rect.
/****************************************************************************/
BOOL SSIRestoreBits(SURFOBJ *pso, PRECTL pRect, ULONG_PTR ident)
{
BOOL rc = FALSE;
DC_BEGIN_FN("SSIRestoreBits");
TRC_DBG((TB, "RestoreScreenBits (%d, %d, %d, %d) level %d",
pRect->left, pRect->bottom, pRect->right, pRect->top,
ssiLocalSSBState.saveLevel));
pddCacheStats[SSI].CacheReads++;
// If the save level is negative then either there was a save
// outstanding when we hooked the SSB or we have received out of order
// restores/discards so we discarded stuff from the SSB stack
// ourselves. We can't distinguish between these two cases at this
// point so we will always pass this on to the display driver and hope
// that it is robust enough to cope with a discard which didn't have a
// corresponding save.
if (ssiLocalSSBState.saveLevel >= 0) {
// If we don't have enough levels (rare problem), we return FALSE
// which causes a repaint.
if (ssiLocalSSBState.saveLevel < SSB_MAX_SAVE_LEVEL) {
// Search for the corresponding save order on our stack.
if (SSIFindSlotAndDiscardAbove(pRect, ident)) {
if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely) {
// Make sure GDI is giving us back the same sized
// block, otherwise the client can get messed up.
//TRC_ASSERT((CURRENT_LOCAL_SSB_STATE.remotePelsRequired ==
// SSIRemotePelsRequired(pRect)),
// (TB,"Rect (%d,%d,%d,%d) for restore level %u "
// "size %u is too large (stored size=%u)",
// pRect->left, pRect->top, pRect->right,
// pRect->bottom, ssiLocalSSBState.saveLevel,
// SSIRemotePelsRequired(pRect),
// CURRENT_LOCAL_SSB_STATE.remotePelsRequired));
// Update the remote pel count first. Even if we fail
// to send the order we want to free up the remote pels.
ssiRemoteSSBState.pelsSaved -=
CURRENT_LOCAL_SSB_STATE.remotePelsRequired;
// The bits were saved remotely, send the restore order.
TRC_DBG((TB, "Try sending the order"));
rc = SSISendSaveBitmapOrder((PDD_PDEV)(pso->dhpdev),
pRect, CURRENT_LOCAL_SSB_STATE.remoteSavedPosition,
SV_RESTOREBITS);
// Now restore the bits to the screen, so long as we sent
// the order. No point repainting the screen if we could
// not send the order as we'll want GRE+USER to redraw it
// so that we can accumulate the output.
if (rc) {
pddCacheStats[SSI].CacheHits++;
if (CURRENT_LOCAL_SSB_STATE.pSaveData != NULL) {
TRC_DBG((TB, "Restore bits to local screen"));
SSICopyRect(pso, FALSE);
}
else {
TRC_DBG((TB, "No data to restore, repaint"));
rc = FALSE;
}
}
else {
// We failed the send, but still need to discard any
// locally saved data.
if (CURRENT_LOCAL_SSB_STATE.pSaveData != NULL) {
EngFreeMem(CURRENT_LOCAL_SSB_STATE.pSaveData);
CURRENT_LOCAL_SSB_STATE.pSaveData = NULL;
}
}
}
else {
// We failed to save the bitmap remotely originally so now
// we need to return FALSE to force a repaint.
// We should never have allocated any local memory.
TRC_ASSERT((CURRENT_LOCAL_SSB_STATE.pSaveData == NULL),
(TB,"We allocated memory without remote save!"));
TRC_NRM((TB, "No remote save, force repaint"));
}
}
else {
// We failed to find a match. This is not an error -
// it will happen when saves are not restored in LIFO fashion
// and it will also happen when SSI gets a sync now whilst
// something is saved.
TRC_DBG((TB, "Cannot find save request"));
}
}
else {
TRC_ALT((TB, "saveLevel(%d) exceeds maximum",
ssiLocalSSBState.saveLevel));
}
}
else {
TRC_ALT((TB, "Restore without save"));
}
DC_END_FN();
return rc;
}
/****************************************************************************/
// SSIDiscardSave
//
// Discards the specified screen rectangle bits. Always returns TRUE
// saying that the discard succeeded.
/****************************************************************************/
BOOL SSIDiscardSave(PRECTL pRect, ULONG_PTR ident)
{
BOOL rc;
DC_BEGIN_FN("SSIDiscardSave");
TRC_DBG((TB, "Discard for rect L%u R%u T%u B%u", pRect->left,
pRect->right, pRect->top, pRect->bottom));
// If the save level is negative then either there was a save
// outstanding when we hooked the SSB or we have received out of order
// restores/discards so we discarded stuff from the SSB stack ourselves.
if (ssiLocalSSBState.saveLevel >= 0) {
// If the save level is greater than the number of levels that we
// support we just return TRUE. We will have ignored the SaveBits
// call - so we have effectively discarded the bits already.
// Our maximum save level is such that we should very rarely (if ever)
// go through this path.
if (ssiLocalSSBState.saveLevel < SSB_MAX_SAVE_LEVEL) {
pddCacheStats[SSI].CacheReads++;
// Search for the corresponding save order on our stack.
// Not finding a slot match is not unusual, it can happen
// when saves are not restored in LIFO fashion or when SSI
// gets a sync while something is saved.
if (SSIFindSlotAndDiscardAbove(pRect, ident)) {
// If the bits were saved remotely then update local counter
// for removed bits.
if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely) {
// We don't transmit FREE/DISCARDSAVE orders - there is
// no need because each Save/Restore order contains all
// the necessary information (e.g. position of the bits
// in the Save Bitmap). Just update our counter to take
// account of the remote freed bits.
ssiRemoteSSBState.pelsSaved -=
CURRENT_LOCAL_SSB_STATE.remotePelsRequired;
}
// If we actually copied the bits, then free the memory.
if (CURRENT_LOCAL_SSB_STATE.pSaveData != NULL) {
TRC_DBG((TB, "Free off stored memory at %p",
CURRENT_LOCAL_SSB_STATE.pSaveData));
EngFreeMem(CURRENT_LOCAL_SSB_STATE.pSaveData);
CURRENT_LOCAL_SSB_STATE.pSaveData = NULL;
}
}
}
else {
TRC_ALT((TB, "saveLevel(%d) exceeds maximum",
ssiLocalSSBState.saveLevel));
}
}
else {
TRC_ALT((TB, "Restore without save"));
}
DC_END_FN();
return TRUE;
}
/****************************************************************************/
// SSICopyRect
//
// Copy a screen rectangle.
/****************************************************************************/
void SSICopyRect(SURFOBJ *pso, BOOL save)
{
UINT32 size;
PBYTE pSrc;
PBYTE pDest;
PBYTE pScreenLocation;
unsigned rectWidth;
unsigned rectHeight;
unsigned paddedRectWidth;
unsigned row;
unsigned srcDelta;
unsigned destDelta;
PDD_PDEV pPDev;
#ifdef DC_HICOLOR
#ifdef DC_DEBUG
unsigned bpp;
#endif
#endif
DC_BEGIN_FN("SSICopyRect");
// Set up some key params which are independent of the direction of
// copy.
rectHeight = CURRENT_LOCAL_SSB_STATE.rect.bottom -
CURRENT_LOCAL_SSB_STATE.rect.top;
pPDev = (PDD_PDEV)pso->dhpdev;
#ifdef DC_HICOLOR
if (pso->iBitmapFormat == BMF_24BPP) {
pScreenLocation = pPDev->pFrameBuf +
(CURRENT_LOCAL_SSB_STATE.rect.top * pso->lDelta) +
(CURRENT_LOCAL_SSB_STATE.rect.left * 3);
// rectWidth is in bytes. At 24bpp, this is 3 * number of pels.
rectWidth = (CURRENT_LOCAL_SSB_STATE.rect.right -
CURRENT_LOCAL_SSB_STATE.rect.left) * 3;
#ifdef DC_DEBUG
bpp = 24;
#endif
}
else if (pso->iBitmapFormat == BMF_16BPP) {
pScreenLocation = pPDev->pFrameBuf +
(CURRENT_LOCAL_SSB_STATE.rect.top * pso->lDelta) +
(CURRENT_LOCAL_SSB_STATE.rect.left * 2);
// rectWidth is in bytes. At 16bpp, this is 2 * number of pels.
rectWidth = (CURRENT_LOCAL_SSB_STATE.rect.right -
CURRENT_LOCAL_SSB_STATE.rect.left) * 2;
#ifdef DC_DEBUG
bpp = 16;
#endif
}
else
#endif
if (pso->iBitmapFormat == BMF_8BPP) {
pScreenLocation = pPDev->pFrameBuf +
(CURRENT_LOCAL_SSB_STATE.rect.top * pso->lDelta) +
CURRENT_LOCAL_SSB_STATE.rect.left;
// rectWidth is in bytes. At 8bpp, this is the number of pels.
rectWidth = CURRENT_LOCAL_SSB_STATE.rect.right -
CURRENT_LOCAL_SSB_STATE.rect.left;
#ifdef DC_HICOLOR
#ifdef DC_DEBUG
bpp = 8;
#endif
#endif
}
else {
pScreenLocation = pPDev->pFrameBuf +
(CURRENT_LOCAL_SSB_STATE.rect.top * pso->lDelta) +
(CURRENT_LOCAL_SSB_STATE.rect.left / 2);
// rectWidth is in bytes. At 4bpp, this is (number of pels)/2.
// However, since we copy whole bytes, we need to round 'right' up
// and 'left' down to the nearest multiple of 2.
rectWidth = ((CURRENT_LOCAL_SSB_STATE.rect.right + 1) -
(CURRENT_LOCAL_SSB_STATE.rect.left & ~1)) / 2;
#ifdef DC_HICOLOR
#ifdef DC_DEBUG
bpp = 4;
#endif
#endif
}
paddedRectWidth = (unsigned)DC_ROUND_UP_4(rectWidth);
TRC_DBG((TB, "CopyRect: L%u R%u B%u T%u H%u W%u, PW%u sc%p index %d",
CURRENT_LOCAL_SSB_STATE.rect.left,
CURRENT_LOCAL_SSB_STATE.rect.right,
CURRENT_LOCAL_SSB_STATE.rect.bottom,
CURRENT_LOCAL_SSB_STATE.rect.top,
rectHeight,
rectWidth,
paddedRectWidth,
pScreenLocation,
ssiLocalSSBState.saveLevel));
#ifdef DC_HICOLOR
TRC_ASSERT(((pso->iBitmapFormat == BMF_4BPP) ||
(pso->iBitmapFormat == BMF_8BPP) ||
(pso->iBitmapFormat == BMF_16BPP) ||
(pso->iBitmapFormat == BMF_24BPP)),
(TB, "Bitmap format %d unsupported", pso->iBitmapFormat));
#else
// Only coded for 4bpp and 8bpp thus far.
TRC_ASSERT(((pso->iBitmapFormat == BMF_8BPP) ||
(pso->iBitmapFormat == BMF_4BPP)),
(TB, "Bitmap format %d unsupported", pso->iBitmapFormat));
#endif
// Allocate memory if required. The size can be calculated from the
// rectl field: NB This is in exclusive coords.
if (save) {
size = rectHeight * paddedRectWidth;
CURRENT_LOCAL_SSB_STATE.pSaveData = EngAllocMem(FL_ZERO_MEMORY,
size, DD_ALLOC_TAG);
#ifdef DC_HICOLOR
TRC_DBG((TB, "Save: alloc %u bytes for %dBPP at %p",
size, bpp,
CURRENT_LOCAL_SSB_STATE.pSaveData));
#else
TRC_DBG((TB, "Save: alloc %u bytes for %dBPP at %p",
size,
pso->iBitmapFormat == BMF_8BPP ? 8 : 4,
CURRENT_LOCAL_SSB_STATE.pSaveData));
#endif
if (CURRENT_LOCAL_SSB_STATE.pSaveData != NULL) {
// Now copy the bits. No need to explicitly zero the pad bytes as
// we've nulled the memory on allocation.
pSrc = pScreenLocation;
pDest = CURRENT_LOCAL_SSB_STATE.pSaveData;
srcDelta = pso->lDelta;
destDelta = paddedRectWidth;
TRC_DBG((TB, "Save: Copying from %p to %p", pSrc, pDest));
for (row = 0; row < rectHeight; row++) {
memcpy(pDest, pSrc, rectWidth);
pDest += destDelta;
pSrc += srcDelta;
}
}
else {
TRC_ALT((TB, "Failed alloc %ul bytes, SSI save aborted", size));
}
}
else {
// Copy the bits to the screen bitmap.
pSrc = CURRENT_LOCAL_SSB_STATE.pSaveData;
pDest = pScreenLocation;
srcDelta = paddedRectWidth;
destDelta = pso->lDelta;
TRC_DBG((TB, "Restore: Copying from %p to %p", pSrc, pDest));
TRC_ASSERT((pSrc != NULL), (TB,"Source for SSI restore is NULL!"));
for (row = 0; row < rectHeight; row++) {
memcpy(pDest, pSrc, rectWidth);
pDest += destDelta;
pSrc += srcDelta;
}
TRC_DBG((TB, "Freeing memory at %p"));
EngFreeMem(CURRENT_LOCAL_SSB_STATE.pSaveData);
CURRENT_LOCAL_SSB_STATE.pSaveData = NULL;
}
DC_END_FN();
} /* SSICopyRect */