Leaked source code of windows server 2003
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.

1379 lines
42 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. if(g_asbcWorkInfo[i].pShuntBuffer)
  571. {
  572. for (j = 0; j < g_asbcWorkInfo[i].pShuntBuffer->numEntries ; j++)
  573. {
  574. pTileData = SBCTilePtrFromIndex(g_asbcWorkInfo[i].pShuntBuffer, j);
  575. pTileData->inUse = FALSE;
  576. }
  577. }
  578. //
  579. // Reset the MRU counter for this shunt buffer
  580. //
  581. g_asbcWorkInfo[i].mruIndex = 0;
  582. }
  583. //
  584. // If we are a palette device (i.e. we are running at 8 bpp or less),
  585. // set the paletteChanged flag so we will send up a color table before
  586. // our next Mem(3)Blt. We do this because the color table order for
  587. // the current device palette may have been discarded during the OA
  588. // sync.
  589. //
  590. ppDev->paletteChanged = (ppDev->cBitsPerPel <= 8);
  591. DebugExitVOID(SBC_DDSyncUpdatesNow);
  592. }
  593. //
  594. //
  595. // SBC_DDOrderSpoiltNotification() - see sbc.h
  596. //
  597. //
  598. void SBC_DDOrderSpoiltNotification(LPINT_ORDER pOrder)
  599. {
  600. LPMEMBLT_ORDER pMemBltOrder = (LPMEMBLT_ORDER)&(pOrder->abOrderData);
  601. LPMEM3BLT_ORDER pMem3BltOrder = (LPMEM3BLT_ORDER)pMemBltOrder;
  602. UINT tileId;
  603. LPSBC_TILE_DATA pTileData;
  604. UINT tileType;
  605. UINT i;
  606. DebugEntry(SBC_DDOrderSpoiltNotification);
  607. //
  608. // pOrder has been removed from the order heap before being processed.
  609. // We have to free up the entry which it references in one of the shunt
  610. // buffers. First get the tile Id.
  611. //
  612. if (pMemBltOrder->type == ORD_MEMBLT_TYPE)
  613. {
  614. tileId = pMemBltOrder->cacheId;
  615. }
  616. else
  617. {
  618. tileId = pMem3BltOrder->cacheId;
  619. }
  620. TRACE_OUT(( "Order referencing tile %hx has been spoiled", tileId));
  621. //
  622. // Find out which of the shunt buffers the entry should be in based on
  623. // the tileId
  624. //
  625. tileType = SBC_TILE_TYPE(tileId);
  626. //
  627. // We implement the shunt buffers as circular FIFO queues, so we will
  628. // start looking from the last order which we marked as being in use,
  629. // and work BACKWARDS. This is because, in general, the entries after
  630. // the last one we accessed will not be in use (unless the whole shunt
  631. // buffer is in use).
  632. //
  633. // So, get the index of the last tile we accessed.
  634. //
  635. i = g_asbcWorkInfo[tileType].mruIndex;
  636. //
  637. // Loop through the circular buffer until we get a match, or have
  638. // circled back to the beginning.
  639. //
  640. // Note that this has been coded as a "do while" loop, rather than just
  641. // a "while" loop so that we don't miss mruIndex. mruIndex is set up
  642. // to point to the NEXT entry to be used, rather than the last entry to
  643. // be used, so decrementing i before doing any work first time round
  644. // the loop is actually what we want to do.
  645. //
  646. do
  647. {
  648. //
  649. // On to the next tile
  650. //
  651. i = (i == 0)
  652. ? g_asbcWorkInfo[tileType].pShuntBuffer->numEntries - 1
  653. : i - 1;
  654. pTileData = SBCTilePtrFromIndex(g_asbcWorkInfo[tileType].pShuntBuffer, i);
  655. if (pTileData->inUse && (pTileData->tileId == tileId))
  656. {
  657. //
  658. // We've got a match, so mark the tile as being free.
  659. //
  660. // We don't want to update the shunt buffer mruIndex - this
  661. // should remain indicating the next tile to be used when
  662. // adding an entry to the shunt buffer.
  663. //
  664. TRACE_OUT(( "Marked tile Id %hx at index %d as free",
  665. tileId,
  666. i));
  667. pTileData->inUse = FALSE;
  668. break;
  669. }
  670. }
  671. while (i != g_asbcWorkInfo[tileType].mruIndex);
  672. DebugExitVOID(SBC_DDOrderSpoiltNotification);
  673. }
  674. //
  675. //
  676. // SBC_DDMaybeQueueColorTable() - see sbc.h
  677. //
  678. //
  679. BOOL SBC_DDMaybeQueueColorTable(LPOSI_PDEV ppDev)
  680. {
  681. BOOL queuedOK = FALSE;
  682. int orderSize;
  683. LPINT_ORDER pOrder;
  684. LPINT_COLORTABLE_ORDER_1BPP pColorTableOrder;
  685. UINT numColors;
  686. UINT i;
  687. DebugEntry(SBC_DDMaybeQueueColorTable);
  688. //
  689. // If we're running at > 8 bpp, then we don't have a palette, so just
  690. // quit out.
  691. //
  692. if (ppDev->cBitsPerPel > 8)
  693. {
  694. queuedOK = TRUE;
  695. DC_QUIT;
  696. }
  697. //
  698. // Check the boolean in our PDEV to see if the palette has changed
  699. // since the last time we sent a color table order. Note that if we
  700. // have a non palette device, the boolean will never be set.
  701. //
  702. if (!ppDev->paletteChanged)
  703. {
  704. queuedOK = TRUE;
  705. DC_QUIT;
  706. }
  707. //
  708. // The palette has changed, so allocate order memory to queue a color
  709. // table order. The order size depends on the bpp of our device. Note
  710. // that the allocation can fail if the order buffer is full.
  711. //
  712. switch (ppDev->cBitsPerPel)
  713. {
  714. case 1:
  715. {
  716. orderSize = sizeof(INT_COLORTABLE_ORDER_1BPP);
  717. }
  718. break;
  719. case 4:
  720. {
  721. orderSize = sizeof(INT_COLORTABLE_ORDER_4BPP);
  722. }
  723. break;
  724. case 8:
  725. {
  726. orderSize = sizeof(INT_COLORTABLE_ORDER_8BPP);
  727. }
  728. break;
  729. default:
  730. {
  731. ERROR_OUT(("Invalid bpp (%d) for palette device", ppDev->cBitsPerPel));
  732. DC_QUIT;
  733. }
  734. break;
  735. }
  736. pOrder = OA_DDAllocOrderMem(orderSize, 0);
  737. if (pOrder == NULL)
  738. {
  739. TRACE_OUT(( "Failed to allocate %d bytes for order", orderSize));
  740. DC_QUIT;
  741. }
  742. TRACE_OUT(( "Allocate %d bytes for color table order", orderSize));
  743. //
  744. // We've successfully allocated the order, so fill in the details. We
  745. // mark the order as internal so that the Update Packager will spot it
  746. // up in the share core and prevent it being sent over the wire.
  747. //
  748. pOrder->OrderHeader.Common.fOrderFlags = OF_INTERNAL;
  749. pColorTableOrder = (LPINT_COLORTABLE_ORDER_1BPP)&(pOrder->abOrderData);
  750. pColorTableOrder->header.type = INTORD_COLORTABLE_TYPE;
  751. pColorTableOrder->header.bpp = (TSHR_UINT16)ppDev->cBitsPerPel;
  752. //
  753. // Unfortunately we can't just copy the palette from the PDEV into the
  754. // color table order because the PDEV has an array of PALETTEENTRY
  755. // structures which are RGBs whereas the order has an array of
  756. // TSHR_RGBQUADs which are BGRs...
  757. //
  758. numColors = COLORS_FOR_BPP(ppDev->cBitsPerPel);
  759. ASSERT(numColors);
  760. for (i = 0; i < numColors; i++)
  761. {
  762. pColorTableOrder->colorData[i].rgbRed = ppDev->pPal[i].peRed;
  763. pColorTableOrder->colorData[i].rgbGreen = ppDev->pPal[i].peGreen;
  764. pColorTableOrder->colorData[i].rgbBlue = ppDev->pPal[i].peBlue;
  765. }
  766. //
  767. // Add the order
  768. //
  769. OA_DDAddOrder(pOrder, NULL);
  770. TRACE_OUT(( "Added internal color table order, size %d", orderSize));
  771. //
  772. // Reset the flag which indicates that the palette needs to be sent
  773. //
  774. ppDev->paletteChanged = FALSE;
  775. //
  776. // Must be OK to get to here
  777. //
  778. queuedOK = TRUE;
  779. DC_EXIT_POINT:
  780. DebugExitBOOL(SBC_DDMaybeQueueColorTable, queuedOK);
  781. return(queuedOK);
  782. }
  783. //
  784. // SBCDDCreateShuntBuffers()
  785. //
  786. // Here's where we calc how many cache entries (tiles) we can support. This
  787. // depends on:
  788. // * The amount of shared memory we have
  789. // * The color depth of the driver
  790. //
  791. // There is an upper bound on the amount of memory we'll use, since this
  792. // maps to how much memory on remotes will be needed to store our sent
  793. // cache entries.
  794. //
  795. // The tiles are created in a fixed proportion (MP_RATIO_MTOL).
  796. //
  797. // We return TRUE for success if we can set up the caches and create the
  798. // objects necessary for a sent bitmap cache.
  799. //
  800. BOOL SBCDDCreateShuntBuffers
  801. (
  802. LPOSI_PDEV ppDev,
  803. LPBYTE psbcSharedMemory,
  804. DWORD sbcSharedMemorySize
  805. )
  806. {
  807. int i;
  808. UINT memPerBuffer[SBC_NUM_TILE_SIZES];
  809. UINT memPerTile[SBC_NUM_TILE_SIZES];
  810. UINT numTiles[SBC_NUM_TILE_SIZES];
  811. UINT memRequired;
  812. LPBYTE pBuffer = psbcSharedMemory;
  813. BOOL rc = FALSE;
  814. DebugEntry(SBCDDCreateShuntBuffers);
  815. //
  816. // We should already have a pointer to the shared memory we can use for
  817. // our shunt buffers, and the number of bytes available. What we have
  818. // to do is to partition this shared memory into SBC_NUM_TILE_SIZE
  819. // shunt buffers. i.e. one shunt buffer per tile size.
  820. //
  821. //
  822. // <--- buffer 0 ---><------------------ buffer 1 -------------------->
  823. //
  824. //��������������������������������������������������������������������Ŀ
  825. //� � : : : : � � : : : : �
  826. //� � : : : : � � tile : tile : tile : tile : tile �
  827. //� � : : : : � � : : : : �
  828. //����������������������������������������������������������������������
  829. //^ ^ ^
  830. //� � �
  831. //� ���� header[0] ���� header[1]
  832. //�
  833. //��� psbcSharedMemory
  834. //
  835. //
  836. // We try to use the number of entries given in the pEntries array, but
  837. // if we do not have enough shared memory for this, we reduce the
  838. // number of entries in each shunt buffer, preserving the ratio between
  839. // the number of entries in each of the shunt buffers.
  840. //
  841. //
  842. // First make sure that we have some shared memory
  843. //
  844. if (sbcSharedMemorySize == 0)
  845. {
  846. ERROR_OUT(( "No SBC shared memory !"));
  847. DC_QUIT;
  848. }
  849. // Max out at MP_MEMORY_MAX bytes
  850. sbcSharedMemorySize = min(sbcSharedMemorySize, MP_MEMORY_MAX);
  851. //
  852. // Do we have enough shared memory to satisfy the requested number of
  853. // entries in each shunt buffer ?
  854. //
  855. memRequired = 0;
  856. for (i = 0; i < SBC_NUM_TILE_SIZES; i++)
  857. {
  858. memPerTile[i] = SBC_BYTES_PER_TILE(g_asbcWorkInfo[i].tileWidth,
  859. g_asbcWorkInfo[i].tileHeight,
  860. ppDev->cBitsPerPel);
  861. // We use the same amount of memory for each tile size.
  862. numTiles[i] = ((sbcSharedMemorySize / SBC_NUM_TILE_SIZES) -
  863. (sizeof(SBC_SHUNT_BUFFER) - sizeof(SBC_TILE_DATA))) /
  864. memPerTile[i];
  865. TRACE_OUT(("Can fit %d tiles of memory size %d in tile cache %d",
  866. numTiles[i], memPerTile[i], i));
  867. memPerBuffer[i] = (numTiles[i] * memPerTile[i]) +
  868. (sizeof(SBC_SHUNT_BUFFER) - sizeof(SBC_TILE_DATA));
  869. memRequired += memPerBuffer[i];
  870. }
  871. TRACE_OUT(( "%d bytes required for request, %d bytes available",
  872. memRequired,
  873. sbcSharedMemorySize));
  874. ASSERT(memRequired <= sbcSharedMemorySize);
  875. // Zero out rest of amount we're going to use
  876. RtlFillMemory(psbcSharedMemory, memRequired, 0);
  877. //
  878. // OK, we've got the
  879. // - the bytes per tile in memPerTile[i]
  880. // - number of entries per shunt buffer in numTiles[i]
  881. // - the total size of each shunt buffer in memPerBuffer[i].
  882. //
  883. // Do the partitioning.
  884. //
  885. for (i = 0; i < SBC_NUM_TILE_SIZES ; i++)
  886. {
  887. g_asbcWorkInfo[i].pShuntBuffer = (LPSBC_SHUNT_BUFFER)pBuffer;
  888. g_asbcWorkInfo[i].pShuntBuffer->numEntries = numTiles[i];
  889. g_asbcWorkInfo[i].pShuntBuffer->numBytes = memPerTile[i]
  890. - sizeof(SBC_TILE_DATA);
  891. g_asbcWorkInfo[i].pShuntBuffer->structureSize = memPerTile[i];
  892. //
  893. // Move the buffer pointer past the memory we are using for this
  894. // shunt buffer.
  895. //
  896. pBuffer += memPerBuffer[i];
  897. TRACE_OUT(( "Shunt buffer %d at %#.8lx: tile bytes %u, "
  898. "structure size %u, num entries %u",
  899. i,
  900. g_asbcWorkInfo[i].pShuntBuffer,
  901. g_asbcWorkInfo[i].pShuntBuffer->numBytes,
  902. g_asbcWorkInfo[i].pShuntBuffer->structureSize,
  903. g_asbcWorkInfo[i].pShuntBuffer->numEntries));
  904. //
  905. // Fill in the mruIndex for this shunt buffer
  906. //
  907. g_asbcWorkInfo[i].mruIndex = 0;
  908. }
  909. //
  910. // Initialize the global variables associated with the shunt buffers
  911. //
  912. g_sbcNextTileId = 0;
  913. //
  914. // Must be OK to get to here
  915. //
  916. rc = TRUE;
  917. DC_EXIT_POINT:
  918. DebugExitBOOL(SBCDDCreateShuntBuffers, rc);
  919. return(rc);
  920. }
  921. //
  922. // Name: SBCGetNextFreeTile
  923. //
  924. // Purpose: Return the next free tile of the correct size from one of the
  925. // shunt buffers.
  926. //
  927. // Returns: TRUE if a tile is returned, FALSE otherwise
  928. //
  929. // Params: IN workTileSize - The tile size. One of
  930. // SBC_MEDIUM_TILE
  931. // SBC_LARGE_TILE
  932. // OUT ppTileData - A pointer to the tile.
  933. //
  934. // Operation: The tileId field of the tile is filled in on return from
  935. // this function.
  936. //
  937. //
  938. BOOL SBCDDGetNextFreeTile(int tileSize, LPSBC_TILE_DATA FAR * ppTileData)
  939. {
  940. BOOL foundFreeTile = FALSE;
  941. LPSBC_TILE_DATA pTileData;
  942. DebugEntry(SBCDDGetNextFreeTile);
  943. //
  944. // Make sure that we have a valid tile size
  945. //
  946. if (tileSize >= SBC_NUM_TILE_SIZES)
  947. {
  948. ERROR_OUT(( "Invalid tile size %d", tileSize));
  949. DC_QUIT;
  950. }
  951. //
  952. // Get a pointer to the next entry to be used in the shunt buffer
  953. // containing tiles of the given size.
  954. //
  955. pTileData = SBCTilePtrFromIndex(g_asbcWorkInfo[tileSize].pShuntBuffer,
  956. g_asbcWorkInfo[tileSize].mruIndex);
  957. //
  958. // If the entry is still in use (the share core has not yet processed
  959. // the order which references this tile) we have to quit - the shunt
  960. // buffer is full.
  961. //
  962. if (pTileData->inUse)
  963. {
  964. TRACE_OUT(( "Target entry (%d, %d) is still in use",
  965. tileSize,
  966. g_asbcWorkInfo[tileSize].mruIndex));
  967. DC_QUIT;
  968. }
  969. //
  970. // The entry is not in use - we can re-use it. Fill in the Id field,
  971. // and the pointer to the entry which we return to the caller.
  972. //
  973. // We always set the top bit of the tile Id for large tiles, and clear
  974. // it for small tiles.
  975. //
  976. *ppTileData = pTileData;
  977. pTileData->tileId = g_sbcNextTileId;
  978. if (tileSize == SBC_MEDIUM_TILE_INDEX)
  979. {
  980. pTileData->tileId &= ~0x8000;
  981. }
  982. else
  983. {
  984. pTileData->tileId |= 0x8000;
  985. }
  986. TRACE_OUT(( "Returning entry (%d, %d), Id %hx",
  987. tileSize,
  988. g_asbcWorkInfo[tileSize].mruIndex,
  989. pTileData->tileId));
  990. //
  991. // Update the index of the next free entry in this shunt buffer, and
  992. // also the Id which we should assign next time. Remember to wrap the
  993. // shunt buffer index to the number of entries in the shunt buffer.
  994. //
  995. g_asbcWorkInfo[tileSize].mruIndex = (g_asbcWorkInfo[tileSize].mruIndex + 1) %
  996. g_asbcWorkInfo[tileSize].pShuntBuffer->numEntries;
  997. g_sbcNextTileId++;
  998. g_sbcNextTileId &= ~0x8000;
  999. //
  1000. // Completed successfully !
  1001. //
  1002. foundFreeTile = TRUE;
  1003. DC_EXIT_POINT:
  1004. DebugExitBOOL(SBCDDGetNextFreeTile, foundFreeTile);
  1005. return(foundFreeTile);
  1006. }
  1007. //
  1008. //
  1009. // Name: SBCDDIsBitmapThrasher
  1010. //
  1011. // Purpose: Check to see if the given bitmap (surface object) is one
  1012. // which would cause cache thrashing.
  1013. //
  1014. // Returns: TRUE if the bitmap is a thrasher, FALSE otherwise.
  1015. //
  1016. // Params: IN pSurfObj - Pointer to the bitmap
  1017. //
  1018. //
  1019. BOOL SBCDDIsBitmapThrasher(SURFOBJ * pSurfObj)
  1020. {
  1021. UINT i;
  1022. BOOL rc = FALSE;
  1023. BOOL bitmapInList = FALSE;
  1024. BOOL updateEntry = FALSE;
  1025. UINT updateIndex;
  1026. UINT nextTickCount;
  1027. UINT evictIndex;
  1028. UINT evictTickCount;
  1029. DebugEntry(SBCDDIsBitmapThrasher);
  1030. //
  1031. // Here's an overview of how our bitmap cache thrash detection works...
  1032. //
  1033. // We hold an array of information about the last SBC_NUM_THRASHERS
  1034. // bitmaps which we have tried to cache. This information is
  1035. // - A value to identify the bitmap. This is the hsurf field from the
  1036. // bitmap surface object, and is different for every bitmap.
  1037. // - A value to identify the "version" of the bitmap. This is the
  1038. // iUniq field from the bitmap surface object, and is updated by GDI
  1039. // each time the bitmap is drawn to.
  1040. // - A timestamp for the last time which we saw iUniq change for this
  1041. // bitmap (or when we added the bitmap to the array).
  1042. //
  1043. // Each time this function is called, we scan this array looking for an
  1044. // entry for the bitmap.
  1045. //
  1046. // If we find an entry, we check whether the bitmap has changed (has
  1047. // the iUniq field changed). If it has not changed, the bitmap is not
  1048. // a thrasher. If the bitmap has changed, we check the interval from
  1049. // the timestamp value to the current time. If the interval is less
  1050. // than the SBC_THRASH_INTERVAL, the bitmap has changed too quickly, so
  1051. // it is a thrasher. If the interval is OK, the bitmap is not a
  1052. // thrasher. In either case, we update the stored iUniq field and the
  1053. // timestamp to record the time / version at which we spotted that the
  1054. // bitmap changed.
  1055. //
  1056. // If we do not find an entry for the bitmap, we add an entry for it.
  1057. // If the array is fully populated, we evict the entry with the oldest
  1058. // timestamp, and replace it with the new entry.
  1059. //
  1060. //
  1061. // Scan the thrasher list looking for a match
  1062. //
  1063. for (i=0 ; i<SBC_NUM_THRASHERS ; i++)
  1064. {
  1065. //
  1066. // If we find a match then we are only worried if it has been
  1067. // modified since the last time we read it.
  1068. //
  1069. if (g_sbcThrashers[i].hsurf == pSurfObj->hsurf)
  1070. {
  1071. bitmapInList = TRUE;
  1072. if (g_sbcThrashers[i].iUniq != pSurfObj->iUniq)
  1073. {
  1074. TRACE_OUT(( "Matching surface %x, index %u,"
  1075. "tick count %u has been modified",
  1076. pSurfObj->hsurf,
  1077. i,
  1078. g_sbcThrashers[i].tickCount));
  1079. updateEntry = TRUE;
  1080. updateIndex = i;
  1081. //
  1082. // Now we need to determine if this is a thrasher. It is a
  1083. // thrasher if the time we last read it is less than our
  1084. // thrash interval. (We only update the time when we read
  1085. // a modified bitmap)
  1086. //
  1087. nextTickCount = SBCDDGetTickCount();
  1088. if ((nextTickCount - g_sbcThrashers[i].tickCount) <
  1089. SBC_THRASH_INTERVAL)
  1090. {
  1091. TRACE_OUT((
  1092. "Rejected cache attempt of thrashy bitmap %x",
  1093. pSurfObj->hsurf));
  1094. rc = TRUE;
  1095. }
  1096. g_sbcThrashers[i].tickCount = nextTickCount;
  1097. g_sbcThrashers[i].iUniq = pSurfObj->iUniq;
  1098. }
  1099. //
  1100. // We've found a match - we can break out of the loop
  1101. //
  1102. break;
  1103. }
  1104. }
  1105. if (!bitmapInList)
  1106. {
  1107. //
  1108. // The bitmap isn't already in the thrasher list, so add it now.
  1109. // Find the entry with the smallest (earliest) tick count - we will
  1110. // evict this entry from the array to make room for the new entry.
  1111. //
  1112. evictIndex = 0;
  1113. evictTickCount = 0xffffffff;
  1114. for (i=0 ; i<SBC_NUM_THRASHERS ; i++)
  1115. {
  1116. if (evictTickCount > g_sbcThrashers[i].tickCount)
  1117. {
  1118. evictTickCount = g_sbcThrashers[i].tickCount;
  1119. evictIndex = i;
  1120. }
  1121. }
  1122. TRACE_OUT(( "Evicting entry %d, surface %x",
  1123. evictIndex,
  1124. g_sbcThrashers[i].hsurf));
  1125. nextTickCount = SBCDDGetTickCount();
  1126. TRACE_OUT(( "Adding surface %x to thrash list, tick %d",
  1127. pSurfObj->hsurf,
  1128. nextTickCount));
  1129. updateEntry = TRUE;
  1130. updateIndex = evictIndex;
  1131. }
  1132. if (updateEntry)
  1133. {
  1134. //
  1135. // We have to update the entry at index updateIndex. We optimise
  1136. // things slightly by always putting the most recent bitmap in
  1137. // position 0 of the array, so copy entry 0 to the eviction index,
  1138. // and put the new entry in position 0.
  1139. //
  1140. g_sbcThrashers[updateIndex] = g_sbcThrashers[0];
  1141. g_sbcThrashers[0].hsurf = pSurfObj->hsurf;
  1142. g_sbcThrashers[0].iUniq = pSurfObj->iUniq;
  1143. g_sbcThrashers[0].tickCount = nextTickCount;
  1144. }
  1145. DebugExitBOOL(SBCDDIsBitmapThrasher, rc);
  1146. return(rc);
  1147. }
  1148. //
  1149. //
  1150. // Name: SBCDDGetTickCount
  1151. //
  1152. // Purpose: Get a system tick count
  1153. //
  1154. // Returns: The number of centi-seconds since the system was started.
  1155. // This number will wrap after approximately 497 days!
  1156. //
  1157. // Params: None
  1158. //
  1159. //
  1160. DWORD SBCDDGetTickCount(void)
  1161. {
  1162. DWORD tickCount;
  1163. LONGLONG perfTickCount;
  1164. DebugEntry(SBCDDGetTickCount);
  1165. //
  1166. // Get the number of system ticks since the system was started.
  1167. //
  1168. EngQueryPerformanceCounter(&perfTickCount);
  1169. //
  1170. // Now convert this into a number of centi-seconds. g_sbcPerfFrequency
  1171. // contains the number of system ticks per second.
  1172. //
  1173. tickCount = (DWORD)((100 * perfTickCount) / g_sbcPerfFrequency);
  1174. DebugExitDWORD(SBCDDGetTickCount, tickCount);
  1175. return(tickCount);
  1176. }
  1177. //
  1178. // FUNCTION: SBCDDSetNewCapabilities
  1179. //
  1180. // DESCRIPTION:
  1181. //
  1182. // Set the new SBC related capabilities
  1183. //
  1184. // RETURNS:
  1185. //
  1186. // NONE
  1187. //
  1188. // PARAMETERS:
  1189. //
  1190. // pDataIn - pointer to the input buffer
  1191. //
  1192. //
  1193. void SBCDDSetNewCapabilities(LPSBC_NEW_CAPABILITIES pCapabilities)
  1194. {
  1195. DebugEntry(SBCSetNewCapabilities);
  1196. g_sbcSendingBPP = pCapabilities->sendingBpp;
  1197. memcpy(&g_asbcCacheInfo, pCapabilities->cacheInfo, sizeof(g_asbcCacheInfo));
  1198. DebugExitVOID(SBCSetNewCapabilities);
  1199. }
  1200.