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.

1376 lines
40 KiB

  1. #include "precomp.h"
  2. //
  3. // SBC.C
  4. // Send Bitmap Cache, display driver side
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. //
  9. //
  10. // SBC_DDProcessRequest() - see sbc.h
  11. //
  12. //
  13. BOOL SBC_DDProcessRequest
  14. (
  15. SURFOBJ* pso,
  16. DWORD fnEscape,
  17. LPOSI_ESCAPE_HEADER pRequest,
  18. LPOSI_ESCAPE_HEADER pResult,
  19. DWORD cbResult
  20. )
  21. {
  22. BOOL rc;
  23. LPOSI_PDEV ppDev = (LPOSI_PDEV)pso->dhpdev;
  24. DebugEntry(SBC_DDProcessRequest);
  25. //
  26. // Get the request number.
  27. //
  28. switch (fnEscape)
  29. {
  30. case SBC_ESC_NEW_CAPABILITIES:
  31. {
  32. if (cbResult != sizeof(SBC_NEW_CAPABILITIES))
  33. {
  34. ERROR_OUT(("SBC_DDProcessRequest: Invalid size %d for SBC_ESC_NEW_CAPABILITIES",
  35. cbResult));
  36. rc = FALSE;
  37. DC_QUIT;
  38. }
  39. TRACE_OUT(("SBC_ESC_NEW_CAPABILITIES"));
  40. SBCDDSetNewCapabilities((LPSBC_NEW_CAPABILITIES)pRequest);
  41. rc = TRUE;
  42. }
  43. break;
  44. default:
  45. {
  46. ERROR_OUT(("Unrecognized SBC_ escape"));
  47. rc = FALSE;
  48. }
  49. break;
  50. }
  51. DC_EXIT_POINT:
  52. DebugExitBOOL(SBC_DDProcessRequest, rc);
  53. return(rc);
  54. }
  55. //
  56. //
  57. // SBC_DDInit() - see sbc.h
  58. //
  59. //
  60. BOOL SBC_DDInit
  61. (
  62. LPOSI_PDEV ppDev,
  63. LPBYTE pRestOfMemory,
  64. DWORD cbRestOfMemory,
  65. LPOSI_INIT_REQUEST pResult
  66. )
  67. {
  68. UINT i;
  69. SIZEL bitmapSize;
  70. BOOL rc = FALSE;
  71. DebugEntry(SBC_DDInit);
  72. //
  73. // We have to create work DIBs to Blt into when SBC_CacheMemScreenBlt
  74. // is called.
  75. //
  76. for (i = 0 ; i < SBC_NUM_TILE_SIZES ; i++)
  77. {
  78. ASSERT(!g_asbcWorkInfo[i].pShuntBuffer);
  79. ASSERT(!g_asbcWorkInfo[i].mruIndex);
  80. ASSERT(!g_asbcWorkInfo[i].workBitmap);
  81. if (i == SBC_MEDIUM_TILE_INDEX)
  82. {
  83. g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileWidth = MP_MEDIUM_TILE_WIDTH;
  84. g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileHeight = MP_MEDIUM_TILE_HEIGHT;
  85. }
  86. else
  87. {
  88. ASSERT(i == SBC_LARGE_TILE_INDEX);
  89. g_asbcWorkInfo[SBC_LARGE_TILE_INDEX].tileWidth = MP_LARGE_TILE_WIDTH;
  90. g_asbcWorkInfo[SBC_LARGE_TILE_INDEX].tileHeight = MP_LARGE_TILE_HEIGHT;
  91. }
  92. //
  93. // Create the bitmap. Note that we create it "top down" rather
  94. // than the default of "bottom up" to simplify copying data from
  95. // the bitmap (we don't have to work out offsets into the data - we
  96. // can copy from the beginning).
  97. //
  98. // We set the last parameter to NULL, to allow GDI to allocate
  99. // memory for the bits. We can get a pointer to the bits later
  100. // when we have a SURFOBJ for the bitmap.
  101. //
  102. bitmapSize.cx = g_asbcWorkInfo[i].tileWidth;
  103. bitmapSize.cy = g_asbcWorkInfo[i].tileHeight;
  104. g_asbcWorkInfo[i].workBitmap = EngCreateBitmap(bitmapSize,
  105. BYTES_IN_BITMAP(g_asbcWorkInfo[i].tileWidth, 1, ppDev->cBitsPerPel),
  106. ppDev->iBitmapFormat, BMF_TOPDOWN, NULL);
  107. if (! g_asbcWorkInfo[i].workBitmap)
  108. {
  109. ERROR_OUT(( "Failed to create work bitmap %d", i));
  110. DC_QUIT;
  111. }
  112. }
  113. //
  114. // Initialize the shunt buffers
  115. //
  116. if (! SBCDDCreateShuntBuffers(ppDev, pRestOfMemory, cbRestOfMemory))
  117. {
  118. ERROR_OUT(( "Failed to create shunt buffers"));
  119. DC_QUIT;
  120. }
  121. //
  122. // Set up the remaining global variables
  123. //
  124. EngQueryPerformanceFrequency(&g_sbcPerfFrequency);
  125. //
  126. // OK, so we can create our SBC cache. Fill in the details.
  127. //
  128. for (i = 0 ; i < SBC_NUM_TILE_SIZES; i++)
  129. {
  130. //
  131. // This is filling in the APP address to the shunt buffers.
  132. //
  133. pResult->psbcTileData[i] = (LPBYTE)pResult->pSharedMemory +
  134. PTRBASE_TO_OFFSET(g_asbcWorkInfo[i].pShuntBuffer, g_asSharedMemory);
  135. }
  136. pResult->aBitmasks[0] = ppDev->flRed;
  137. pResult->aBitmasks[1] = ppDev->flGreen;
  138. pResult->aBitmasks[2] = ppDev->flBlue;
  139. //
  140. // If we are a palette device (i.e. we are running at 8 bpp or less),
  141. // set the paletteChanged flag so that we will send a color table to
  142. // the share core before our first Mem(3)Blt.
  143. //
  144. ppDev->paletteChanged = (ppDev->cBitsPerPel <= 8);
  145. rc = TRUE;
  146. DC_EXIT_POINT:
  147. DebugExitBOOL(SBC_DDInit, rc);
  148. return(rc);
  149. }
  150. //
  151. //
  152. // SBC_DDTerm() - see sbc.h
  153. //
  154. //
  155. void SBC_DDTerm(void)
  156. {
  157. UINT i;
  158. DebugEntry(SBC_DDTerm);
  159. //
  160. // We just have to set the pointers to the shunt buffers to NULL
  161. //
  162. for (i = 0 ; i < SBC_NUM_TILE_SIZES ; i++)
  163. {
  164. // Kill the bitmap if there
  165. if (g_asbcWorkInfo[i].workBitmap)
  166. {
  167. EngDeleteSurface((HSURF)g_asbcWorkInfo[i].workBitmap);
  168. g_asbcWorkInfo[i].workBitmap = 0;
  169. }
  170. g_asbcWorkInfo[i].pShuntBuffer = NULL;
  171. g_asbcWorkInfo[i].mruIndex = 0;
  172. }
  173. DebugExitVOID(SBC_DDTerm);
  174. }
  175. //
  176. //
  177. // SBC_DDIsMemScreenBltCachable() - see sbc.h
  178. //
  179. //
  180. BOOL SBC_DDIsMemScreenBltCachable(LPMEMBLT_ORDER_EXTRA_INFO pMemBltInfo)
  181. {
  182. BOOL rc = FALSE;
  183. UINT tileWidth;
  184. UINT tileHeight;
  185. SURFOBJ * pSourceSurf;
  186. DebugEntry(SBC_DDIsMemScreenBltCachable);
  187. //
  188. // Is this an RLE bitmap - these bitmaps can have effective transparent
  189. // sections which we cannot mimic with SBC.
  190. //
  191. pSourceSurf = pMemBltInfo->pSource;
  192. if ( (pSourceSurf->iBitmapFormat == BMF_4RLE) ||
  193. (pSourceSurf->iBitmapFormat == BMF_8RLE) )
  194. {
  195. TRACE_OUT(( "RLE Bitmap %d", pSourceSurf->iBitmapFormat));
  196. DC_QUIT;
  197. }
  198. //
  199. // If this is a thrasher then don't cache it
  200. //
  201. if (SBCDDIsBitmapThrasher(pSourceSurf))
  202. {
  203. TRACE_OUT(( "Its a thrasher"));
  204. DC_QUIT;
  205. }
  206. //
  207. // Make sure that this bitmap can be tiled OK
  208. //
  209. if (!SBC_DDQueryBitmapTileSize(pSourceSurf->sizlBitmap.cx,
  210. pSourceSurf->sizlBitmap.cy,
  211. &tileWidth,
  212. &tileHeight))
  213. {
  214. TRACE_OUT(("Cache does not support tiling"));
  215. DC_QUIT;
  216. }
  217. rc = TRUE;
  218. DC_EXIT_POINT:
  219. DebugExitDWORD(SBC_DDIsMemScreenBltCachable, rc);
  220. return(rc);
  221. }
  222. //
  223. //
  224. // SBC_DDCacheMemScreenBlt() - see sbc.h
  225. //
  226. //
  227. BOOL SBC_DDCacheMemScreenBlt
  228. (
  229. LPINT_ORDER pOrder,
  230. LPMEMBLT_ORDER_EXTRA_INFO pMemBltInfo
  231. )
  232. {
  233. BOOL rc = FALSE;
  234. LPMEMBLT_ORDER pMemBltOrder = (LPMEMBLT_ORDER)&(pOrder->abOrderData);
  235. LPMEM3BLT_ORDER pMem3BltOrder = (LPMEM3BLT_ORDER)pMemBltOrder;
  236. UINT bmpWidth;
  237. UINT bmpHeight;
  238. UINT tileWidth;
  239. UINT tileHeight;
  240. POINTL tileOrg;
  241. UINT cxSubBitmapWidth;
  242. UINT cySubBitmapHeight;
  243. UINT type;
  244. SURFOBJ * pDestSurf;
  245. SURFOBJ * pSourceSurf;
  246. LPOSI_PDEV pDestDev;
  247. SURFOBJ * pWorkSurf = NULL;
  248. LPBYTE pWorkBits;
  249. RECTL destRectl;
  250. POINTL sourcePt;
  251. int tileSize;
  252. LPSBC_TILE_DATA pTileData = NULL;
  253. DebugEntry(SBC_DDCacheMemScreenBlt);
  254. //
  255. // Do a first pass on the cacheability of the Blt
  256. //
  257. if (!SBC_DDIsMemScreenBltCachable(pMemBltInfo))
  258. {
  259. TRACE_OUT(( "This MemBlt Order is not cachable"));
  260. DC_QUIT;
  261. }
  262. //
  263. // Get the width and height of the source bitmap
  264. //
  265. pSourceSurf = pMemBltInfo->pSource;
  266. bmpWidth = pSourceSurf->sizlBitmap.cx;
  267. bmpHeight = pSourceSurf->sizlBitmap.cy;
  268. //
  269. // Calculate the tile size for this blit
  270. //
  271. if (!SBC_DDQueryBitmapTileSize(bmpWidth, bmpHeight, &tileWidth, &tileHeight))
  272. {
  273. TRACE_OUT(("Cache does not support tiling"));
  274. DC_QUIT;
  275. }
  276. //
  277. // Set up pointers to the source coordinates in the order.
  278. //
  279. type = pMemBltOrder->type;
  280. if (type == ORD_MEMBLT_TYPE)
  281. {
  282. sourcePt.x = pMemBltOrder->nXSrc;
  283. sourcePt.y = pMemBltOrder->nYSrc;
  284. TRACE_OUT((
  285. "Request to cache MemBlt (%d, %d), %d x %d -> (%d, %d), src %x",
  286. sourcePt.x,
  287. sourcePt.y,
  288. pMemBltOrder->nWidth,
  289. pMemBltOrder->nHeight,
  290. pMemBltOrder->nLeftRect,
  291. pMemBltOrder->nTopRect,
  292. pSourceSurf->hsurf));
  293. }
  294. else
  295. {
  296. sourcePt.x = pMem3BltOrder->nXSrc;
  297. sourcePt.y = pMem3BltOrder->nYSrc;
  298. TRACE_OUT((
  299. "Request to cache Mem3Blt (%d, %d), %d x %d -> (%d, %d), src %x",
  300. sourcePt.x,
  301. sourcePt.y,
  302. pMem3BltOrder->nWidth,
  303. pMem3BltOrder->nHeight,
  304. pMem3BltOrder->nLeftRect,
  305. pMem3BltOrder->nTopRect,
  306. pSourceSurf->hsurf));
  307. }
  308. //
  309. // Calculate the tile origin and size of remaining bitmap. Origin is
  310. // rounded down to the nearest tile. Actual size of bitmap to cache
  311. // may be smaller than tile size if the tile runs off the right/bottom
  312. // of the bitmap
  313. //
  314. tileOrg.x = sourcePt.x - (sourcePt.x % tileWidth);
  315. tileOrg.y = sourcePt.y - (sourcePt.y % tileHeight);
  316. //
  317. // Actual size of bitmap to cache may be smaller than tile size if the
  318. // tile runs off the right/bottom of the bitmap. To see why this
  319. // calculation is correct, realize that (bmpWidth - tileOrg.x) is the
  320. // remaining width of the bitmap after the start of this tile.
  321. //
  322. cxSubBitmapWidth = min(tileWidth, bmpWidth - tileOrg.x);
  323. cySubBitmapHeight = min(tileHeight, bmpHeight - tileOrg.y);
  324. //
  325. // We know how large a tile we have - we now have to Blt it into one of
  326. // our work bitmaps and pass it up to the share core. First, work out
  327. // which of our work bitmaps we should use and set up some variables
  328. // based on this.
  329. //
  330. for (tileSize = 0; tileSize < SBC_NUM_TILE_SIZES ; tileSize++)
  331. {
  332. if ((cxSubBitmapWidth <= g_asbcWorkInfo[tileSize].tileWidth) &&
  333. (cySubBitmapHeight <= g_asbcWorkInfo[tileSize].tileHeight))
  334. {
  335. break;
  336. }
  337. }
  338. if (tileSize == SBC_NUM_TILE_SIZES)
  339. {
  340. ERROR_OUT(( "%d x %d tile doesn't fit into work bmp",
  341. cxSubBitmapWidth,
  342. cySubBitmapHeight));
  343. DC_QUIT;
  344. }
  345. //
  346. // Before doing any more work, get the next free entry in the shunt
  347. // buffer. Note that this fills in the tileId element of the returned
  348. // structure.
  349. //
  350. // It is perfectly valid for this call to fail. The shunt buffer may
  351. // just be full if we are sending lots of bitmap data up to the share
  352. // core.
  353. //
  354. if (!SBCDDGetNextFreeTile(tileSize, &pTileData))
  355. {
  356. TRACE_OUT(( "Unable to get a free tile in shunt buffer"));
  357. DC_QUIT;
  358. }
  359. //
  360. // Lock the work bitmap to get a surface to pass to EngBitBlt
  361. //
  362. pWorkSurf = EngLockSurface((HSURF)g_asbcWorkInfo[tileSize].workBitmap);
  363. if (pWorkSurf == NULL)
  364. {
  365. ERROR_OUT(( "Failed to lock work surface"));
  366. DC_QUIT;
  367. }
  368. TRACE_OUT(( "Locked surface"));
  369. //
  370. // Do the Blt to our work bitmap to get the bits at native bpp, and
  371. // using the color table which we sent to the share core.
  372. //
  373. destRectl.top = 0;
  374. destRectl.left = 0;
  375. destRectl.right = cxSubBitmapWidth;
  376. destRectl.bottom = cySubBitmapHeight;
  377. sourcePt = tileOrg;
  378. if (!EngBitBlt(pWorkSurf,
  379. pSourceSurf,
  380. NULL, // mask surface
  381. NULL, // clip object
  382. pMemBltInfo->pXlateObj,
  383. &destRectl,
  384. &sourcePt,
  385. NULL, // mask origin
  386. NULL, // brush
  387. NULL, // brush origin
  388. 0xcccc)) // SRCCPY
  389. {
  390. ERROR_OUT(( "Failed to Blt to work bitmap"));
  391. DC_QUIT;
  392. }
  393. TRACE_OUT(( "Completed BitBlt"));
  394. //
  395. // The Blt succeeded, so pass the bits to the share core by copying
  396. // them into the correct shunt buffer.
  397. //
  398. // bytesUsed is set to the number of bytes required for
  399. // cySubBitmapHeight number of full scanlines in the shunt buffer tile
  400. // (NOT the number of bytes available in the tile, or the number of
  401. // bytes of data which was actually Blted)
  402. //
  403. // major/minorCacheInfo are set to details from the source surface.
  404. // hdev does not change on consecutive Blts from the same surface, but
  405. // iUniq may.
  406. //
  407. pDestSurf = pMemBltInfo->pDest;
  408. pDestDev = (LPOSI_PDEV)pDestSurf->dhpdev;
  409. pTileData->bytesUsed = BYTES_IN_BITMAP(g_asbcWorkInfo[tileSize].tileWidth,
  410. cySubBitmapHeight,
  411. pDestDev->cBitsPerPel);
  412. pTileData->srcX = (TSHR_UINT16)sourcePt.x;
  413. pTileData->srcY = (TSHR_UINT16)sourcePt.y;
  414. pTileData->width = (WORD)cxSubBitmapWidth;
  415. pTileData->height = (WORD)cySubBitmapHeight;
  416. pTileData->tilingWidth = (WORD)tileWidth;
  417. pTileData->tilingHeight = (WORD)tileHeight;
  418. pTileData->majorCacheInfo = (UINT_PTR)pSourceSurf->hsurf;
  419. pTileData->minorCacheInfo = (UINT)pSourceSurf->iUniq;
  420. pTileData->majorPalette = (UINT_PTR)pMemBltInfo->pXlateObj;
  421. pTileData->minorPalette = (UINT)(pMemBltInfo->pXlateObj != NULL ?
  422. pMemBltInfo->pXlateObj->iUniq : 0);
  423. //
  424. // If the source surface has the BMF_DONTCACHE flag set then it is a
  425. // DIB Section. This means that an app can change the bits in the
  426. // surface without calling GDI, and hence without the iUniq value being
  427. // updated.
  428. //
  429. // We rely on iUniq changing for the fast path to work, so we must
  430. // exclude these bitmaps from the fast path. Do this by resetting the
  431. // majorCacheInfo field (we use this rather than minorCacheInfo because
  432. // we can't tell what an invalid iUniq value is).
  433. //
  434. if ( (pSourceSurf->iType == STYPE_BITMAP) &&
  435. ((pSourceSurf->fjBitmap & BMF_DONTCACHE) != 0) )
  436. {
  437. TRACE_OUT(( "Source hsurf %#.8lx has BMF_DONTCACHE set",
  438. pTileData->majorCacheInfo));
  439. pTileData->majorCacheInfo = SBC_DONT_FASTPATH;
  440. }
  441. //
  442. // Note that this only works correctly because we create our work
  443. // bitmaps to be "top down" rather than the default of "bottom up".
  444. // i.e. the data for the top scanline is first in memory, so we can
  445. // start copying from the start of the bit data. Bottom up would mean
  446. // working out an offset into the work bitmap to start copying from.
  447. //
  448. memcpy(pTileData->bitData, pWorkSurf->pvBits, pTileData->bytesUsed);
  449. //
  450. // We've done the copy. Reset the work bitmap bits for next time we
  451. // use this work bitmap - this helps with compression later on.
  452. //
  453. memset(pWorkSurf->pvBits, 0, pWorkSurf->cjBits);
  454. //
  455. // Fill in the required info in the Mem(3)Blt order.
  456. //
  457. if (type == ORD_MEMBLT_TYPE)
  458. {
  459. pMemBltOrder->cacheId = pTileData->tileId;
  460. }
  461. else
  462. {
  463. pMem3BltOrder->cacheId = pTileData->tileId;
  464. }
  465. //
  466. // We've filled in all the data in the shunt buffer entry, so mark it
  467. // as in use so that the share core can access it.
  468. //
  469. pTileData->inUse = TRUE;
  470. //
  471. // Must have completed successfully to get to here
  472. //
  473. TRACE_OUT(( "Queued tile (%d, %d), %d x %d, tile %d x %d, Id %hx",
  474. sourcePt.x,
  475. sourcePt.y,
  476. cxSubBitmapWidth,
  477. cySubBitmapHeight,
  478. g_asbcWorkInfo[tileSize].tileWidth,
  479. g_asbcWorkInfo[tileSize].tileHeight,
  480. pTileData->tileId));
  481. rc = TRUE;
  482. DC_EXIT_POINT:
  483. //
  484. // Unlock the work surface (if required)
  485. //
  486. if (pWorkSurf != NULL)
  487. {
  488. EngUnlockSurface(pWorkSurf);
  489. TRACE_OUT(( "Unlocked surface"));
  490. }
  491. DebugExitDWORD(SBC_DDCacheMemScreenBlt, rc);
  492. return(rc);
  493. }
  494. //
  495. // SBC_DDQueryBitmapTileSize()
  496. //
  497. // Once 2.X COMPAT is gone, we don't need this anymore. We won't set our
  498. // random cell sizes based off of what REMOTES say.
  499. //
  500. BOOL SBC_DDQueryBitmapTileSize
  501. (
  502. UINT bmpWidth,
  503. UINT bmpHeight,
  504. UINT * pTileWidth,
  505. UINT * pTileHeight
  506. )
  507. {
  508. BOOL rc = FALSE;
  509. DebugEntry(SBC_DDQueryBitmapTileSize);
  510. //
  511. // The tile cell sizes are currently changed when back level nodes
  512. // join in a 3.0 call, in which case we must take the MINIMUM of the
  513. // cell sizes/entries for everybody in the share.
  514. //
  515. if (g_asbcCacheInfo[ID_LARGE_BMP_CACHE].cCellSize <
  516. BYTES_IN_BITMAP(g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileWidth,
  517. g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileHeight,
  518. g_sbcSendingBPP))
  519. {
  520. //
  521. // This should be a short-term thing. When an old dude joins the
  522. // share, we'll also adjust g_sbcSendingBPP.
  523. //
  524. TRACE_OUT(("SBC_DDQueryBitmapTileSize: No space for any cells"));
  525. DC_QUIT;
  526. }
  527. rc = TRUE;
  528. //
  529. // If the large size is adequate, use that cell size
  530. //
  531. if (g_asbcCacheInfo[ID_LARGE_BMP_CACHE].cCellSize >=
  532. BYTES_IN_BITMAP(g_asbcWorkInfo[SBC_LARGE_TILE_INDEX].tileWidth,
  533. g_asbcWorkInfo[SBC_LARGE_TILE_INDEX].tileHeight,
  534. g_sbcSendingBPP))
  535. {
  536. if ((bmpWidth > g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileWidth) ||
  537. (bmpHeight > g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileHeight))
  538. {
  539. *pTileWidth = g_asbcWorkInfo[SBC_LARGE_TILE_INDEX].tileWidth;
  540. *pTileHeight = g_asbcWorkInfo[SBC_LARGE_TILE_INDEX].tileHeight;
  541. DC_QUIT;
  542. }
  543. }
  544. //
  545. // Sigh, medium cells it is.
  546. //
  547. *pTileWidth = g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileWidth;
  548. *pTileHeight = g_asbcWorkInfo[SBC_MEDIUM_TILE_INDEX].tileHeight;
  549. DC_EXIT_POINT:
  550. DebugExitBOOL(SBC_DDQueryBitmapTileSize, rc);
  551. return(rc);
  552. }
  553. //
  554. //
  555. // SBC_DDSyncUpdatesNow() - see sbc.h
  556. //
  557. //
  558. void SBC_DDSyncUpdatesNow(LPOSI_PDEV ppDev)
  559. {
  560. LPSBC_TILE_DATA pTileData;
  561. UINT i;
  562. UINT j;
  563. DebugEntry(SBC_DDSyncUpdatesNow);
  564. TRACE_OUT(( "Marking all shunt buffer entries as not in use"));
  565. //
  566. // We have to mark all entries in the shunt buffers as being free.
  567. //
  568. for (i = 0; i < SBC_NUM_TILE_SIZES ; i++)
  569. {
  570. for (j = 0; j < g_asbcWorkInfo[i].pShuntBuffer->numEntries ; j++)
  571. {
  572. pTileData = SBCTilePtrFromIndex(g_asbcWorkInfo[i].pShuntBuffer, j);
  573. pTileData->inUse = FALSE;
  574. }
  575. //
  576. // Reset the MRU counter for this shunt buffer
  577. //
  578. g_asbcWorkInfo[i].mruIndex = 0;
  579. }
  580. //
  581. // If we are a palette device (i.e. we are running at 8 bpp or less),
  582. // set the paletteChanged flag so we will send up a color table before
  583. // our next Mem(3)Blt. We do this because the color table order for
  584. // the current device palette may have been discarded during the OA
  585. // sync.
  586. //
  587. ppDev->paletteChanged = (ppDev->cBitsPerPel <= 8);
  588. DebugExitVOID(SBC_DDSyncUpdatesNow);
  589. }
  590. //
  591. //
  592. // SBC_DDOrderSpoiltNotification() - see sbc.h
  593. //
  594. //
  595. void SBC_DDOrderSpoiltNotification(LPINT_ORDER pOrder)
  596. {
  597. LPMEMBLT_ORDER pMemBltOrder = (LPMEMBLT_ORDER)&(pOrder->abOrderData);
  598. LPMEM3BLT_ORDER pMem3BltOrder = (LPMEM3BLT_ORDER)pMemBltOrder;
  599. UINT tileId;
  600. LPSBC_TILE_DATA pTileData;
  601. UINT tileType;
  602. UINT i;
  603. DebugEntry(SBC_DDOrderSpoiltNotification);
  604. //
  605. // pOrder has been removed from the order heap before being processed.
  606. // We have to free up the entry which it references in one of the shunt
  607. // buffers. First get the tile Id.
  608. //
  609. if (pMemBltOrder->type = ORD_MEMBLT_TYPE)
  610. {
  611. tileId = pMemBltOrder->cacheId;
  612. }
  613. else
  614. {
  615. tileId = pMem3BltOrder->cacheId;
  616. }
  617. TRACE_OUT(( "Order referencing tile %hx has been spoiled", tileId));
  618. //
  619. // Find out which of the shunt buffers the entry should be in based on
  620. // the tileId
  621. //
  622. tileType = SBC_TILE_TYPE(tileId);
  623. //
  624. // We implement the shunt buffers as circular FIFO queues, so we will
  625. // start looking from the last order which we marked as being in use,
  626. // and work BACKWARDS. This is because, in general, the entries after
  627. // the last one we accessed will not be in use (unless the whole shunt
  628. // buffer is in use).
  629. //
  630. // So, get the index of the last tile we accessed.
  631. //
  632. i = g_asbcWorkInfo[tileType].mruIndex;
  633. //
  634. // Loop through the circular buffer until we get a match, or have
  635. // circled back to the beginning.
  636. //
  637. // Note that this has been coded as a "do while" loop, rather than just
  638. // a "while" loop so that we don't miss mruIndex. mruIndex is set up
  639. // to point to the NEXT entry to be used, rather than the last entry to
  640. // be used, so decrementing i before doing any work first time round
  641. // the loop is actually what we want to do.
  642. //
  643. do
  644. {
  645. //
  646. // On to the next tile
  647. //
  648. i = (i == 0)
  649. ? g_asbcWorkInfo[tileType].pShuntBuffer->numEntries - 1
  650. : i - 1;
  651. pTileData = SBCTilePtrFromIndex(g_asbcWorkInfo[tileType].pShuntBuffer, i);
  652. if (pTileData->inUse && (pTileData->tileId == tileId))
  653. {
  654. //
  655. // We've got a match, so mark the tile as being free.
  656. //
  657. // We don't want to update the shunt buffer mruIndex - this
  658. // should remain indicating the next tile to be used when
  659. // adding an entry to the shunt buffer.
  660. //
  661. TRACE_OUT(( "Marked tile Id %hx at index %d as free",
  662. tileId,
  663. i));
  664. pTileData->inUse = FALSE;
  665. break;
  666. }
  667. }
  668. while (i != g_asbcWorkInfo[tileType].mruIndex);
  669. DebugExitVOID(SBC_DDOrderSpoiltNotification);
  670. }
  671. //
  672. //
  673. // SBC_DDMaybeQueueColorTable() - see sbc.h
  674. //
  675. //
  676. BOOL SBC_DDMaybeQueueColorTable(LPOSI_PDEV ppDev)
  677. {
  678. BOOL queuedOK = FALSE;
  679. int orderSize;
  680. LPINT_ORDER pOrder;
  681. LPINT_COLORTABLE_ORDER_1BPP pColorTableOrder;
  682. UINT numColors;
  683. UINT i;
  684. DebugEntry(SBC_DDMaybeQueueColorTable);
  685. //
  686. // If we're running at > 8 bpp, then we don't have a palette, so just
  687. // quit out.
  688. //
  689. if (ppDev->cBitsPerPel > 8)
  690. {
  691. queuedOK = TRUE;
  692. DC_QUIT;
  693. }
  694. //
  695. // Check the boolean in our PDEV to see if the palette has changed
  696. // since the last time we sent a color table order. Note that if we
  697. // have a non palette device, the boolean will never be set.
  698. //
  699. if (!ppDev->paletteChanged)
  700. {
  701. queuedOK = TRUE;
  702. DC_QUIT;
  703. }
  704. //
  705. // The palette has changed, so allocate order memory to queue a color
  706. // table order. The order size depends on the bpp of our device. Note
  707. // that the allocation can fail if the order buffer is full.
  708. //
  709. switch (ppDev->cBitsPerPel)
  710. {
  711. case 1:
  712. {
  713. orderSize = sizeof(INT_COLORTABLE_ORDER_1BPP);
  714. }
  715. break;
  716. case 4:
  717. {
  718. orderSize = sizeof(INT_COLORTABLE_ORDER_4BPP);
  719. }
  720. break;
  721. case 8:
  722. {
  723. orderSize = sizeof(INT_COLORTABLE_ORDER_8BPP);
  724. }
  725. break;
  726. default:
  727. {
  728. ERROR_OUT(("Invalid bpp (%d) for palette device", ppDev->cBitsPerPel));
  729. DC_QUIT;
  730. }
  731. break;
  732. }
  733. pOrder = OA_DDAllocOrderMem(orderSize, 0);
  734. if (pOrder == NULL)
  735. {
  736. TRACE_OUT(( "Failed to allocate %d bytes for order", orderSize));
  737. DC_QUIT;
  738. }
  739. TRACE_OUT(( "Allocate %d bytes for color table order", orderSize));
  740. //
  741. // We've successfully allocated the order, so fill in the details. We
  742. // mark the order as internal so that the Update Packager will spot it
  743. // up in the share core and prevent it being sent over the wire.
  744. //
  745. pOrder->OrderHeader.Common.fOrderFlags = OF_INTERNAL;
  746. pColorTableOrder = (LPINT_COLORTABLE_ORDER_1BPP)&(pOrder->abOrderData);
  747. pColorTableOrder->header.type = INTORD_COLORTABLE_TYPE;
  748. pColorTableOrder->header.bpp = (TSHR_UINT16)ppDev->cBitsPerPel;
  749. //
  750. // Unfortunately we can't just copy the palette from the PDEV into the
  751. // color table order because the PDEV has an array of PALETTEENTRY
  752. // structures which are RGBs whereas the order has an array of
  753. // TSHR_RGBQUADs which are BGRs...
  754. //
  755. numColors = COLORS_FOR_BPP(ppDev->cBitsPerPel);
  756. ASSERT(numColors);
  757. for (i = 0; i < numColors; i++)
  758. {
  759. pColorTableOrder->colorData[i].rgbRed = ppDev->pPal[i].peRed;
  760. pColorTableOrder->colorData[i].rgbGreen = ppDev->pPal[i].peGreen;
  761. pColorTableOrder->colorData[i].rgbBlue = ppDev->pPal[i].peBlue;
  762. }
  763. //
  764. // Add the order
  765. //
  766. OA_DDAddOrder(pOrder, NULL);
  767. TRACE_OUT(( "Added internal color table order, size %d", orderSize));
  768. //
  769. // Reset the flag which indicates that the palette needs to be sent
  770. //
  771. ppDev->paletteChanged = FALSE;
  772. //
  773. // Must be OK to get to here
  774. //
  775. queuedOK = TRUE;
  776. DC_EXIT_POINT:
  777. DebugExitBOOL(SBC_DDMaybeQueueColorTable, queuedOK);
  778. return(queuedOK);
  779. }
  780. //
  781. // SBCDDCreateShuntBuffers()
  782. //
  783. // Here's where we calc how many cache entries (tiles) we can support. This
  784. // depends on:
  785. // * The amount of shared memory we have
  786. // * The color depth of the driver
  787. //
  788. // There is an upper bound on the amount of memory we'll use, since this
  789. // maps to how much memory on remotes will be needed to store our sent
  790. // cache entries.
  791. //
  792. // The tiles are created in a fixed proportion (MP_RATIO_MTOL).
  793. //
  794. // We return TRUE for success if we can set up the caches and create the
  795. // objects necessary for a sent bitmap cache.
  796. //
  797. BOOL SBCDDCreateShuntBuffers
  798. (
  799. LPOSI_PDEV ppDev,
  800. LPBYTE psbcSharedMemory,
  801. DWORD sbcSharedMemorySize
  802. )
  803. {
  804. int i;
  805. UINT memPerBuffer[SBC_NUM_TILE_SIZES];
  806. UINT memPerTile[SBC_NUM_TILE_SIZES];
  807. UINT numTiles[SBC_NUM_TILE_SIZES];
  808. UINT memRequired;
  809. LPBYTE pBuffer = psbcSharedMemory;
  810. BOOL rc = FALSE;
  811. DebugEntry(SBCDDCreateShuntBuffers);
  812. //
  813. // We should already have a pointer to the shared memory we can use for
  814. // our shunt buffers, and the number of bytes available. What we have
  815. // to do is to partition this shared memory into SBC_NUM_TILE_SIZE
  816. // shunt buffers. i.e. one shunt buffer per tile size.
  817. //
  818. //
  819. // <--- buffer 0 ---><------------------ buffer 1 -------------------->
  820. //
  821. //��������������������������������������������������������������������Ŀ
  822. //� � : : : : � � : : : : �
  823. //� � : : : : � � tile : tile : tile : tile : tile �
  824. //� � : : : : � � : : : : �
  825. //����������������������������������������������������������������������
  826. //^ ^ ^
  827. //� � �
  828. //� ���� header[0] ���� header[1]
  829. //�
  830. //��� psbcSharedMemory
  831. //
  832. //
  833. // We try to use the number of entries given in the pEntries array, but
  834. // if we do not have enough shared memory for this, we reduce the
  835. // number of entries in each shunt buffer, preserving the ratio between
  836. // the number of entries in each of the shunt buffers.
  837. //
  838. //
  839. // First make sure that we have some shared memory
  840. //
  841. if (sbcSharedMemorySize == 0)
  842. {
  843. ERROR_OUT(( "No SBC shared memory !"));
  844. DC_QUIT;
  845. }
  846. // Max out at MP_MEMORY_MAX bytes
  847. sbcSharedMemorySize = min(sbcSharedMemorySize, MP_MEMORY_MAX);
  848. //
  849. // Do we have enough shared memory to satisfy the requested number of
  850. // entries in each shunt buffer ?
  851. //
  852. memRequired = 0;
  853. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  854. {
  855. memPerTile[i] = SBC_BYTES_PER_TILE(g_asbcWorkInfo[i].tileWidth,
  856. g_asbcWorkInfo[i].tileHeight,
  857. ppDev->cBitsPerPel);
  858. // We use the same amount of memory for each tile size.
  859. numTiles[i] = ((sbcSharedMemorySize / SBC_NUM_TILE_SIZES) -
  860. (sizeof(SBC_SHUNT_BUFFER) - sizeof(SBC_TILE_DATA))) /
  861. memPerTile[i];
  862. TRACE_OUT(("Can fit %d tiles of memory size %d in tile cache %d",
  863. numTiles[i], memPerTile[i], i));
  864. memPerBuffer[i] = (numTiles[i] * memPerTile[i]) +
  865. (sizeof(SBC_SHUNT_BUFFER) - sizeof(SBC_TILE_DATA));
  866. memRequired += memPerBuffer[i];
  867. }
  868. TRACE_OUT(( "%d bytes required for request, %d bytes available",
  869. memRequired,
  870. sbcSharedMemorySize));
  871. ASSERT(memRequired <= sbcSharedMemorySize);
  872. // Zero out rest of amount we're going to use
  873. RtlFillMemory(psbcSharedMemory, memRequired, 0);
  874. //
  875. // OK, we've got the
  876. // - the bytes per tile in memPerTile[i]
  877. // - number of entries per shunt buffer in numTiles[i]
  878. // - the total size of each shunt buffer in memPerBuffer[i].
  879. //
  880. // Do the partitioning.
  881. //
  882. for (i = 0; i < SBC_NUM_TILE_SIZES ; i++)
  883. {
  884. g_asbcWorkInfo[i].pShuntBuffer = (LPSBC_SHUNT_BUFFER)pBuffer;
  885. g_asbcWorkInfo[i].pShuntBuffer->numEntries = numTiles[i];
  886. g_asbcWorkInfo[i].pShuntBuffer->numBytes = memPerTile[i]
  887. - sizeof(SBC_TILE_DATA);
  888. g_asbcWorkInfo[i].pShuntBuffer->structureSize = memPerTile[i];
  889. //
  890. // Move the buffer pointer past the memory we are using for this
  891. // shunt buffer.
  892. //
  893. pBuffer += memPerBuffer[i];
  894. TRACE_OUT(( "Shunt buffer %d at %#.8lx: tile bytes %u, "
  895. "structure size %u, num entries %u",
  896. i,
  897. g_asbcWorkInfo[i].pShuntBuffer,
  898. g_asbcWorkInfo[i].pShuntBuffer->numBytes,
  899. g_asbcWorkInfo[i].pShuntBuffer->structureSize,
  900. g_asbcWorkInfo[i].pShuntBuffer->numEntries));
  901. //
  902. // Fill in the mruIndex for this shunt buffer
  903. //
  904. g_asbcWorkInfo[i].mruIndex = 0;
  905. }
  906. //
  907. // Initialize the global variables associated with the shunt buffers
  908. //
  909. g_sbcNextTileId = 0;
  910. //
  911. // Must be OK to get to here
  912. //
  913. rc = TRUE;
  914. DC_EXIT_POINT:
  915. DebugExitBOOL(SBCDDCreateShuntBuffers, rc);
  916. return(rc);
  917. }
  918. //
  919. // Name: SBCGetNextFreeTile
  920. //
  921. // Purpose: Return the next free tile of the correct size from one of the
  922. // shunt buffers.
  923. //
  924. // Returns: TRUE if a tile is returned, FALSE otherwise
  925. //
  926. // Params: IN workTileSize - The tile size. One of
  927. // SBC_MEDIUM_TILE
  928. // SBC_LARGE_TILE
  929. // OUT ppTileData - A pointer to the tile.
  930. //
  931. // Operation: The tileId field of the tile is filled in on return from
  932. // this function.
  933. //
  934. //
  935. BOOL SBCDDGetNextFreeTile(int tileSize, LPSBC_TILE_DATA FAR * ppTileData)
  936. {
  937. BOOL foundFreeTile = FALSE;
  938. LPSBC_TILE_DATA pTileData;
  939. DebugEntry(SBCDDGetNextFreeTile);
  940. //
  941. // Make sure that we have a valid tile size
  942. //
  943. if (tileSize >= SBC_NUM_TILE_SIZES)
  944. {
  945. ERROR_OUT(( "Invalid tile size %d", tileSize));
  946. DC_QUIT;
  947. }
  948. //
  949. // Get a pointer to the next entry to be used in the shunt buffer
  950. // containing tiles of the given size.
  951. //
  952. pTileData = SBCTilePtrFromIndex(g_asbcWorkInfo[tileSize].pShuntBuffer,
  953. g_asbcWorkInfo[tileSize].mruIndex);
  954. //
  955. // If the entry is still in use (the share core has not yet processed
  956. // the order which references this tile) we have to quit - the shunt
  957. // buffer is full.
  958. //
  959. if (pTileData->inUse)
  960. {
  961. TRACE_OUT(( "Target entry (%d, %d) is still in use",
  962. tileSize,
  963. g_asbcWorkInfo[tileSize].mruIndex));
  964. DC_QUIT;
  965. }
  966. //
  967. // The entry is not in use - we can re-use it. Fill in the Id field,
  968. // and the pointer to the entry which we return to the caller.
  969. //
  970. // We always set the top bit of the tile Id for large tiles, and clear
  971. // it for small tiles.
  972. //
  973. *ppTileData = pTileData;
  974. pTileData->tileId = g_sbcNextTileId;
  975. if (tileSize == SBC_MEDIUM_TILE_INDEX)
  976. {
  977. pTileData->tileId &= ~0x8000;
  978. }
  979. else
  980. {
  981. pTileData->tileId |= 0x8000;
  982. }
  983. TRACE_OUT(( "Returning entry (%d, %d), Id %hx",
  984. tileSize,
  985. g_asbcWorkInfo[tileSize].mruIndex,
  986. pTileData->tileId));
  987. //
  988. // Update the index of the next free entry in this shunt buffer, and
  989. // also the Id which we should assign next time. Remember to wrap the
  990. // shunt buffer index to the number of entries in the shunt buffer.
  991. //
  992. g_asbcWorkInfo[tileSize].mruIndex = (g_asbcWorkInfo[tileSize].mruIndex + 1) %
  993. g_asbcWorkInfo[tileSize].pShuntBuffer->numEntries;
  994. g_sbcNextTileId++;
  995. g_sbcNextTileId &= ~0x8000;
  996. //
  997. // Completed successfully !
  998. //
  999. foundFreeTile = TRUE;
  1000. DC_EXIT_POINT:
  1001. DebugExitBOOL(SBCDDGetNextFreeTile, foundFreeTile);
  1002. return(foundFreeTile);
  1003. }
  1004. //
  1005. //
  1006. // Name: SBCDDIsBitmapThrasher
  1007. //
  1008. // Purpose: Check to see if the given bitmap (surface object) is one
  1009. // which would cause cache thrashing.
  1010. //
  1011. // Returns: TRUE if the bitmap is a thrasher, FALSE otherwise.
  1012. //
  1013. // Params: IN pSurfObj - Pointer to the bitmap
  1014. //
  1015. //
  1016. BOOL SBCDDIsBitmapThrasher(SURFOBJ * pSurfObj)
  1017. {
  1018. UINT i;
  1019. BOOL rc = FALSE;
  1020. BOOL bitmapInList = FALSE;
  1021. BOOL updateEntry = FALSE;
  1022. UINT updateIndex;
  1023. UINT nextTickCount;
  1024. UINT evictIndex;
  1025. UINT evictTickCount;
  1026. DebugEntry(SBCDDIsBitmapThrasher);
  1027. //
  1028. // Here's an overview of how our bitmap cache thrash detection works...
  1029. //
  1030. // We hold an array of information about the last SBC_NUM_THRASHERS
  1031. // bitmaps which we have tried to cache. This information is
  1032. // - A value to identify the bitmap. This is the hsurf field from the
  1033. // bitmap surface object, and is different for every bitmap.
  1034. // - A value to identify the "version" of the bitmap. This is the
  1035. // iUniq field from the bitmap surface object, and is updated by GDI
  1036. // each time the bitmap is drawn to.
  1037. // - A timestamp for the last time which we saw iUniq change for this
  1038. // bitmap (or when we added the bitmap to the array).
  1039. //
  1040. // Each time this function is called, we scan this array looking for an
  1041. // entry for the bitmap.
  1042. //
  1043. // If we find an entry, we check whether the bitmap has changed (has
  1044. // the iUniq field changed). If it has not changed, the bitmap is not
  1045. // a thrasher. If the bitmap has changed, we check the interval from
  1046. // the timestamp value to the current time. If the interval is less
  1047. // than the SBC_THRASH_INTERVAL, the bitmap has changed too quickly, so
  1048. // it is a thrasher. If the interval is OK, the bitmap is not a
  1049. // thrasher. In either case, we update the stored iUniq field and the
  1050. // timestamp to record the time / version at which we spotted that the
  1051. // bitmap changed.
  1052. //
  1053. // If we do not find an entry for the bitmap, we add an entry for it.
  1054. // If the array is fully populated, we evict the entry with the oldest
  1055. // timestamp, and replace it with the new entry.
  1056. //
  1057. //
  1058. // Scan the thrasher list looking for a match
  1059. //
  1060. for (i=0 ; i<SBC_NUM_THRASHERS ; i++)
  1061. {
  1062. //
  1063. // If we find a match then we are only worried if it has been
  1064. // modified since the last time we read it.
  1065. //
  1066. if (g_sbcThrashers[i].hsurf == pSurfObj->hsurf)
  1067. {
  1068. bitmapInList = TRUE;
  1069. if (g_sbcThrashers[i].iUniq != pSurfObj->iUniq)
  1070. {
  1071. TRACE_OUT(( "Matching surface %x, index %u,"
  1072. "tick count %u has been modified",
  1073. pSurfObj->hsurf,
  1074. i,
  1075. g_sbcThrashers[i].tickCount));
  1076. updateEntry = TRUE;
  1077. updateIndex = i;
  1078. //
  1079. // Now we need to determine if this is a thrasher. It is a
  1080. // thrasher if the time we last read it is less than our
  1081. // thrash interval. (We only update the time when we read
  1082. // a modified bitmap)
  1083. //
  1084. nextTickCount = SBCDDGetTickCount();
  1085. if ((nextTickCount - g_sbcThrashers[i].tickCount) <
  1086. SBC_THRASH_INTERVAL)
  1087. {
  1088. TRACE_OUT((
  1089. "Rejected cache attempt of thrashy bitmap %x",
  1090. pSurfObj->hsurf));
  1091. rc = TRUE;
  1092. }
  1093. g_sbcThrashers[i].tickCount = nextTickCount;
  1094. g_sbcThrashers[i].iUniq = pSurfObj->iUniq;
  1095. }
  1096. //
  1097. // We've found a match - we can break out of the loop
  1098. //
  1099. break;
  1100. }
  1101. }
  1102. if (!bitmapInList)
  1103. {
  1104. //
  1105. // The bitmap isn't already in the thrasher list, so add it now.
  1106. // Find the entry with the smallest (earliest) tick count - we will
  1107. // evict this entry from the array to make room for the new entry.
  1108. //
  1109. evictIndex = 0;
  1110. evictTickCount = 0xffffffff;
  1111. for (i=0 ; i<SBC_NUM_THRASHERS ; i++)
  1112. {
  1113. if (evictTickCount > g_sbcThrashers[i].tickCount)
  1114. {
  1115. evictTickCount = g_sbcThrashers[i].tickCount;
  1116. evictIndex = i;
  1117. }
  1118. }
  1119. TRACE_OUT(( "Evicting entry %d, surface %x",
  1120. evictIndex,
  1121. g_sbcThrashers[i].hsurf));
  1122. nextTickCount = SBCDDGetTickCount();
  1123. TRACE_OUT(( "Adding surface %x to thrash list, tick %d",
  1124. pSurfObj->hsurf,
  1125. nextTickCount));
  1126. updateEntry = TRUE;
  1127. updateIndex = evictIndex;
  1128. }
  1129. if (updateEntry)
  1130. {
  1131. //
  1132. // We have to update the entry at index updateIndex. We optimise
  1133. // things slightly by always putting the most recent bitmap in
  1134. // position 0 of the array, so copy entry 0 to the eviction index,
  1135. // and put the new entry in position 0.
  1136. //
  1137. g_sbcThrashers[updateIndex] = g_sbcThrashers[0];
  1138. g_sbcThrashers[0].hsurf = pSurfObj->hsurf;
  1139. g_sbcThrashers[0].iUniq = pSurfObj->iUniq;
  1140. g_sbcThrashers[0].tickCount = nextTickCount;
  1141. }
  1142. DebugExitBOOL(SBCDDIsBitmapThrasher, rc);
  1143. return(rc);
  1144. }
  1145. //
  1146. //
  1147. // Name: SBCDDGetTickCount
  1148. //
  1149. // Purpose: Get a system tick count
  1150. //
  1151. // Returns: The number of centi-seconds since the system was started.
  1152. // This number will wrap after approximately 497 days!
  1153. //
  1154. // Params: None
  1155. //
  1156. //
  1157. DWORD SBCDDGetTickCount(void)
  1158. {
  1159. DWORD tickCount;
  1160. LONGLONG perfTickCount;
  1161. DebugEntry(SBCDDGetTickCount);
  1162. //
  1163. // Get the number of system ticks since the system was started.
  1164. //
  1165. EngQueryPerformanceCounter(&perfTickCount);
  1166. //
  1167. // Now convert this into a number of centi-seconds. g_sbcPerfFrequency
  1168. // contains the number of system ticks per second.
  1169. //
  1170. tickCount = (DWORD)((100 * perfTickCount) / g_sbcPerfFrequency);
  1171. DebugExitDWORD(SBCDDGetTickCount, tickCount);
  1172. return(tickCount);
  1173. }
  1174. //
  1175. // FUNCTION: SBCDDSetNewCapabilities
  1176. //
  1177. // DESCRIPTION:
  1178. //
  1179. // Set the new SBC related capabilities
  1180. //
  1181. // RETURNS:
  1182. //
  1183. // NONE
  1184. //
  1185. // PARAMETERS:
  1186. //
  1187. // pDataIn - pointer to the input buffer
  1188. //
  1189. //
  1190. void SBCDDSetNewCapabilities(LPSBC_NEW_CAPABILITIES pCapabilities)
  1191. {
  1192. DebugEntry(SBCSetNewCapabilities);
  1193. g_sbcSendingBPP = pCapabilities->sendingBpp;
  1194. memcpy(&g_asbcCacheInfo, pCapabilities->cacheInfo, sizeof(g_asbcCacheInfo));
  1195. DebugExitVOID(SBCSetNewCapabilities);
  1196. }
  1197.