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.
942 lines
36 KiB
942 lines
36 KiB
/****************************************************************************/
|
|
// 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 */
|
|
|