Source code of Windows XP (NT5)
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.

1868 lines
54 KiB

  1. //
  2. // SBC.C
  3. // Sent Bitmap Cache
  4. //
  5. // Copyright(c) Microsoft 1997-
  6. //
  7. #include <as16.h>
  8. //
  9. // SBC_DDProcessRequest()
  10. // Handle SBC escapes
  11. //
  12. BOOL SBC_DDProcessRequest
  13. (
  14. UINT fnEscape,
  15. LPOSI_ESCAPE_HEADER pResult,
  16. DWORD cbResult
  17. )
  18. {
  19. BOOL rc;
  20. DebugEntry(SBC_DDProcessRequest);
  21. switch (fnEscape)
  22. {
  23. case SBC_ESC_NEW_CAPABILITIES:
  24. {
  25. TRACE_OUT(("SBC_ESC_NEW_CAPABILITIES"));
  26. ASSERT(cbResult == sizeof(SBC_NEW_CAPABILITIES));
  27. #if 0
  28. SBCDDSetNewCapabilities((LPSBC_NEW_CAPABILITIES)pResult);
  29. #endif
  30. rc = TRUE;
  31. }
  32. break;
  33. default:
  34. {
  35. ERROR_OUT(("Unrecognized SBC_ escape"));
  36. rc = FALSE;
  37. }
  38. break;
  39. }
  40. DebugExitBOOL(SBC_DDProcessRequest, rc);
  41. return(rc);
  42. }
  43. #if 0
  44. //
  45. // FUNCTION: SBCDDSetNewCapabilities
  46. //
  47. // DESCRIPTION:
  48. //
  49. // Set the new SBC related capabilities
  50. //
  51. // RETURNS:
  52. //
  53. // NONE
  54. //
  55. // PARAMETERS:
  56. //
  57. // pDataIn - pointer to the input buffer
  58. //
  59. //
  60. void SBCDDSetNewCapabilities(LPSBC_NEW_CAPABILITIES pCapabilities)
  61. {
  62. DebugEntry(SBCSetNewCapabilities);
  63. //
  64. // Copy the data from the Share Core.
  65. //
  66. g_sbcSendingBPP = pCapabilities->sendingBpp;
  67. hmemcpy(&g_sbcCacheInfo, pCapabilities->cacheInfo, sizeof(g_sbcCacheInfo));
  68. DebugExitVOID(SBCSetNewCapabilities);
  69. }
  70. #endif
  71. //
  72. // SBC_DDInit()
  73. //
  74. BOOL SBC_DDInit
  75. (
  76. HDC hdcScreen,
  77. LPDWORD ppShuntBuffers,
  78. LPDWORD pBitmasks
  79. )
  80. {
  81. UINT i;
  82. BOOL rc = FALSE;
  83. DebugEntry(SBC_DDInit);
  84. #if 0
  85. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  86. {
  87. ASSERT(!g_sbcWorkInfo[i].pShuntBuffer);
  88. ASSERT(!g_sbcWorkInfo[i].mruIndex);
  89. ASSERT(!g_sbcWorkInfo[i].workBitmap);
  90. if (i == SBC_SMALL_TILE_INDEX)
  91. {
  92. g_sbcWorkInfo[SBC_SMALL_TILE_INDEX].tileWidth = SBC_SMALL_TILE_WIDTH;
  93. g_sbcWorkInfo[SBC_SMALL_TILE_INDEX].tileHeight = SBC_SMALL_TILE_HEIGHT;
  94. }
  95. else
  96. {
  97. ASSERT(i == SBC_LARGE_TILE_INDEX);
  98. g_sbcWorkInfo[SBC_LARGE_TILE_INDEX].tileWidth = SBC_LARGE_TILE_WIDTH;
  99. g_sbcWorkInfo[SBC_LARGE_TILE_INDEX].tileHeight = SBC_LARGE_TILE_HEIGHT;
  100. }
  101. g_sbcWorkInfo[i].workBitmap = CreateCompatibleBitmap(hdcScreen,
  102. g_sbcWorkInfo[i].tileWidth, g_sbcWorkInfo[i].tileHeight);
  103. if (! g_sbcWorkInfo[i].workBitmap)
  104. {
  105. ERROR_OUT(("Failed to create work bitmap %d", i));
  106. DC_QUIT;
  107. }
  108. SetObjectOwner(g_sbcWorkInfo[i].workBitmap, g_hInstAs16);
  109. MakeObjectPrivate(g_sbcWorkInfo[i].workBitmap, TRUE);
  110. }
  111. //
  112. // Initialize the shunt buffers
  113. //
  114. if (! SBCDDCreateShuntBuffers())
  115. DC_QUIT;
  116. //
  117. // We've created our SBC cache. Fill in the details
  118. //
  119. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  120. {
  121. ppShuntBuffers[i] = (DWORD)MapSL(g_sbcWorkInfo[i].pShuntBuffer);
  122. ASSERT(ppShuntBuffers[i]);
  123. }
  124. pBitmasks[0] = g_osiScreenRedMask;
  125. pBitmasks[1] = g_osiScreenGreenMask;
  126. pBitmasks[2] = g_osiScreenBlueMask;
  127. g_sbcPaletteChanged = TRUE;
  128. rc = TRUE;
  129. DC_EXIT_POINT:
  130. #endif
  131. DebugExitBOOL(SBC_DDInit, rc);
  132. return(rc);
  133. }
  134. //
  135. // SBC_DDTerm()
  136. //
  137. void SBC_DDTerm(void)
  138. {
  139. UINT i;
  140. DebugEntry(SBC_DDTerm);
  141. #if 0
  142. //
  143. // Clear out our array and free the shunt buffer memory.
  144. //
  145. for (i = 0 ; i < SBC_NUM_TILE_SIZES ; i++)
  146. {
  147. // Kill the bitmap if we there
  148. if (g_sbcWorkInfo[i].workBitmap)
  149. {
  150. SysDeleteObject(g_sbcWorkInfo[i].workBitmap);
  151. g_sbcWorkInfo[i].workBitmap = NULL;
  152. }
  153. if (g_sbcWorkInfo[i].pShuntBuffer)
  154. {
  155. GlobalFree((HGLOBAL)SELECTOROF(g_sbcWorkInfo[i].pShuntBuffer));
  156. g_sbcWorkInfo[i].pShuntBuffer = NULL;
  157. }
  158. g_sbcWorkInfo[i].mruIndex = 0;
  159. }
  160. #endif
  161. DebugExitVOID(SBC_DDTerm);
  162. }
  163. #if 0
  164. //
  165. // SBC_DDTossFromCache()
  166. // This throws away a bitmap if we'd cached it, which happens when the
  167. // contents change.
  168. //
  169. void SBC_DDTossFromCache
  170. (
  171. HBITMAP hbmp
  172. )
  173. {
  174. DebugEntry(SBC_DDTossFromCache);
  175. DebugExitVOID(SBC_DDTossFromCache);
  176. }
  177. //
  178. //
  179. // SBC_DDIsMemScreenBltCachable() - see sbc.h
  180. //
  181. //
  182. BOOL SBC_DDIsMemScreenBltCachable
  183. (
  184. UINT type,
  185. HDC hdcSrc,
  186. HBITMAP hbmpSrc,
  187. UINT cxSubWidth,
  188. UINT cySubHeight,
  189. HDC hdcDst,
  190. LPBITMAPINFO lpbmi
  191. )
  192. {
  193. BOOL rc = FALSE;
  194. UINT srcBpp;
  195. UINT tileWidth;
  196. UINT tileHeight;
  197. BITMAP bmpDetails;
  198. int bmpWidth;
  199. int bmpHeight;
  200. DebugEntry(SBC_DDIsMemScreenBltCachable);
  201. ASSERT((type == LOWORD(ORD_MEMBLT)) || (type == LOWORD(ORD_MEM3BLT)));
  202. if (g_sbcSendingBPP > 8)
  203. {
  204. TRACE_OUT(( "Unsupported sending bpp %d", g_sbcSendingBPP));
  205. DC_QUIT;
  206. }
  207. //
  208. // If this is a thrasher then don't cache it
  209. //
  210. if (!SBCBitmapCacheAllowed(hbmp))
  211. {
  212. TRACE_OUT(( "Its a thrasher"));
  213. DC_QUIT;
  214. }
  215. //
  216. // Ensure we're not in full screen mode.
  217. //
  218. if (g_asShared->fullScreen)
  219. {
  220. TRACE_OUT(("Not caching SBC; full screen active"));
  221. DC_QUIT;
  222. }
  223. if (hdcSrc && (GetMapMode(hdcSrc) != MM_TEXT))
  224. {
  225. TRACE_OUT(("Not caching SBC; source map mode not MM_TEXT"));
  226. DC_QUIT;
  227. }
  228. if (!hbmp)
  229. {
  230. //
  231. // We don't cache compressed DIB and DIB section bitmaps
  232. //
  233. if (lpbi->bmiHeader.biCompression != BI_RGB)
  234. DC_QUIT;
  235. bmpWidth = lpbi->bmiHeader.biWidth;
  236. bmpHeight = lpbi->bmiHeader.biHeight;
  237. srcBpp = lpbi->bmiHeader.biPlanes * lpbi->bmiHeader.biBitCount;
  238. }
  239. else
  240. {
  241. if (!GetObject(hbmp, sizeof(bmpDetails), &bmpDetails))
  242. {
  243. ERROR_OUT(("Can't get source info"));
  244. DC_QUIT;
  245. }
  246. srcBpp = bmpDetails.bmBitsPixel * bmpDetails.bmPlanes;
  247. bmpWidth = bmpDetails.bmWidth;
  248. bmpHeight = bmpDetails.bmHeight;
  249. }
  250. //
  251. // Oprah394
  252. //
  253. // This function is much too ready to take on work, even when it would
  254. // mean bogging down the host with unnecessary caching work. We
  255. // have no way to determine when an app is doing animation save to
  256. // reject cache requests when the rate looks to be too high.
  257. //
  258. // This function is called for complete source bitmaps before tiling
  259. // so we do not need to worry about confusing tiling with animation.
  260. // The CacheRequests count is decayed in SBC_Periodic
  261. //
  262. //
  263. // MNM0063 - Oprah 394 revisited
  264. //
  265. // If we decide here that we are doing animation, we set the
  266. // sbcAnimating flag for the benefit of other parts of the code. In
  267. // particular, we use this to suppress the comparison of before and
  268. // after states of the screen during a BitBlt operation
  269. //
  270. //
  271. if ((cxSubBitmapWidth != bmpWidth) ||
  272. (cySubBitmapHeight != bmpHeight))
  273. {
  274. TRACE_OUT(("Partial blit - check for slideshow effects"));
  275. g_sbcBltRate++;
  276. if (g_sbcBltRate > SBC_CACHE_DISABLE_RATE)
  277. {
  278. TRACE_OUT(("Excessive cache rate %d - disabled", g_sbcBltRate));
  279. g_sbcAnimating = TRUE;
  280. DC_QUIT;
  281. }
  282. }
  283. //
  284. // MNM63: if we get here, we will assume we're not animating
  285. //
  286. g_sbcAnimating = FALSE;
  287. //
  288. // If the bitmap is 1bpp and the colors are not default then we don't
  289. // cache it (all bitmaps are cached in glorious technicolor!)
  290. //
  291. if ( (srcBpp == 1) &&
  292. ( (g_oeState.lpdc->DrawMode.bkColorL != DEFAULT_BG_COLOR) ||
  293. (g_oeState.lpdc->DrawMode.txColorL != DEFAULT_FG_COLOR) ||
  294. (type == LOWORD(ORD_MEM3BLT))) )
  295. {
  296. TRACE_OUT(("Didn't cache mono bitmap with non-default colors"));
  297. DC_QUIT;
  298. }
  299. //
  300. // Check that the cache will accept tiles
  301. //
  302. if (!SBC_DDQueryBitmapTileSize(bmpWidth,
  303. bmpHeight,
  304. &tileWidth,
  305. &tileHeight))
  306. {
  307. TRACE()"Cache does not support tiling"));
  308. DC_QUIT;
  309. }
  310. //
  311. // We are ready to go ahead with the caching!
  312. //
  313. rc = TRUE;
  314. DC_EXIT_POINT:
  315. DebugExitBOOL(SBC_DDIsMemScreenBltCachable, rc);
  316. return(rc);
  317. }
  318. //
  319. //
  320. // SBC_DDCacheMemScreenBlt() - see sbc.h
  321. //
  322. //
  323. BOOL SBC_DDCacheMemScreenBlt
  324. (
  325. LPINT_ORDER pOrder,
  326. LPMEMBLT_ORDER_EXTRA_INFO lpMemBltInfo,
  327. HDC hdcDst
  328. )
  329. {
  330. BOOL rc = FALSE;
  331. LPMEMBLT_ORDER pMemBltOrder = (LPMEMBLT_ORDER)&(pOrder->abOrderData);
  332. LPMEM3BLT_ORDER pMem3BltOrder = (LPMEM3BLT_ORDER)pMemBltOrder;
  333. HBITMAP hBitmap;
  334. HDC hdcSrc;
  335. UINT iCache;
  336. UINT iCacheEntry;
  337. UINT iColorTable;
  338. UINT type;
  339. LPINT pXSrc;
  340. LPINT pYSrc;
  341. UINT srcBpp;
  342. BITMAP bmpDetails;
  343. UINT bmpWidth;
  344. UINT bmpHeight;
  345. UINT tileWidth;
  346. UINT tileHeight;
  347. POINT tileOrg;
  348. UINT cxSubBitmapWidth;
  349. UINT cySubBitmapHeight;
  350. LPBYTE pWorkBits;
  351. RECT destRect;
  352. POINT sourcePt;
  353. int tileSize;
  354. LPSBC_TILE_DATA pTileData = NULL;
  355. DebugEntry(SBC_DDCacheMemScreenBlt);
  356. //
  357. // Do a first pass on the cacheability of the Blt
  358. //
  359. if (!SBC_DDIsMemScreenBltCachable(lpMemBltInfo))
  360. {
  361. TRACE_OUT(( "This MemBlt Order is not cachable"));
  362. DC_QUIT;
  363. }
  364. //
  365. // Get the width and height of the source bitmap
  366. //
  367. pSourceSurf = pMemBltInfo->pSource;
  368. bmpWidth = pSourceSurf->sizlBitmap.cx;
  369. bmpHeight = pSourceSurf->sizlBitmap.cy;
  370. //
  371. // Calculate the tile size for this blit
  372. //
  373. if (!SBC_DDQueryBitmapTileSize(bmpWidth,
  374. bmpHeight,
  375. &tileWidth,
  376. &tileHeight))
  377. {
  378. TRACE_OUT(( "Cache does not support tiling"));
  379. DC_QUIT;
  380. }
  381. //
  382. // Set up pointers to the source coordinates in the order.
  383. //
  384. type = pMemBltOrder->type;
  385. if (type == ORD_MEMBLT_TYPE)
  386. {
  387. sourcePt.x = pMemBltOrder->nXSrc;
  388. sourcePt.y = pMemBltOrder->nYSrc;
  389. TRACE_OUT((
  390. "Request to cache MemBlt (%d, %d), %d x %d -> (%d, %d), src %x",
  391. sourcePt.x,
  392. sourcePt.y,
  393. pMemBltOrder->nWidth,
  394. pMemBltOrder->nHeight,
  395. pMemBltOrder->nLeftRect,
  396. pMemBltOrder->nTopRect,
  397. pSourceSurf->hsurf));
  398. }
  399. else
  400. {
  401. sourcePt.x = pMem3BltOrder->nXSrc;
  402. sourcePt.y = pMem3BltOrder->nYSrc;
  403. TRACE_OUT((
  404. "Request to cache Mem3Blt (%d, %d), %d x %d -> (%d, %d), src %x",
  405. sourcePt.x,
  406. sourcePt.y,
  407. pMem3BltOrder->nWidth,
  408. pMem3BltOrder->nHeight,
  409. pMem3BltOrder->nLeftRect,
  410. pMem3BltOrder->nTopRect,
  411. pSourceSurf->hsurf));
  412. }
  413. //
  414. // Calculate the tile origin and size of remaining bitmap. Origin is
  415. // rounded down to the nearest tile. Actual size of bitmap to cache
  416. // may be smaller than tile size if the tile runs off the right/bottom
  417. // of the bitmap
  418. //
  419. tileOrg.x = sourcePt.x - (sourcePt.x % tileWidth);
  420. tileOrg.y = sourcePt.y - (sourcePt.y % tileHeight);
  421. //
  422. // Actual size of bitmap to cache may be smaller than tile size if the
  423. // tile runs off the right/bottom of the bitmap. To see why this
  424. // calculation is correct, realize that (bmpWidth - tileOrg.x) is the
  425. // remaining width of the bitmap after the start of this tile.
  426. //
  427. cxSubBitmapWidth = min(tileWidth, bmpWidth - tileOrg.x);
  428. cySubBitmapHeight = min(tileHeight, bmpHeight - tileOrg.y);
  429. //
  430. // We know how large a tile we have - we now have to Blt it into one of
  431. // our work bitmaps and pass it up to the share core. First, work out
  432. // which of our work bitmaps we should use and set up some variables
  433. // based on this.
  434. //
  435. for (tileSize=0 ; tileSize<SBC_NUM_TILE_SIZES ; tileSize++)
  436. {
  437. if ((cxSubBitmapWidth <= g_sbcWorkInfo[tileSize].tileWidth) &&
  438. (cySubBitmapHeight <= g_sbcWorkInfo[tileSize].tileHeight))
  439. {
  440. break;
  441. }
  442. }
  443. if (tileSize == SBC_NUM_TILE_SIZES)
  444. {
  445. ERROR_OUT(( "%d x %d tile doesn't fit into work bmp",
  446. cxSubBitmapWidth,
  447. cySubBitmapHeight));
  448. DC_QUIT;
  449. }
  450. //
  451. // Before doing any more work, get the next free entry in the shunt
  452. // buffer. Note that this fills in the tileId element of the returned
  453. // structure.
  454. //
  455. // It is perfectly valid for this call to fail. The shunt buffer may
  456. // just be full if we are sending lots of bitmap data up to the share
  457. // core.
  458. //
  459. if (!SBCDDGetNextFreeTile(tileSize, &pTileData))
  460. {
  461. TRACE_OUT(( "Unable to get a free tile in shunt buffer"));
  462. DC_QUIT;
  463. }
  464. //
  465. // Lock the work bitmap to get a surface to pass to EngBitBlt
  466. //
  467. pWorkSurf = EngLockSurface((HSURF)g_sbcWorkInfo[tileSize].workBitmap);
  468. if (pWorkSurf == NULL)
  469. {
  470. ERROR_OUT(( "Failed to lock work surface"));
  471. DC_QUIT;
  472. }
  473. TRACE_OUT(( "Locked surface"));
  474. //
  475. // Do the Blt to our work bitmap to get the bits at native bpp, and
  476. // using the color table which we sent to the share core.
  477. //
  478. destRectl.top = 0;
  479. destRectl.left = 0;
  480. destRectl.right = cxSubBitmapWidth;
  481. destRectl.bottom = cySubBitmapHeight;
  482. sourcePt = tileOrg;
  483. if (!EngBitBlt(pWorkSurf,
  484. pSourceSurf,
  485. NULL, // mask surface
  486. NULL, // clip object
  487. pMemBltInfo->pXlateObj,
  488. &destRectl,
  489. &sourcePt,
  490. NULL, // mask origin
  491. NULL, // brush
  492. NULL, // brush origin
  493. 0xcccc)) // SRCCPY
  494. {
  495. ERROR_OUT(( "Failed to Blt to work bitmap"));
  496. DC_QUIT;
  497. }
  498. TRACE_OUT(( "Completed BitBlt"));
  499. //
  500. // The Blt succeeded, so pass the bits to the share core by copying
  501. // them into the correct shunt buffer.
  502. //
  503. // bytesUsed is set to the number of bytes required for
  504. // cySubBitmapHeight number of full scanlines in the shunt buffer tile
  505. // (NOT the number of bytes available in the tile, or the number of
  506. // bytes of data which was actually Blted)
  507. //
  508. // major/minorCacheInfo are set to details from the source surface.
  509. // hdev does not change on consecutive Blts from the same surface, but
  510. // iUniq may.
  511. //
  512. pDestSurf = pMemBltInfo->pDest;
  513. pDestDev = (LPOSI_PDEV)pDestSurf->dhpdev;
  514. pTileData->bytesUsed = BYTES_IN_BITMAP(g_sbcWorkInfo[tileSize].tileWidth,
  515. cySubBitmapHeight,
  516. pDestDev->cBitsPerPel);
  517. pTileData->srcX = (TSHR_UINT16)sourcePt.x;
  518. pTileData->srcY = (TSHR_UINT16)sourcePt.y;
  519. pTileData->width = cxSubBitmapWidth;
  520. pTileData->height = cySubBitmapHeight;
  521. pTileData->tilingWidth = tileWidth;
  522. pTileData->tilingHeight = tileHeight;
  523. pTileData->majorCacheInfo = (UINT)pSourceSurf->hsurf;
  524. pTileData->minorCacheInfo = (UINT)pSourceSurf->iUniq;
  525. pTileData->majorPalette = (UINT)pMemBltInfo->pXlateObj;
  526. pTileData->minorPalette = (UINT)(pMemBltInfo->pXlateObj != NULL ?
  527. pMemBltInfo->pXlateObj->iUniq : 0);
  528. //
  529. // If the source surface has the BMF_DONTCACHE flag set then it is a
  530. // DIB Section. This means that an app can change the bits in the
  531. // surface without calling GDI, and hence without the iUniq value being
  532. // updated.
  533. //
  534. // We rely on iUniq changing for the fast path to work, so we must
  535. // exclude these bitmaps from the fast path. Do this by resetting the
  536. // majorCacheInfo field (we use this rather than minorCacheInfo because
  537. // we can't tell what an invalid iUniq value is).
  538. //
  539. if ( (pSourceSurf->iType == STYPE_BITMAP) &&
  540. ((pSourceSurf->fjBitmap & BMF_DONTCACHE) != 0) )
  541. {
  542. TRACE_OUT(( "Source hsurf %#.8lx has BMF_DONTCACHE set",
  543. pTileData->majorCacheInfo));
  544. pTileData->majorCacheInfo = SBC_DONT_FASTPATH;
  545. }
  546. //
  547. // Note that this only works correctly because we create our work
  548. // bitmaps to be "top down" rather than the default of "bottom up".
  549. // i.e. the data for the top scanline is first in memory, so we can
  550. // start copying from the start of the bit data. Bottom up would mean
  551. // working out an offset into the work bitmap to start copying from.
  552. //
  553. memcpy(pTileData->bitData, pWorkSurf->pvBits, pTileData->bytesUsed);
  554. //
  555. // We've done the copy. Reset the work bitmap bits for next time we
  556. // use this work bitmap - this helps with compression later on.
  557. //
  558. memset(pWorkSurf->pvBits, 0, pWorkSurf->cjBits);
  559. //
  560. // Fill in the required info in the Mem(3)Blt order.
  561. //
  562. if (type == ORD_MEMBLT_TYPE)
  563. {
  564. pMemBltOrder->cacheId = pTileData->tileId;
  565. }
  566. else
  567. {
  568. pMem3BltOrder->cacheId = pTileData->tileId;
  569. }
  570. //
  571. // We've filled in all the data in the shunt buffer entry, so mark it
  572. // as in use so that the share core can access it.
  573. //
  574. pTileData->inUse = TRUE;
  575. //
  576. // Must have completed successfully to get to here
  577. //
  578. TRACE_OUT(( "Queued tile (%d, %d), %d x %d, tile %d x %d, Id %hx",
  579. sourcePt.x,
  580. sourcePt.y,
  581. cxSubBitmapWidth,
  582. cySubBitmapHeight,
  583. g_sbcWorkInfo[tileSize].tileWidth,
  584. g_sbcWorkInfo[tileSize].tileHeight,
  585. pTileData->tileId));
  586. rc = TRUE;
  587. DC_EXIT_POINT:
  588. //
  589. // Unlock the work surface (if required)
  590. //
  591. if (pWorkSurf != NULL)
  592. {
  593. EngUnlockSurface(pWorkSurf);
  594. TRACE_OUT(( "Unlocked surface"));
  595. }
  596. DebugExitDWORD(SBC_DDCacheMemScreenBlt, rc);
  597. return(rc);
  598. //
  599. // If the data flow rate is high enough then we don't bother with
  600. // any bitmap caching. This allows the host to run at its maximum
  601. // speed at all times, which gives us the maximum amount of spoiling
  602. // and responsiveness.
  603. //
  604. if (!usrCacheBitmaps)
  605. {
  606. DC_QUIT;
  607. }
  608. //
  609. // Bitmap caching is only supported for 4bpp and 8bpp protocols. If we
  610. // switch the sending bpp during a share it does not matter because we
  611. // are controlling the remote bitmap caches.
  612. //
  613. if ((usrSendingbpp != 4) &&
  614. (usrSendingbpp != 8))
  615. {
  616. DC_QUIT;
  617. }
  618. //
  619. // Extract the src DC handle from the Order Header.
  620. //
  621. hdcSrc = pOrder->OrderHeader.memBltInfo.hdcSrc;
  622. //
  623. // If the mapping mode of the src DC is anything other that MM_TEXT
  624. // (the default) then we don't cache the bitmap.
  625. // We are aiming to cache icons and buttons and these will normally
  626. // be drawn using MM_TEXT mapping mode. Therefore if the mode is
  627. // anything other than MM_TEXT we can assume something more complex
  628. // is going on and we probably don't want to cache it anyway.
  629. //
  630. if ((hdcSrc != NULL) && (GetMapMode(hdcSrc) != MM_TEXT))
  631. {
  632. TRACE()"Didn't cache blt using complex mapping mode"));
  633. DC_QUIT;
  634. }
  635. //
  636. // Extract the src bitmap handle from the Order.
  637. //
  638. type = ((LPMEMBLT_ORDER)&pOrder->abOrderData)->type;
  639. if (type == LOWORD(ORD_MEMBLT))
  640. {
  641. hBitmap = (HBITMAP)((LPMEMBLT_ORDER)&pOrder->abOrderData)->hBitmap;
  642. }
  643. else
  644. {
  645. hBitmap = (HBITMAP)((LPMEM3BLT_ORDER)&pOrder->abOrderData)->hBitmap;
  646. }
  647. TRACE_DBG()"hBitmap %x", hBitmap));
  648. //
  649. // If this is a thrasher then don't cache it
  650. //
  651. if (!SBCBitmapCacheAllowed(hBitmap))
  652. {
  653. TRACE()"Its a thrasher!"));
  654. DC_QUIT;
  655. }
  656. //
  657. // Fetch the bitmap details. If the bitmap is 1bpp and the colors are
  658. // not default then we don't cache it (all bitmaps are cached in
  659. // glorious technicolor!)
  660. //
  661. if (hBitmap == NULL)
  662. {
  663. bmpWidth = (TSHR_INT16)pOrder->OrderHeader.memBltInfo.lpbmi->
  664. bmiHeader.biWidth;
  665. bmpHeight = (TSHR_INT)pOrder->OrderHeader.memBltInfo.lpbmi->
  666. bmiHeader.biHeight;
  667. srcBpp = pOrder->OrderHeader.memBltInfo.lpbmi->bmiHeader.biPlanes *
  668. pOrder->OrderHeader.memBltInfo.lpbmi->bmiHeader.biBitCount;
  669. }
  670. else
  671. {
  672. if (GetObject(hBitmap, sizeof(BITMAP), &bmpDetails))
  673. {
  674. srcBpp = bmpDetails.bmBitsPixel * bmpDetails.bmPlanes;
  675. bmpWidth = bmpDetails.bmWidth;
  676. bmpHeight = bmpDetails.bmHeight;
  677. }
  678. else
  679. {
  680. TRACE_ERR()"Failed to get bmp details (%x)", (TSHR_UINT16)hBitmap));
  681. DC_QUIT;
  682. }
  683. }
  684. if ( (srcBpp == 1) &&
  685. ( (GetBkColor(hdcDst) != DEFAULT_BG_COLOR) ||
  686. (GetTextColor(hdcDst) != DEFAULT_FG_COLOR) ||
  687. (type == LOWORD(ORD_MEM3BLT))) )
  688. {
  689. TRACE()"Didn't cache mono bitmap with non-default colors"));
  690. DC_QUIT;
  691. }
  692. //
  693. // Set up pointers to the source coordinates in the order.
  694. //
  695. if ( type == LOWORD(ORD_MEMBLT) )
  696. {
  697. pXSrc = &((LPMEMBLT_ORDER)&(pOrder->abOrderData))->nXSrc;
  698. pYSrc = &((LPMEMBLT_ORDER)&(pOrder->abOrderData))->nYSrc;
  699. }
  700. else
  701. {
  702. pXSrc = &((LPMEM3BLT_ORDER)&(pOrder->abOrderData))->nXSrc;
  703. pYSrc = &((LPMEM3BLT_ORDER)&(pOrder->abOrderData))->nYSrc;
  704. }
  705. //
  706. // Calculate the tile size for this blit
  707. //
  708. if (!SBC_QueryBitmapTileSize(bmpWidth,
  709. bmpHeight,
  710. &tileWidth,
  711. &tileHeight))
  712. {
  713. TRACE()"Cache does not support tiling"));
  714. DC_QUIT;
  715. }
  716. //
  717. // Calculate the tile origin and size of remaining bitmap. Origin is
  718. // rounded down to the nearest tile. Actual size of bitmap to cache
  719. // may be smaller than tile size if the tile runs off the right/bottom
  720. // of the bitmap
  721. //
  722. tileOrg.x = *pXSrc - (*pXSrc % tileWidth);
  723. tileOrg.y = *pYSrc - (*pYSrc % tileHeight);
  724. //
  725. // Actual size of bitmap to cache may be smaller than tile size if the
  726. // tile runs off the right/bottom of the bitmap. To see why this
  727. // calculation is correct, realize that (bmpWidth - tileOrg.x) is the
  728. // remaining width of the bitmap after the start of this tile.
  729. //
  730. cxSubBitmapWidth = MIN((TSHR_INT16)tileWidth, bmpWidth - tileOrg.x);
  731. cySubBitmapHeight = MIN((TSHR_INT16)tileHeight, bmpHeight - tileOrg.y);
  732. //
  733. // Add the bitmap to the cache.
  734. //
  735. // If the sub-bitmap is already in the cache then this function will
  736. // locate it and return the cache index.
  737. //
  738. // If the sub-bitmap is not in the cache, this function will cache
  739. // it, adding the sub-bitmap data to the order queue.
  740. //
  741. if (!SBCCacheSubBitmap(&iCache,
  742. hBitmap,
  743. hdcSrc,
  744. hdcDst,
  745. tileOrg.x,
  746. tileOrg.y,
  747. bmpWidth,
  748. bmpHeight,
  749. cxSubBitmapWidth,
  750. cySubBitmapHeight,
  751. srcBpp,
  752. &iCacheEntry,
  753. &iColorTable,
  754. pOrder->OrderHeader.memBltInfo.pBits,
  755. pOrder->OrderHeader.memBltInfo.lpbmi,
  756. pOrder->OrderHeader.memBltInfo.fuColorUse,
  757. pOrder->OrderHeader.memBltInfo.hPalDest))
  758. {
  759. //
  760. // The sub-bitmap could not be cached - return FALSE.
  761. // The caller will add the destination of the blt into the SDA and
  762. // discard the order.
  763. //
  764. TRACE()"Failed to cache bitmap %04x", hBitmap));
  765. DC_QUIT;
  766. }
  767. //
  768. // Set up the source co-ordinates. For R1 protocols, the x-coordinate
  769. // includes the offset which is required to get the right cell within
  770. // the receive bitmap cache. For R2, we set up the cache entry in a
  771. // separate field.
  772. //
  773. if (!sbcMultiPoint)
  774. {
  775. *pXSrc = (iCacheEntry * sbcBmpCaches[iCache].cCellSize) +
  776. *pXSrc % tileWidth;
  777. }
  778. else
  779. {
  780. *pXSrc = *pXSrc % tileWidth;
  781. }
  782. *pYSrc = *pYSrc % tileHeight;
  783. //
  784. // The sub-bitmap and color table are in the cache. Store a cache
  785. // handle and color handle (which the receiver will turn back into an
  786. // HBITMAP). Also store the cache index for R2 protocols (see above).
  787. //
  788. if (type == LOWORD(ORD_MEMBLT))
  789. {
  790. ((LPMEMBLT_ORDER)&pOrder->abOrderData)->hBitmap =
  791. MEMBLT_COMBINEHANDLES(iColorTable,iCache);
  792. if (sbcMultiPoint)
  793. {
  794. ((LPMEMBLT_R2_ORDER)&pOrder->abOrderData)->type =
  795. LOWORD(ORD_MEMBLT_R2);
  796. ((LPMEMBLT_R2_ORDER)&pOrder->abOrderData)->cacheIndex =
  797. iCacheEntry;
  798. }
  799. TRACE()"MEMBLT color %d bitmap %d:%d",iColorTable,iCache,iCacheEntry));
  800. }
  801. else
  802. {
  803. ((LPMEM3BLT_ORDER)&pOrder->abOrderData)->hBitmap =
  804. MEMBLT_COMBINEHANDLES(iColorTable,iCache);
  805. if (sbcMultiPoint)
  806. {
  807. ((LPMEM3BLT_R2_ORDER)&pOrder->abOrderData)->type =
  808. LOWORD(ORD_MEM3BLT_R2);
  809. ((LPMEM3BLT_R2_ORDER)&pOrder->abOrderData)->cacheIndex =
  810. iCacheEntry;
  811. }
  812. TRACE()"MEM3BLT color %d bitmap %d:%d",iColorTable,iCache,iCacheEntry));
  813. }
  814. TRACE_DBG()"iCacheEntry=%u, tileWidth=%hu, xSrc=%hd, ySrc=%hd",
  815. iCacheEntry, tileWidth, *pXSrc, *pYSrc));
  816. rc = TRUE;
  817. DC_EXIT(rc);
  818. }
  819. //
  820. //
  821. // SBC_DDQueryBitmapTileSize - see sbc.h
  822. //
  823. //
  824. BOOL SBC_DDQueryBitmapTileSize
  825. (
  826. UINT bmpWidth,
  827. UINT bmpHeight,
  828. LPUINT pTileWidth,
  829. LPUINT pTileHeight
  830. )
  831. {
  832. BOOL rc = FALSE;
  833. UINT i;
  834. UINT maxSide;
  835. DebugEntry(SBC_DDQueryBitmapTileSize);
  836. //
  837. // The tile cell sizes are a local only decision, with the proviso that
  838. // the largest uncompressed tile must fit into the largest cache slot.
  839. // What this means is that for R1.1 we must define cell dimensions that
  840. // have a good fit in the square cache cells. For R2.0 we can just
  841. // select tile sizes that seem appropriate. Taking widths that are not
  842. // a multiple of 16 is wasteful. The height should generally be less
  843. // than the width, simply on the grounds that bitmaps tend to be wider
  844. // than they are high.
  845. //
  846. if (g_sbcCacheInfo[ID_LARGE_BMP_CACHE].cCellSize <
  847. (g_sbcWorkInfo[SBC_SMALL_TILE_INDEX].tileWidth *
  848. g_sbcWorkInfo[SBC_SMALL_TILE_INDEX].tileHeight))
  849. {
  850. ERROR_OUT(( "No space for any cells"));
  851. DC_QUIT;
  852. }
  853. rc = TRUE;
  854. //
  855. // If large cell size is adequate then allow 64*63 cells for
  856. // wide bitmaps
  857. //
  858. if (g_sbcCacheInfo[ID_LARGE_BMP_CACHE].cCellSize >=
  859. (MP_LARGE_TILE_WIDTH * MP_LARGE_TILE_HEIGHT))
  860. {
  861. if ((bmpWidth > MP_SMALL_TILE_WIDTH) ||
  862. (bmpHeight > MP_SMALL_TILE_HEIGHT))
  863. {
  864. *pTileWidth = MP_LARGE_TILE_WIDTH;
  865. *pTileHeight = MP_LARGE_TILE_HEIGHT;
  866. DC_QUIT;
  867. }
  868. }
  869. //
  870. // Otherwise we just use 32*31 cells
  871. //
  872. *pTileWidth = MP_SMALL_TILE_WIDTH;
  873. *pTileHeight = MP_SMALL_TILE_HEIGHT;
  874. DC_EXIT_POINT:
  875. DebugExitBOOL(SBC_DDQueryBitmapTileSize, rc);
  876. return(rc);
  877. }
  878. //
  879. //
  880. // SBC_DDSyncUpdatesNow() - see sbc.h
  881. //
  882. //
  883. void SBC_DDSyncUpdatesNow(void)
  884. {
  885. LPSBC_TILE_DATA pTileData;
  886. UINT i;
  887. UINT j;
  888. DebugEntry(SBC_DDSyncUpdatesNow);
  889. TRACE_OUT(( "Marking all shunt buffer entries as not in use"));
  890. //
  891. // We have to mark all entries in the shunt buffers as being free.
  892. //
  893. for (i = 0 ; i < SBC_NUM_TILE_SIZES; i++)
  894. {
  895. for (j = 0 ; j < g_sbcWorkInfo[i].pShuntBuffer->numEntries; j++)
  896. {
  897. pTileData = SBCTilePtrFromIndex(g_sbcWorkInfo[i].pShuntBuffer, j);
  898. pTileData->inUse = FALSE;
  899. }
  900. //
  901. // Reset the MRU counter for this shunt buffer
  902. //
  903. g_sbcWorkInfo[i].mruIndex = 0;
  904. }
  905. //
  906. // If we are a palette device (i.e. we are running at 8 bpp or less),
  907. // set the paletteChanged flag so we will send up a color table before
  908. // our next Mem(3)Blt. We do this because the color table order for
  909. // the current device palette may have been discarded during the OA
  910. // sync.
  911. //
  912. g_sbcPaletteChanged = (g_osiScreenBPP <= 8);
  913. DebugExitVOID(SBC_DDSyncUpdatesNow);
  914. }
  915. //
  916. //
  917. // SBC_DDOrderSpoiltNotification() - see sbc.h
  918. //
  919. //
  920. void SBC_DDOrderSpoiltNotification(LPINT_ORDER pOrder)
  921. {
  922. LPMEMBLT_ORDER pMemBltOrder = (LPMEMBLT_ORDER)&(pOrder->abOrderData);
  923. LPMEM3BLT_ORDER pMem3BltOrder = (LPMEM3BLT_ORDER)pMemBltOrder;
  924. UINT tileId;
  925. LPSBC_TILE_DATA pTileData;
  926. UINT tileType;
  927. UINT i;
  928. DebugEntry(SBC_DDOrderSpoiltNotification);
  929. //
  930. // pOrder has been removed from the order heap before being processed.
  931. // We have to free up the entry which it references in one of the shunt
  932. // buffers. First get the tile Id.
  933. //
  934. if (pMemBltOrder->type = ORD_MEMBLT_TYPE)
  935. {
  936. tileId = pMemBltOrder->cacheId;
  937. }
  938. else
  939. {
  940. tileId = pMem3BltOrder->cacheId;
  941. }
  942. TRACE_OUT(( "Order referencing tile %hx has been spoiled", tileId));
  943. //
  944. // Find out which of the shunt buffers the entry should be in based on
  945. // the tileId
  946. //
  947. tileType = SBC_TILE_TYPE(tileId);
  948. //
  949. // We implement the shunt buffers as circular FIFO queues, so we will
  950. // start looking from the last order which we marked as being in use,
  951. // and work BACKWARDS. This is because, in general, the entries after
  952. // the last one we accessed will not be in use (unless the whole shunt
  953. // buffer is in use).
  954. //
  955. // So, get the index of the last tile we accessed.
  956. //
  957. i = g_sbcWorkInfo[tileType].mruIndex;
  958. //
  959. // Loop through the circular buffer until we get a match, or have
  960. // circled back to the beginning.
  961. //
  962. // Note that this has been coded as a "do while" loop, rather than just
  963. // a "while" loop so that we don't miss mruIndex. mruIndex is set up
  964. // to point to the NEXT entry to be used, rather than the last entry to
  965. // be used, so decrementing i before doing any work first time round
  966. // the loop is actually what we want to do.
  967. //
  968. do
  969. {
  970. //
  971. // On to the next tile
  972. //
  973. i = (i == 0)
  974. ? g_sbcWorkInfo[tileType].pShuntBuffer->numEntries - 1
  975. : i - 1;
  976. pTileData = SBCTilePtrFromIndex(g_sbcWorkInfo[tileType].pShuntBuffer, i);
  977. if (pTileData->inUse && (pTileData->tileId == tileId))
  978. {
  979. //
  980. // We've got a match, so mark the tile as being free.
  981. //
  982. // We don't want to update the shunt buffer mruIndex - this
  983. // should remain indicating the next tile to be used when
  984. // adding an entry to the shunt buffer.
  985. //
  986. TRACE_OUT(( "Marked tile Id %hx at index %d as free",
  987. tileId,
  988. i));
  989. pTileData->inUse = FALSE;
  990. break;
  991. }
  992. }
  993. while (i != g_sbcWorkInfo[tileType].mruIndex);
  994. DebugExitVOID(SBC_DDOrderSpoiltNotification);
  995. }
  996. //
  997. //
  998. // SBC_DDMaybeQueueColorTable() - see sbc.h
  999. //
  1000. //
  1001. BOOL SBC_DDMaybeQueueColorTable(void)
  1002. {
  1003. BOOL queuedOK = FALSE;
  1004. int orderSize;
  1005. LPINT_ORDER pOrder;
  1006. LPINT_COLORTABLE_ORDER_1BPP pColorTableOrder;
  1007. UINT numColors;
  1008. UINT i;
  1009. DebugEntry(SBC_DDMaybeQueueColorTable);
  1010. //
  1011. // If we're running at > 8 bpp, then we don't have a palette, so just
  1012. // quit out.
  1013. //
  1014. if (g_osiScreenBPP > 8)
  1015. {
  1016. queuedOK = TRUE;
  1017. DC_QUIT;
  1018. }
  1019. //
  1020. // Check the boolean in our PDEV to see if the palette has changed
  1021. // since the last time we sent a color table order. Note that if we
  1022. // have a non palette device, the boolean will never be set.
  1023. //
  1024. if (!g_sbcPaletteChanged)
  1025. {
  1026. queuedOK = TRUE;
  1027. DC_QUIT;
  1028. }
  1029. //
  1030. // The palette has changed, so allocate order memory to queue a color
  1031. // table order. The order size depends on the bpp of our device. Note
  1032. // that the allocation can fail if the order buffer is full.
  1033. //
  1034. switch (g_osiScreenBPP)
  1035. {
  1036. case 1:
  1037. {
  1038. orderSize = sizeof(INT_COLORTABLE_ORDER_1BPP);
  1039. }
  1040. break;
  1041. case 4:
  1042. {
  1043. orderSize = sizeof(INT_COLORTABLE_ORDER_4BPP);
  1044. }
  1045. break;
  1046. case 8:
  1047. {
  1048. orderSize = sizeof(INT_COLORTABLE_ORDER_8BPP);
  1049. }
  1050. break;
  1051. default:
  1052. {
  1053. ERROR_OUT(("Invalid bpp (%d) for palette device", g_osiScreenBPP));
  1054. DC_QUIT;
  1055. }
  1056. break;
  1057. }
  1058. pOrder = OA_DDAllocOrderMem(orderSize, 0);
  1059. if (pOrder == NULL)
  1060. {
  1061. TRACE_OUT(( "Failed to allocate %d bytes for order", orderSize));
  1062. DC_QUIT;
  1063. }
  1064. TRACE_OUT(( "Allocate %d bytes for color table order", orderSize));
  1065. //
  1066. // We've successfully allocated the order, so fill in the details. We
  1067. // mark the order as internal so that the Update Packager will spot it
  1068. // up in the share core and prevent it being sent over the wire.
  1069. //
  1070. pOrder->OrderHeader.Common.fOrderFlags = OF_INTERNAL;
  1071. pColorTableOrder = (LPINT_COLORTABLE_ORDER_1BPP)&(pOrder->abOrderData);
  1072. pColorTableOrder->header.type = INTORD_COLORTABLE_TYPE;
  1073. pColorTableOrder->header.bpp = g_osiScreenBPP;
  1074. //
  1075. // Get the current system palette and save it.
  1076. //
  1077. numColors = COLORS_FOR_BPP(g_osiScreenBPP);
  1078. for (i = 0 ; i < numColors; i++)
  1079. {
  1080. pColorTableOrder->colorData[i].rgbRed = ppDev->pPal[i].peRed;
  1081. pColorTableOrder->colorData[i].rgbGreen = ppDev->pPal[i].peGreen;
  1082. pColorTableOrder->colorData[i].rgbBlue = ppDev->pPal[i].peBlue;
  1083. }
  1084. //
  1085. // Add the order
  1086. //
  1087. OA_DDAddOrder(pOrder, NULL);
  1088. TRACE_OUT(( "Added internal color table order, size %d", orderSize));
  1089. //
  1090. // Reset the flag which indicates that the palette needs to be sent
  1091. //
  1092. g_sbcPaletteChanged = FALSE;
  1093. //
  1094. // Must be OK to get to here
  1095. //
  1096. queuedOK = TRUE;
  1097. DC_EXIT_POINT:
  1098. DebugExitBOOL(SBC_DDMaybeQueueColorTable, queuedOK);
  1099. return(queuedOK);
  1100. }
  1101. //
  1102. // Name: SBCDDCreateShuntBuffers
  1103. //
  1104. // Purpose: Allocate memory for, and initialize the two shunt buffers
  1105. // used to pass data from the driver to the share core.
  1106. //
  1107. // Returns: TRUE if the buffers were allocated OK, FALSE otherwise.
  1108. //
  1109. // Operation: If this function succeeds, the following global variables
  1110. // are initialized.
  1111. //
  1112. // g_sbcWorkInfo[x].pShuntBuffer
  1113. // g_sbcWorkInfo[x].mruIndex
  1114. // g_sbcNextTileId
  1115. //
  1116. // If the function fails, some of these variables may be
  1117. // initialized.
  1118. //
  1119. BOOL SBCDDCreateShuntBuffers(void)
  1120. {
  1121. int i;
  1122. UINT memPerTile[SBC_NUM_TILE_SIZES];
  1123. UINT numEntries[SBC_NUM_TILE_SIZES];
  1124. DWORD memRequired;
  1125. DWORD minRequired;
  1126. HGLOBAL hBuffer;
  1127. LPBYTE pBuffer;
  1128. BOOL rc;
  1129. DebugEntry(SBCDDCreateShuntBuffers);
  1130. rc = FALSE;
  1131. //
  1132. // We should already have a pointer to the shared memory we can use for
  1133. // our shunt buffers, and the number of bytes available. What we have
  1134. // to do is to partition this shared memory into SBC_NUM_TILE_SIZE
  1135. // shunt buffers. i.e. one shunt buffer per tile size.
  1136. //
  1137. //
  1138. // <--- buffer 0 ---><------------------ buffer 1 -------------------->
  1139. //
  1140. //��������������������������������������������������������������������Ŀ
  1141. //� � : : : : � � : : : : �
  1142. //� � : : : : � � tile : tile : tile : tile : tile �
  1143. //� � : : : : � � : : : : �
  1144. //����������������������������������������������������������������������
  1145. //^ ^ ^
  1146. //� � �
  1147. //� ���� header[0] ���� header[1]
  1148. //�
  1149. //��� psbcSharedMemory
  1150. //
  1151. //
  1152. // We try to use the number of entries given in the pEntries array, but
  1153. // if we do not have enough shared memory for this, we reduce the
  1154. // number of entries in each shunt buffer, preserving the ratio between
  1155. // the number of entries in each of the shunt buffers.
  1156. //
  1157. for (i = 0; i < SBC_NUM_TILE_SIZES ; i++)
  1158. {
  1159. numEntries[i] = SBC_TILE_ENTRIES;
  1160. //
  1161. // Calculate how much memory we need per tile, and for the whole
  1162. // shunt buffer.
  1163. //
  1164. memPerTile[i] = SBC_BYTES_PER_TILE(g_sbcWorkInfo[i].tileWidth,
  1165. g_sbcWorkInfo[i].tileHeight,
  1166. g_osiScreenBPP);
  1167. memRequired = SBCShuntBufferSize(memPerTile[i], numEntries[i]);
  1168. if (i == SBC_SMALL_TILE_INDEX)
  1169. minRequired = SBCShuntBufferSize(memPerTile[i], SBC_SMALL_TILE_MIN_ENTRIES);
  1170. else
  1171. minRequired = SBCShuntBufferSize(memPerTile[i], SBC_LARGE_TILE_MIN_ENTRIES);
  1172. TRACE_OUT(( "[%d]: Requested %d entries, %ld bytes, %ld bytes min",
  1173. i, numEntries[i], memRequired, minRequired));
  1174. //
  1175. // If memRequired or minRequired are greater than 64K, bail out.
  1176. //
  1177. if (memRequired > 0x10000)
  1178. {
  1179. if (minRequired > 0x10000)
  1180. {
  1181. WARNING_OUT(("Not enough memory for SBC"));
  1182. DC_QUIT;
  1183. }
  1184. //
  1185. // We have enough shared memory for the minimum # of entries,
  1186. // but not enough for the default. Figure out how many will fit.
  1187. // in 64K. We do this in a tricky way to avoid DWORD divides
  1188. //
  1189. // Basically, the result is
  1190. // (64K - fixed shunt buffer goop) / memPerTile
  1191. //
  1192. numEntries[i] = (0xFFFF -
  1193. (sizeof(SBC_SHUNT_BUFFER) - sizeof(SBC_TILE_DATA)) + 1) /
  1194. memPerTile[i];
  1195. }
  1196. //
  1197. // Try to allocate memory block.
  1198. //
  1199. hBuffer = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT | GMEM_SHARE,
  1200. SBCShuntBufferSize(memPerTile[i], numEntries[i]));
  1201. if (!hBuffer)
  1202. {
  1203. WARNING_OUT(("Not enough memory for SBC"));
  1204. DC_QUIT;
  1205. }
  1206. g_sbcWorkInfo[i].pShuntBuffer = (LPSBC_SHUNT_BUFFER)MAKELP(hBuffer, 0);
  1207. }
  1208. //
  1209. // There are currently only two tile sizes and therefore two shunt
  1210. // buffers. If we run out of memory on the second one, yeah, we'll
  1211. // exit this function with one 64K block still allocated for the small
  1212. // tile size cache. It will get freed when SBC_DDTerm() is called.
  1213. //
  1214. // If this happens, freeing the block isn't going to make much of a
  1215. // difference, Windows is almost on its knees anyway. So no point in
  1216. // getting fancy and freeing it now.
  1217. //
  1218. //
  1219. // OK, we're home free.
  1220. //
  1221. for (i = 0; i < SBC_NUM_TILE_SIZES ; i++)
  1222. {
  1223. ASSERT(g_sbcWorkInfo[i].pShuntBuffer);
  1224. g_sbcWorkInfo[i].pShuntBuffer->numEntries = numEntries[i];
  1225. g_sbcWorkInfo[i].pShuntBuffer->numBytes = memPerTile[i]
  1226. - sizeof(SBC_TILE_DATA);
  1227. g_sbcWorkInfo[i].pShuntBuffer->structureSize = memPerTile[i];
  1228. //
  1229. // Fill in the mruIndex for this shunt buffer
  1230. //
  1231. g_sbcWorkInfo[i].mruIndex = 0;
  1232. }
  1233. //
  1234. // Initialize the global variables associated with the shunt buffers
  1235. //
  1236. g_sbcNextTileId = 0;
  1237. rc = TRUE;
  1238. DC_EXIT_POINT:
  1239. DebugExitBOOL(SBCDDCreateShuntBuffers, rc);
  1240. return(rc);
  1241. }
  1242. //
  1243. // Name: SBCDDGetNextFreeTile
  1244. //
  1245. // Purpose: Return the next free tile of the correct size from one of the
  1246. // shunt buffers.
  1247. //
  1248. // Returns: TRUE if a tile is returned, FALSE otherwise
  1249. //
  1250. // Params: IN workTileSize - The tile size. One of
  1251. // SBC_SMALL_TILE
  1252. // SBC_LARGE_TILE
  1253. // OUT ppTileData - A pointer to the tile.
  1254. //
  1255. // Operation: The tileId field of the tile is filled in on return from
  1256. // this function.
  1257. //
  1258. //*PROC-********************************************************************
  1259. BOOL SBCDDGetNextFreeTile(int tileSize, LPSBC_TILE_DATA FAR * ppTileData)
  1260. {
  1261. BOOL foundFreeTile = FALSE;
  1262. LPSBC_TILE_DATA pTileData;
  1263. DebugEntry(SBCDDGetNextFreeTile);
  1264. ASSERT(tileSize < SBC_NUM_TILE_SIZES);
  1265. //
  1266. // Get a pointer to the next entry to be used in the shunt buffer
  1267. // containing tiles of the given size.
  1268. //
  1269. pTileData = SBCTilePtrFromIndex(g_sbcWorkInfo[tileSize].pShuntBuffer,
  1270. g_sbcWorkInfo[tileSize].mruIndex);
  1271. //
  1272. // If the entry is still in use (the share core has not yet processed
  1273. // the order which references this tile) we have to quit - the shunt
  1274. // buffer is full.
  1275. //
  1276. if (pTileData->inUse)
  1277. {
  1278. TRACE_OUT(( "Target entry (%d, %d) is still in use",
  1279. tileSize,
  1280. g_sbcWorkInfo[tileSize].mruIndex));
  1281. DC_QUIT;
  1282. }
  1283. //
  1284. // The entry is not in use - we can re-use it. Fill in the Id field,
  1285. // and the pointer to the entry which we return to the caller.
  1286. //
  1287. // We always set the top bit of the tile Id for large tiles, and clear
  1288. // it for small tiles.
  1289. //
  1290. *ppTileData = pTileData;
  1291. pTileData->tileId = g_sbcNextTileId;
  1292. if (tileSize == SBC_SMALL_TILE_INDEX)
  1293. {
  1294. pTileData->tileId &= ~0x8000;
  1295. }
  1296. else
  1297. {
  1298. pTileData->tileId |= 0x8000;
  1299. }
  1300. TRACE_OUT(( "Returning entry (%d, %d), Id %hx",
  1301. tileSize,
  1302. g_sbcWorkInfo[tileSize].mruIndex,
  1303. pTileData->tileId));
  1304. //
  1305. // Update the index of the next free entry in this shunt buffer, and
  1306. // also the Id which we should assign next time. Remember to wrap the
  1307. // shunt buffer index to the number of entries in the shunt buffer.
  1308. //
  1309. g_sbcWorkInfo[tileSize].mruIndex = (g_sbcWorkInfo[tileSize].mruIndex + 1) %
  1310. g_sbcWorkInfo[tileSize].pShuntBuffer->numEntries;
  1311. g_sbcNextTileId++;
  1312. g_sbcNextTileId &= ~0x8000;
  1313. //
  1314. // Completed successfully !
  1315. //
  1316. foundFreeTile = TRUE;
  1317. DC_EXIT_POINT:
  1318. DebugExitBOOL(SBCDDGetNextFreeTile, foundFreeTile);
  1319. return(foundFreeTile);
  1320. }
  1321. //
  1322. // Name: SBCDDIsBitmapThrasher
  1323. //
  1324. // Purpose: Check to see if the given bitmap (surface object) is one
  1325. // which would cause cache thrashing.
  1326. //
  1327. // Returns: TRUE if the bitmap is a thrasher, FALSE otherwise.
  1328. //
  1329. // Params: IN pSurfObj - Pointer to the bitmap
  1330. //
  1331. BOOL SBCDDIsBitmapThrasher(HDC hdc)
  1332. {
  1333. UINT i;
  1334. BOOL rc = FALSE;
  1335. BOOL bitmapInList = FALSE;
  1336. BOOL updateEntry = FALSE;
  1337. UINT updateIndex;
  1338. UINT nextTickCount;
  1339. UINT evictIndex;
  1340. UINT evictTickCount;
  1341. DebugEntry(SBCDDIsBitmapThrasher);
  1342. //
  1343. // Here's an overview of how our bitmap cache thrash detection works...
  1344. //
  1345. // We hold an array of information about the last SBC_NUM_THRASHERS
  1346. // bitmaps which we have tried to cache. This information is
  1347. // - A value to identify the bitmap. This is the hsurf field from the
  1348. // bitmap surface object, and is different for every bitmap.
  1349. // - A value to identify the "version" of the bitmap. This is the
  1350. // iUniq field from the bitmap surface object, and is updated by GDI
  1351. // each time the bitmap is drawn to.
  1352. // - A timestamp for the last time which we saw iUniq change for this
  1353. // bitmap (or when we added the bitmap to the array).
  1354. //
  1355. // Each time this function is called, we scan this array looking for an
  1356. // entry for the bitmap.
  1357. //
  1358. // If we find an entry, we check whether the bitmap has changed (has
  1359. // the iUniq field changed). If it has not changed, the bitmap is not
  1360. // a thrasher. If the bitmap has changed, we check the interval from
  1361. // the timestamp value to the current time. If the interval is less
  1362. // than the SBC_THRASH_INTERVAL, the bitmap has changed too quickly, so
  1363. // it is a thrasher. If the interval is OK, the bitmap is not a
  1364. // thrasher. In either case, we update the stored iUniq field and the
  1365. // timestamp to record the time / version at which we spotted that the
  1366. // bitmap changed.
  1367. //
  1368. // If we do not find an entry for the bitmap, we add an entry for it.
  1369. // If the array is fully populated, we evict the entry with the oldest
  1370. // timestamp, and replace it with the new entry.
  1371. //
  1372. //
  1373. // Scan the thrasher list looking for a match
  1374. //
  1375. for (i=0 ; i < SBC_NUM_THRASHERS ; i++)
  1376. {
  1377. //
  1378. // If we find a match then we are only worried if it has been
  1379. // modified since the last time we read it.
  1380. //
  1381. if (sbcThrashers[i].hsurf == lpdce->hbmp)
  1382. {
  1383. bitmapInList = TRUE;
  1384. if (sbcThrashers[i].iUniq != pSurfObj->iUniq)
  1385. {
  1386. TRACE_OUT(( "Matching surface %x, index %u,"
  1387. "tick count %u has been modified",
  1388. pSurfObj->hsurf,
  1389. i,
  1390. sbcThrashers[i].tickCount));
  1391. updateEntry = TRUE;
  1392. updateIndex = i;
  1393. //
  1394. // Now we need to determine if this is a thrasher. It is a
  1395. // thrasher if the time we last read it is less than our
  1396. // thrash interval. (We only update the time when we read
  1397. // a modified bitmap)
  1398. //
  1399. nextTickCount = SBCDDGetTickCount();
  1400. if ((nextTickCount - sbcThrashers[i].tickCount) <
  1401. SBC_THRASH_INTERVAL)
  1402. {
  1403. TRACE_OUT((
  1404. "Rejected cache attempt of thrashy bitmap %x",
  1405. pSurfObj->hsurf));
  1406. rc = TRUE;
  1407. }
  1408. sbcThrashers[i].tickCount = nextTickCount;
  1409. sbcThrashers[i].iUniq = pSurfObj->iUniq;
  1410. }
  1411. //
  1412. // We've found a match - we can break out of the loop
  1413. //
  1414. break;
  1415. }
  1416. }
  1417. if (!bitmapInList)
  1418. {
  1419. //
  1420. // The bitmap isn't already in the thrasher list, so add it now.
  1421. // Find the entry with the smallest (earliest) tick count - we will
  1422. // evict this entry from the array to make room for the new entry.
  1423. //
  1424. evictIndex = 0;
  1425. evictTickCount = 0xffffffff;
  1426. for (i = 0; i < SBC_NUM_THRASHERS; i++)
  1427. {
  1428. if (evictTickCount > sbcThrashers[i].tickCount)
  1429. {
  1430. evictTickCount = sbcThrashers[i].tickCount;
  1431. evictIndex = i;
  1432. }
  1433. }
  1434. TRACE_OUT(( "Evicting entry %d, surface %x",
  1435. evictIndex,
  1436. sbcThrashers[i].hsurf));
  1437. nextTickCount = SBCDDGetTickCount();
  1438. TRACE_OUT(( "Adding surface %x to thrash list, tick %d",
  1439. pSurfObj->hsurf,
  1440. nextTickCount));
  1441. updateEntry = TRUE;
  1442. updateIndex = evictIndex;
  1443. }
  1444. if (updateEntry)
  1445. {
  1446. //
  1447. // We have to update the entry at index updateIndex. We optimise
  1448. // things slightly by always putting the most recent bitmap in
  1449. // position 0 of the array, so copy entry 0 to the eviction index,
  1450. // and put the new entry in position 0.
  1451. //
  1452. sbcThrashers[updateIndex] = sbcThrashers[0];
  1453. sbcThrashers[0].hsurf = lpdce->hbmp;
  1454. sbcThrashers[0].iUniq = pSurfObj->iUniq;
  1455. sbcThrashers[0].tickCount = nextTickCount;
  1456. }
  1457. DebugExitBOOL(SBCDDIsBitmapThrasher, rc);
  1458. return(rc);
  1459. }
  1460. //
  1461. // Name: SBCDDGetTickCount
  1462. //
  1463. // Purpose: Get a system tick count
  1464. //
  1465. // Returns: The number of centi-seconds since the system was started.
  1466. // This number will wrap after approximately 497 days!
  1467. //
  1468. // Params: None
  1469. //
  1470. DWORD SBCDDGetTickCount(void)
  1471. {
  1472. DWORD tickCount;
  1473. DebugEntry(SBCDDGetTickCount);
  1474. tickCount = GetTickCount() / 10;
  1475. DebugExitDWORD(SBCDDGetTickCount, tickCount);
  1476. return(tickCount);
  1477. }
  1478. #endif // #if 0
  1479. #if 0
  1480. //
  1481. // SBC_BitmapHasChanged(..)
  1482. //
  1483. // See asbcapi.h for description.
  1484. //
  1485. DCVOID DCAPI SBC_BitmapHasChanged(HBITMAP hChangedBitmap)
  1486. {
  1487. TSHR_UINT nextIndex;
  1488. TSHR_INT nextTickCount;
  1489. TSHR_INT tickDelta;
  1490. TSHR_INT tickWork;
  1491. UINT i;
  1492. TRACE_FN("SBC_BitmapHasChanged");
  1493. //
  1494. // We maintain a list of bitmaps that are the target for a drawing
  1495. // operation and we prevent these bitmaps from being cached unless
  1496. // the update frequency is below a target value.
  1497. //
  1498. // All we need to do at this stage is to make sure that the bitmap
  1499. // handle is in the thrash list and is marked as modified since the
  1500. // last read. That means that the next read will be "productive"
  1501. // and so we will check/update the timer at that stage. If the
  1502. // "productive" read occurs within a certain interval from the last
  1503. // read then this bitmap has become a thrasher.
  1504. //
  1505. if (sbcThrashers[0].hBitmap == hChangedBitmap)
  1506. {
  1507. TRACE()"Repeat bitmap %x modified",(UINT)hChangedBitmap));
  1508. sbcThrashers[0].modified = TRUE;
  1509. }
  1510. else
  1511. {
  1512. nextIndex = 0;
  1513. nextTickCount = (int)(CO_GET_TICK_COUNT()/32);
  1514. tickDelta = abs(nextTickCount - sbcThrashers[0].tickCount);
  1515. for (i=1; i<SBC_NUM_THRASHERS; i++)
  1516. {
  1517. if (sbcThrashers[i].hBitmap == hChangedBitmap)
  1518. {
  1519. sbcThrashers[i].modified = TRUE;
  1520. break;
  1521. }
  1522. tickWork = abs(nextTickCount - sbcThrashers[i].tickCount);
  1523. if (tickWork > tickDelta)
  1524. {
  1525. tickDelta = tickWork;
  1526. nextIndex = i;
  1527. }
  1528. }
  1529. //
  1530. // If not found in the list then add to the list. Always add to
  1531. // the top of the list so we find repeated bitmaps as the first
  1532. // entry
  1533. //
  1534. if (i == SBC_NUM_THRASHERS)
  1535. {
  1536. TRACE()"Relegating bitmap %x at list pos %u",
  1537. (UINT)sbcThrashers[nextIndex].hBitmap,nextIndex));
  1538. if (nextIndex != 0)
  1539. {
  1540. sbcThrashers[nextIndex].hBitmap = sbcThrashers[0].hBitmap;
  1541. sbcThrashers[nextIndex].tickCount = sbcThrashers[0].tickCount;
  1542. sbcThrashers[nextIndex].modified = sbcThrashers[0].modified;
  1543. }
  1544. sbcThrashers[0].hBitmap = hChangedBitmap;
  1545. sbcThrashers[0].tickCount = nextTickCount - BMC_THRASH_INTERVAL;
  1546. sbcThrashers[0].modified = TRUE;
  1547. TRACE()"Adding bitmap %x to thrash list tick %u",
  1548. (TSHR_UINT16)hChangedBitmap, nextTickCount));
  1549. }
  1550. }
  1551. //
  1552. // We also maintain a list of "fast path" bitmaps, which is those tiles
  1553. // that have not been modified since we cached them and can therefore
  1554. // be interpreted from the handle alone. This must be an exhaustive
  1555. // search for each bitmap update and so we cannot offord the CPU of
  1556. // processing a very long list, but we can afford to cache enough to
  1557. // handle most animations. Also it is not worth the CPU to try and
  1558. // save individual tiles here. We just evict the complete bitmap.
  1559. //
  1560. for (i=0; i<SBC_NUM_FASTPATH; i++)
  1561. {
  1562. if (sbcFastPath[i].hBitmap == hChangedBitmap)
  1563. {
  1564. TRACE()"Bitmap %x no longer fastpathed",(UINT)hChangedBitmap));
  1565. sbcFastPath[i].hBitmap = 0;
  1566. }
  1567. }
  1568. return;
  1569. }
  1570. //
  1571. // SBC_BitmapDeleted()
  1572. //
  1573. // See asbcapi.h for description.
  1574. //
  1575. DCVOID DCAPI SBC_BitmapDeleted(HBITMAP hDeletedBitmap)
  1576. {
  1577. UINT i;
  1578. TRACE_FN("SBC_BitmapDeleted");
  1579. //
  1580. // Remove the bitmap from the thrashy list.
  1581. //
  1582. for (i=0; i<SBC_NUM_THRASHERS; i++)
  1583. {
  1584. if (sbcThrashers[i].hBitmap == hDeletedBitmap)
  1585. {
  1586. TRACE_DBG()"Bitmap %x no longer thrashing",hDeletedBitmap));
  1587. sbcThrashers[i].hBitmap = 0;
  1588. sbcThrashers[i].tickCount = 0;
  1589. break;
  1590. }
  1591. }
  1592. //
  1593. // We also maintain a list of "fast path" bitmaps, which is those tiles
  1594. // that have not been modified since we cached them and can therefore
  1595. // be interpreted from the handle alone. This must be an exhaustive
  1596. // search for each bitmap update and so we cannot offord the CPU of
  1597. // processing a very long list, but we can afford to cache enough to
  1598. // handle most animations. Also it is not worth the CPU to try and
  1599. // save individual tiles here. We just evict the complete bitmap.
  1600. //
  1601. for (i=0; i<SBC_NUM_FASTPATH; i++)
  1602. {
  1603. if (sbcFastPath[i].hBitmap == hDeletedBitmap)
  1604. {
  1605. TRACE()"Bitmap %x no longer fastpathed",(UINT)hDeletedBitmap));
  1606. sbcFastPath[i].hBitmap = 0;
  1607. sbcFastPath[i].tickCount = 0;
  1608. }
  1609. }
  1610. return;
  1611. }
  1612. //
  1613. // SBC_ColorsChanged()
  1614. //
  1615. // Called whenever the system palette changes (presumably as a result of
  1616. // a new logical palette being realized to the screen).
  1617. //
  1618. //
  1619. DCVOID DCAPI SBC_ColorsChanged(DCVOID)
  1620. {
  1621. TRACE_FN("SBC_ColorsChanged");
  1622. //
  1623. // Just clear out all the fast path cache because we can no longer
  1624. // trust the cached bits to accurately reflect the color table we
  1625. // have cached. (Note that this does not mean we will not use the
  1626. // bits without resending, merely that we will force a retest of
  1627. // the bits with the latest color info selected.
  1628. //
  1629. TRACE()"Fastpath table reset"));
  1630. memset(sbcFastPath, 0, sizeof(sbcFastPath));
  1631. }
  1632. #endif