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.

1781 lines
57 KiB

  1. //
  2. // OA.C
  3. // Order Accumulator
  4. //
  5. // Copyright(c) Microsoft 1997-
  6. //
  7. #include <as16.h>
  8. #ifdef DEBUG
  9. //
  10. // We use this to make sure our order heap list is committed in the order
  11. // the items were allocated in.
  12. //
  13. // NOTE:
  14. // Can't make this CODESEG. USER in Win95 has a bug, the validation layer
  15. // for CopyRect() got the parameters reversed, and it won't continue
  16. // if the SOURCE (it meant the DEST) rect isn't writeable.
  17. //
  18. static RECT g_oaEmptyRect = { 0x7FFF, 0x7FFF, 0, 0 };
  19. #endif // DEBUG
  20. //
  21. // OA_DDProcessRequest()
  22. // Handles OA escapes
  23. //
  24. BOOL OA_DDProcessRequest
  25. (
  26. UINT fnEscape,
  27. LPOSI_ESCAPE_HEADER pRequest,
  28. DWORD cbRequest
  29. )
  30. {
  31. BOOL rc = TRUE;
  32. DebugEntry(OA_DDProcessRequest);
  33. switch (fnEscape)
  34. {
  35. case OA_ESC_FLOW_CONTROL:
  36. {
  37. ASSERT(cbRequest == sizeof(OA_FLOW_CONTROL));
  38. // Save new throughput measurement
  39. g_oaFlow = ((LPOA_FLOW_CONTROL)pRequest)->oaFlow;
  40. }
  41. break;
  42. default:
  43. {
  44. ERROR_OUT(("Unrecognized OA escape"));
  45. rc = FALSE;
  46. }
  47. break;
  48. }
  49. DebugExitBOOL(OA_DDProcessRequest, rc);
  50. return(rc);
  51. }
  52. //
  53. //
  54. // OA_DDAddOrder(..)
  55. //
  56. // Adds an order to the queue for transmission.
  57. //
  58. // If the new order is completetly covered by the current SDA then
  59. // it is spoilt.
  60. //
  61. // If the order is opaque and overlaps earlier orders it may clip
  62. // or spoil them.
  63. //
  64. // Called by the GDI interception code.
  65. //
  66. //
  67. void OA_DDAddOrder(LPINT_ORDER pNewOrder, void FAR * pExtraInfo)
  68. {
  69. RECT SDARects[BA_NUM_RECTS*2];
  70. UINT cBounds;
  71. UINT spoilingBounds;
  72. UINT totalBounds;
  73. UINT i;
  74. RECT SrcRect;
  75. RECT tmpRect;
  76. BOOL gotBounds = FALSE;
  77. int dx;
  78. int dy;
  79. RECT IntersectedSrcRect;
  80. RECT InvalidDstRect;
  81. LPINT_ORDER pTmpOrder;
  82. LPEXTTEXTOUT_ORDER pExtTextOut;
  83. LPOA_FAST_DATA lpoaFast;
  84. LPOA_SHARED_DATA lpoaShared;
  85. DebugEntry(OA_DDAddOrder);
  86. lpoaShared = OA_SHM_START_WRITING;
  87. lpoaFast = OA_FST_START_WRITING;
  88. //
  89. // Accumulate order accumulation rate. We are interested in how
  90. // quickly orders are being added to the buffer, so that we can tell
  91. // DCS scheduling whether frequent sends are advisable
  92. //
  93. SHM_CheckPointer(lpoaFast);
  94. lpoaFast->ordersAccumulated++;
  95. //
  96. // If the order is a private one, then we just add it to the Order
  97. // List and return immediately.
  98. //
  99. // Private Orders are used to send bitmap cache information (bitmap
  100. // bits and color tables).
  101. //
  102. // Private Orders never spoil any others and must never be spoilt.
  103. //
  104. if (pNewOrder->OrderHeader.Common.fOrderFlags & OF_PRIVATE)
  105. {
  106. TRACE_OUT(("Add private order (%lx)", pNewOrder));
  107. OADDAppendToOrderList(lpoaShared, pNewOrder);
  108. DC_QUIT;
  109. }
  110. //
  111. // If this order is spoilable and its is completely enclosed by the
  112. // current screen data area, we can spoil it. Unless...
  113. //
  114. // PM - Performance
  115. //
  116. // We have observed in usability testing that clipping orders always
  117. // degrades the end-user's perceived performance. This is because the
  118. // orders flow much faster than the screendata and tend to relate to
  119. // text, which is what the user really wants to see. For example, text
  120. // overwriting a bitmap will be delayed because we want to send the
  121. // bitmap as screendata.
  122. //
  123. // Also, word documents tend to contain sections of screendata due to
  124. // mismatched fonts, intelliquotes, spelling annotation, current line
  125. // memblit. Nothing we can do about this, but if we page down two or
  126. // three times, or down and up again we get an accumulation of the
  127. // screendata on all the pages spoiling the orders and the end result
  128. // is that we have to wait longer than we would if we had not spoiled
  129. // the orders.
  130. //
  131. // So, what we can do instead is leave the text orders in and overwrite
  132. // them with screendata when it gets through. However, to make this
  133. // really effective what we also do is convert any transparent text
  134. // (as WEB browsers tend to use) into opaque text on a default
  135. // background.
  136. //
  137. //
  138. if ((pNewOrder->OrderHeader.Common.fOrderFlags & OF_SPOILABLE) != 0)
  139. {
  140. //
  141. // Get the driver's current bounds.
  142. //
  143. BA_CopyBounds(SDARects, &cBounds, FALSE);
  144. gotBounds = TRUE;
  145. for (i = 0; i < cBounds; i++)
  146. {
  147. if ( OADDCompleteOverlapRect(&pNewOrder->OrderHeader.Common.rcsDst,
  148. &(SDARects[i])) )
  149. {
  150. //
  151. // The destination of the order is completely covered by
  152. // the SDA. Check for a text order.
  153. //
  154. pExtTextOut = (LPEXTTEXTOUT_ORDER)pNewOrder->abOrderData;
  155. if (pExtTextOut->type == ORD_EXTTEXTOUT_TYPE)
  156. {
  157. //
  158. // The order is going to be completely overwritten so
  159. // we can play around with it all we like.
  160. // Just make it opaque so the user can read it while
  161. // waiting for the screendata to follow on.
  162. //
  163. pExtTextOut->fuOptions |= ETO_OPAQUE;
  164. //
  165. // pExtTextOut->rectangle is a TSHR_RECT32
  166. //
  167. pExtTextOut->rectangle.left = pNewOrder->OrderHeader.Common.rcsDst.left;
  168. pExtTextOut->rectangle.top = pNewOrder->OrderHeader.Common.rcsDst.top;
  169. pExtTextOut->rectangle.right = pNewOrder->OrderHeader.Common.rcsDst.right;
  170. pExtTextOut->rectangle.bottom = pNewOrder->OrderHeader.Common.rcsDst.bottom;
  171. TRACE_OUT(("Converted text order to opaque"));
  172. break;
  173. }
  174. else
  175. {
  176. TRACE_OUT(("Spoiling order %08lx by SDA", pNewOrder));
  177. OA_DDFreeOrderMem(pNewOrder);
  178. DC_QUIT;
  179. }
  180. }
  181. }
  182. }
  183. //
  184. // Pass the order onto the Bitmap Cache Controller to try to cache the
  185. // src bitmap.
  186. //
  187. if (ORDER_IS_MEMBLT(pNewOrder) || ORDER_IS_MEM3BLT(pNewOrder))
  188. {
  189. ERROR_OUT(("MEMBLT orders not supported!"));
  190. }
  191. if (ORDER_IS_SCRBLT(pNewOrder))
  192. {
  193. //
  194. //
  195. // Handle Screen to Screen (SS) bitblts.
  196. //
  197. // The basic plan
  198. // --------------
  199. //
  200. // If the source of a screen to screen blt intersects with the
  201. // current SDA then we have to do some additional work because all
  202. // orders are always executed before the SDA is copied. This means
  203. // that the data within the SDA will not be available at the time
  204. // we want to do the SS blt.
  205. //
  206. // In this situation we adjust the SS blt to remove all overlap
  207. // from the src rectangle. The destination rectangle is adjusted
  208. // accordingly. The area removed from the destination rectangle is
  209. // added into the SDA.
  210. //
  211. //
  212. TRACE_OUT(("Handle SS blt(%lx)", pNewOrder));
  213. //
  214. // Make the order non-spoilable because we don't want the adding
  215. // of screen data to delete the order.
  216. //
  217. pNewOrder->OrderHeader.Common.fOrderFlags &= ~OF_SPOILABLE;
  218. //
  219. // Calculate the src rect.
  220. //
  221. SrcRect.left = ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nXSrc;
  222. SrcRect.right = SrcRect.left +
  223. ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nWidth - 1;
  224. SrcRect.top = ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nYSrc;
  225. SrcRect.bottom = SrcRect.top +
  226. ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nHeight - 1;
  227. //
  228. //
  229. // ORIGINAL SCRBLT SCHEME
  230. // ----------------------
  231. //
  232. // If the source rectangle intersects the current Screen Data Area
  233. // (SDA) then the src rectangle is modified so that no there is no
  234. // intersection with the SDA, and the dst rectangle adjusted
  235. // accordingly (this is the theory - in practice the operation
  236. // remains the same and we just adjust the dst clip rectangle).
  237. // The destination area that is removed is added into the SDA.
  238. //
  239. // The code works, but can result in more screen data being sent
  240. // than is required.
  241. //
  242. // e.g.
  243. //
  244. // Operation:
  245. //
  246. // SSSSSS DDDDDD
  247. // SSSSSS -> DDDDDD
  248. // SSSSSS DDDDDD
  249. // SxSSSS DDDDDD
  250. //
  251. // S - src rect
  252. // D - dst rect
  253. // x - SDA overlap
  254. //
  255. // The bottom edge of the blt is trimmed off, and the corresponding
  256. // destination area added into the SDA.
  257. //
  258. // SSSSSS DDDDDD
  259. // SSSSSS -> DDDDDD
  260. // SSSSSS DDDDDD
  261. // xxxxxx
  262. //
  263. //
  264. //
  265. // NEW SCRBLT SCHEME
  266. // ------------------
  267. //
  268. // The new scheme does not modify the blt rectangles, and just
  269. // maps the SDA overlap to the destination rect and adds that
  270. // area back into the SDA.
  271. //
  272. // e.g. (as above)
  273. //
  274. // Operation:
  275. //
  276. // SSSSSS DDDDDD
  277. // SSSSSS -> DDDDDD
  278. // SSSSSS DDDDDD
  279. // SxSSSS DDDDDD
  280. //
  281. // S - src rect
  282. // D - dst rect
  283. // x - SDA overlap
  284. //
  285. // The blt operation remains the same, but the overlap area is
  286. // mapped to the destination rectangle and added into the SDA.
  287. //
  288. // SSSSSS DDDDDD
  289. // SSSSSS -> DDDDDD
  290. // SSSSSS DDDDDD
  291. // SxSSSS DxDDDD
  292. //
  293. //
  294. // This scheme results in a smaller SDA area. However, this scheme
  295. // does blt potentially invalid data to the destination - which
  296. // may briefly be visible at the remote machine (because orders
  297. // are replayed before Screen Data). This has not (yet) proved to
  298. // be a problem.
  299. //
  300. // The main benefit of the new scheme is when scrolling an area
  301. // that includes a small SDA.
  302. //
  303. // new old
  304. // scheme scheme
  305. //
  306. // AAAAAAAA AAAAAAAA AAAAAAAA
  307. // AAAAAAAA AAAxAAAA xxxxxxxx
  308. // AAAAAAAA scroll up 3 times -> AAAxAAAA xxxxxxxx
  309. // AAAAAAAA AAAxAAAA xxxxxxxx
  310. // AAAxAAAA AAAxAAAA xxxxxxxx
  311. //
  312. //
  313. //
  314. if (!gotBounds)
  315. {
  316. //
  317. // Get the driver's current bounds.
  318. //
  319. BA_CopyBounds(SDARects, &cBounds, FALSE);
  320. }
  321. //
  322. // Now get any bounds which the share core is currently processing.
  323. // We have to include these bounds when we are doing the above
  324. // processing to avoid a situation where the core grabs the screen
  325. // data from the source of a ScrBlt after the source has been
  326. // updated by another order.
  327. //
  328. // e.g. If there is no driver SDA, but the core is processing the
  329. // area marked 'c'...
  330. //
  331. // If we ignore the core SDA, we queue a ScrBlt order which does
  332. // the following.
  333. //
  334. // SSSSSS DDDDDD
  335. // SccccS -> DDDDDD
  336. // SccccS DDDDDD
  337. // SSSSSS DDDDDD
  338. //
  339. // However, if another order (marked 'N') is accumulated before
  340. // the core grabs the SDA, we end up with the shadow doing the
  341. // following
  342. //
  343. // SSSSSS DDDDDD
  344. // ScNNcS -> DDNNDD
  345. // ScNNcS DDNNDD
  346. // SSSSSS DDDDDD
  347. //
  348. // i.e. the new order gets copied to the destination of the ScrBlt.
  349. // So, the ScrBlt order must be processed as
  350. //
  351. // SSSSSS DDDDDD
  352. // SccccS -> DxxxxD
  353. // SccccS DxxxxD
  354. // SSSSSS DDDDDD
  355. //
  356. //
  357. BA_QuerySpoilingBounds(&SDARects[cBounds], &spoilingBounds);
  358. totalBounds = cBounds + spoilingBounds;
  359. //
  360. //
  361. // This is the new SCRBLT handler.
  362. //
  363. //
  364. for (i = 0; i < totalBounds ; i++)
  365. {
  366. if ( (SrcRect.left >= SDARects[i].left) &&
  367. (SrcRect.right <= SDARects[i].right) &&
  368. (SrcRect.top >= SDARects[i].top) &&
  369. (SrcRect.bottom <= SDARects[i].bottom) )
  370. {
  371. //
  372. // The src of the SS blt is completely within the SDA. We
  373. // must add in the whole destination rectangle into the SDA
  374. // and spoil the SS blt.
  375. //
  376. TRACE_OUT(("SS blt src within SDA - spoil it"));
  377. RECT_FROM_TSHR_RECT16(&tmpRect,
  378. pNewOrder->OrderHeader.Common.rcsDst);
  379. OA_DDFreeOrderMem(pNewOrder);
  380. BA_AddScreenData(&tmpRect);
  381. DC_QUIT;
  382. }
  383. //
  384. // Intersect the src rect with the SDA rect.
  385. //
  386. IntersectedSrcRect.left = max( SrcRect.left,
  387. SDARects[i].left );
  388. IntersectedSrcRect.right = min( SrcRect.right,
  389. SDARects[i].right );
  390. IntersectedSrcRect.top = max( SrcRect.top,
  391. SDARects[i].top );
  392. IntersectedSrcRect.bottom = min( SrcRect.bottom,
  393. SDARects[i].bottom );
  394. dx = ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nLeftRect -
  395. ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nXSrc;
  396. dy = ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nTopRect -
  397. ((LPSCRBLT_ORDER)&pNewOrder->abOrderData)->nYSrc;
  398. InvalidDstRect.left = IntersectedSrcRect.left + dx;
  399. InvalidDstRect.right = IntersectedSrcRect.right + dx;
  400. InvalidDstRect.top = IntersectedSrcRect.top + dy;
  401. InvalidDstRect.bottom = IntersectedSrcRect.bottom + dy;
  402. //
  403. // Intersect the invalid destination rectangle with the
  404. // destination clip rectangle.
  405. //
  406. InvalidDstRect.left = max(
  407. InvalidDstRect.left,
  408. pNewOrder->OrderHeader.Common.rcsDst.left );
  409. InvalidDstRect.right = min(
  410. InvalidDstRect.right,
  411. pNewOrder->OrderHeader.Common.rcsDst.right );
  412. InvalidDstRect.top = max(
  413. InvalidDstRect.top,
  414. pNewOrder->OrderHeader.Common.rcsDst.top );
  415. InvalidDstRect.bottom = min(
  416. InvalidDstRect.bottom,
  417. pNewOrder->OrderHeader.Common.rcsDst.bottom );
  418. if ( (InvalidDstRect.left <= InvalidDstRect.right) &&
  419. (InvalidDstRect.top <= InvalidDstRect.bottom) )
  420. {
  421. //
  422. // Add the invalid area into the SDA.
  423. //
  424. TRACE_OUT(("Sending SDA {%d, %d, %d, %d}", InvalidDstRect.left,
  425. InvalidDstRect.top, InvalidDstRect.right, InvalidDstRect.bottom));
  426. BA_AddScreenData(&InvalidDstRect);
  427. }
  428. } // for (i = 0; i < totalBounds ; i++)
  429. //
  430. // Make the order spoilable again (this assumes that all SS blts
  431. // are spoilable.
  432. //
  433. pNewOrder->OrderHeader.Common.fOrderFlags |= OF_SPOILABLE;
  434. } // if (ORDER_IS_SCRBLT(pNewOrder))
  435. else if ((pNewOrder->OrderHeader.Common.fOrderFlags & OF_DESTROP) != 0)
  436. {
  437. //
  438. // This is the case where the output of the order depends on the
  439. // existing contents of the target area (e.g. an invert).
  440. //
  441. // What we have to do here is to add any parts of the destination
  442. // of this order which intersect the SDA which the share core is
  443. // processing to the driver SDA. The reason for this is the same
  444. // as the SCRBLT case - the share core may grab the data from the
  445. // screen after we have applied this order (e.g. after we have
  446. // inverted an area of the screen), then send the order as well
  447. // (re-inverting the area of the screen).
  448. //
  449. // Note that we only have to worry about the SDA which the share
  450. // core is processing - we can ignore the driver's SDA.
  451. //
  452. TRACE_OUT(("Handle dest ROP (%#.8lx)", pNewOrder));
  453. BA_QuerySpoilingBounds(SDARects, &spoilingBounds);
  454. for (i = 0; i < spoilingBounds ; i++)
  455. {
  456. //
  457. // Intersect the dest rect with the share core SDA rect.
  458. //
  459. InvalidDstRect.left = max(
  460. SDARects[i].left,
  461. pNewOrder->OrderHeader.Common.rcsDst.left );
  462. InvalidDstRect.right = min(
  463. SDARects[i].right,
  464. pNewOrder->OrderHeader.Common.rcsDst.right );
  465. InvalidDstRect.top = max(
  466. SDARects[i].top,
  467. pNewOrder->OrderHeader.Common.rcsDst.top );
  468. InvalidDstRect.bottom = min(
  469. SDARects[i].bottom,
  470. pNewOrder->OrderHeader.Common.rcsDst.bottom );
  471. if ( (InvalidDstRect.left <= InvalidDstRect.right) &&
  472. (InvalidDstRect.top <= InvalidDstRect.bottom) )
  473. {
  474. //
  475. // Add the invalid area into the SDA.
  476. //
  477. TRACE_OUT(("Sending SDA {%d, %d, %d, %d}",
  478. InvalidDstRect.left,
  479. InvalidDstRect.top,
  480. InvalidDstRect.right,
  481. InvalidDstRect.bottom));
  482. BA_AddScreenData(&InvalidDstRect);
  483. }
  484. }
  485. }
  486. //
  487. // Add the new order to the end of the Order List.
  488. //
  489. OADDAppendToOrderList(lpoaShared, pNewOrder);
  490. TRACE_OUT(("Append order(%lx) to list", pNewOrder));
  491. //
  492. // Now see if this order spoils any existing orders
  493. //
  494. if (pNewOrder->OrderHeader.Common.fOrderFlags & OF_SPOILER)
  495. {
  496. //
  497. // Its a spoiler, so try to spoil with it.
  498. //
  499. // We have to pass in the bounding rectangle of the order, and the
  500. // first order to try to spoil to OADDSpoilFromOrder. The first
  501. // order to try to spoil is the one before the new order.
  502. //
  503. RECT_FROM_TSHR_RECT16(&tmpRect,
  504. pNewOrder->OrderHeader.Common.rcsDst);
  505. pTmpOrder = COM_BasedListPrev(&lpoaShared->orderListHead, pNewOrder,
  506. FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  507. OADDSpoilFromOrder(lpoaShared, pTmpOrder, &tmpRect);
  508. }
  509. //
  510. // This is where the Win95 product would call DCS_TriggerEarlyTimer.
  511. //
  512. DC_EXIT_POINT:
  513. OA_FST_STOP_WRITING;
  514. OA_SHM_STOP_WRITING;
  515. DebugExitVOID(OA_DDAddOrder);
  516. }
  517. //
  518. //
  519. // FUNCTION: OA_DDAllocOrderMem
  520. //
  521. // DESCRIPTION:
  522. //
  523. // Allocates memory for an internal order structure from our own private
  524. // Order Heap.
  525. //
  526. // Allocates any Additional Order Memory from global memory. A pointer to
  527. // the Additional Order Memory is stored within the allocated order's
  528. // header (pOrder->OrderHeader.pAdditionalOrderData).
  529. //
  530. //
  531. // PARAMETERS:
  532. //
  533. // cbOrderDataLength - length in bytes of the order data to be allocated
  534. // from the Order Heap.
  535. //
  536. // cbAdditionalOrderDataLength - length in bytes of additional order data
  537. // to be allocated from Global Memory. If this parameter is zero no
  538. // additional order memory is allocated.
  539. //
  540. //
  541. // RETURNS:
  542. //
  543. // A pointer to the allocated order memory. NULL if the memory allocation
  544. // failed.
  545. //
  546. //
  547. //
  548. LPINT_ORDER OA_DDAllocOrderMem(UINT cbOrderDataLength, UINT cbAdditionalOrderDataLength)
  549. {
  550. LPINT_ORDER pOrder = NULL;
  551. LPINT_ORDER pFirstOrder;
  552. LPINT_ORDER pTailOrder;
  553. RECT tferRect;
  554. LONG targetSize;
  555. DWORD moveOffset;
  556. DWORD moveBytes;
  557. LPINT_ORDER pColorTableOrder = NULL;
  558. LPBYTE pNextOrderPos;
  559. LPOA_SHARED_DATA lpoaShared;
  560. DebugEntry(OA_DDAllocOrderMem);
  561. lpoaShared = OA_SHM_START_WRITING;
  562. //
  563. // PM Performance
  564. //
  565. // Although turning order accumulation off does clear the pipe, ready
  566. // for us to get the screendata over the wire as soon as we can, it
  567. // actually hinders end-user responsiveness because they see a longer
  568. // interval when nothing is happening, rather than getting feedback
  569. // that we are busy and the whole thing taking longer!
  570. //
  571. // So, what we do when we fill up the order buffer is we discard half
  572. // the orders in the buffer, adding them to the screendata. In this
  573. // way we will always keep between 50 and 100% of the orders for the
  574. // final updates to the window, which hopefully will be what the user
  575. // really wants to see.
  576. //
  577. // If the orders keep coming then we will keep on accumulating some,
  578. // sending them, discarding others until things quiet down, at which
  579. // point we will flush out our order buffer.
  580. //
  581. // When we come to flush the order buffer we also spoil the early ones
  582. // against screendata, so that we only have the final set of orders to
  583. // replay. We control the size of this final non-spoiled set depending
  584. // on whether we are running over a high or low speed connection.
  585. // Also, if we did not encounter any back pressure during the session
  586. // then we do not purge any orders at all, preferring to send
  587. // everything we possibly can as orders.
  588. //
  589. // Note that this approach assumes that we do not spoil all orders
  590. // against screendata on the fly because that leads to us generally
  591. // sending out-of-data orders followed by up-to-date screendata, which
  592. // is exactly what we do not want to see.
  593. //
  594. //
  595. CheckOaHeap(lpoaShared);
  596. //
  597. // First check that we have not already exceeded our high water mark
  598. // recommended by flow control. If we have then purge half the queue
  599. // so we have space to accumulate the later, more valuable, orders
  600. //
  601. // Note that this does not guarantee that we will have less orders
  602. // accumulated than the limit set by flow control. However, if enough
  603. // orders are generated, we will come through this branch on each order
  604. // and finally reduce to below the imposed limit.
  605. //
  606. SHM_CheckPointer(&lpoaShared->totalOrderBytes);
  607. if (g_oaPurgeAllowed && (lpoaShared->totalOrderBytes >
  608. (DWORD)(g_oaFlow == OAFLOW_FAST ? OA_FAST_HEAP : OA_SLOW_HEAP)))
  609. {
  610. RECT aRects[BA_NUM_RECTS];
  611. UINT numRects;
  612. UINT i;
  613. WARNING_OUT(("Purging orders; total 0x%08x is greater than heap 0x%08x",
  614. lpoaShared->totalOrderBytes,
  615. (DWORD)(g_oaFlow == OAFLOW_FAST ? OA_FAST_HEAP : OA_SLOW_HEAP)));
  616. //
  617. // If we need to make room for the new order then purge half the
  618. // current queue. We do this so we end up with the most recent
  619. // orders on the queue, rather than the oldest.
  620. //
  621. targetSize = lpoaShared->totalOrderBytes / 2;
  622. TRACE_OUT(("Target size %ld", targetSize));
  623. //
  624. // Iterate through the list until we have found the first order
  625. // beyond the limit to be destroyed. Once we have got this order,
  626. // we can shuffle the list over the useless orders.
  627. //
  628. pOrder = COM_BasedListFirst(&lpoaShared->orderListHead,
  629. FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  630. pTailOrder = (LPINT_ORDER)COM_BasedPrevListField(&lpoaShared->orderListHead);
  631. //
  632. // If we hit this condition, we have to have at least one order
  633. // pending, so these both must be non NULL.
  634. //
  635. SHM_CheckPointer(pOrder);
  636. SHM_CheckPointer(pTailOrder);
  637. TRACE_OUT(("Order 0x%08lx, tail 0x%08lx", pOrder, pTailOrder));
  638. //
  639. // Disable spoiling of existing orders by screen data while we do
  640. // the purge otherwise we may try to spoil an order which we are
  641. // purging !
  642. //
  643. g_baSpoilByNewSDAEnabled = FALSE;
  644. while ((pOrder != NULL) && (targetSize > 0))
  645. {
  646. //
  647. // Can't check at end; COM_BasedListNext may return NULL and
  648. // SHM_CheckPointer doesn't like that.
  649. //
  650. SHM_CheckPointer(pOrder);
  651. //
  652. // Check to see if this is an internal color table order. If
  653. // it is, the OF_INTERNAL flag will be set.
  654. //
  655. // MemBlt orders rely on being preceeded by a color table order
  656. // to set up the colors correctly. If we purge all the color
  657. // table orders, the following Mem(3)Blts will get the wrong
  658. // colors. So, we have to keep track of the last color table
  659. // order to be purged and then add it back into the order heap
  660. // later.
  661. //
  662. if ((pOrder->OrderHeader.Common.fOrderFlags & OF_INTERNAL) != 0)
  663. {
  664. TRACE_OUT(("Found color table order at %#.8lx", pOrder));
  665. pColorTableOrder = pOrder;
  666. }
  667. else
  668. {
  669. //
  670. // Add the order to the Screen Data Area
  671. //
  672. TRACE_OUT(("Purging orders. Add rect to SDA {%d, %d, %d, %d}",
  673. pOrder->OrderHeader.Common.rcsDst.left,
  674. pOrder->OrderHeader.Common.rcsDst.top,
  675. pOrder->OrderHeader.Common.rcsDst.right,
  676. pOrder->OrderHeader.Common.rcsDst.bottom));
  677. RECT_FROM_TSHR_RECT16(&tferRect,
  678. pOrder->OrderHeader.Common.rcsDst);
  679. BA_AddScreenData(&tferRect);
  680. }
  681. //
  682. // Keep track of how much data still needs removing.
  683. //
  684. targetSize -= INT_ORDER_SIZE(pOrder);
  685. lpoaShared->totalHeapOrderBytes -= INT_ORDER_SIZE(pOrder);
  686. TRACE_OUT(("Total heap order bytes: %ld",
  687. lpoaShared->totalHeapOrderBytes));
  688. lpoaShared->totalOrderBytes -= MAX_ORDER_SIZE(pOrder);
  689. TRACE_OUT(("Total order bytes: %ld",
  690. lpoaShared->totalOrderBytes));
  691. //
  692. // If the order is a Mem(3)Blt, we have to tell SBC that we are
  693. // getting rid of it.
  694. //
  695. if (ORDER_IS_MEMBLT(pOrder) || ORDER_IS_MEM3BLT(pOrder))
  696. {
  697. ERROR_OUT(("MEMBLT orders not supported!"));
  698. }
  699. //
  700. // Get the next order to be removed.
  701. //
  702. pOrder = COM_BasedListNext(&lpoaShared->orderListHead,
  703. pOrder, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  704. }
  705. TRACE_OUT(("Stopped at order %#.8lx", pOrder));
  706. //
  707. // Orders have been transferred to SDA, so now we have to
  708. // - move the last purged color table order (if there is one) to
  709. // the start of the order heap
  710. // - shuffle up the heap
  711. // - reset the pointers.
  712. //
  713. // pOrder points to the first non-purged order.
  714. //
  715. if (pOrder != NULL)
  716. {
  717. pNextOrderPos = lpoaShared->orderHeap;
  718. //
  719. // If we purged (at least) one color table order, move the last
  720. // color table order to the start of the order heap.
  721. //
  722. if (pColorTableOrder != NULL)
  723. {
  724. TRACE_OUT(("Moving color table from %#.8lx to start",
  725. pColorTableOrder));
  726. hmemcpy(pNextOrderPos, pColorTableOrder,
  727. INT_ORDER_SIZE(pColorTableOrder));
  728. pColorTableOrder = (LPINT_ORDER)pNextOrderPos;
  729. lpoaShared->totalHeapOrderBytes
  730. += INT_ORDER_SIZE(pColorTableOrder);
  731. TRACE_OUT(("Total heap order bytes: %ld",
  732. lpoaShared->totalHeapOrderBytes));
  733. lpoaShared->totalOrderBytes += MAX_ORDER_SIZE(pColorTableOrder);
  734. TRACE_OUT(("Total order bytes: %ld",
  735. lpoaShared->totalOrderBytes));
  736. pNextOrderPos += INT_ORDER_SIZE(pColorTableOrder);
  737. //
  738. // Chain the order into the start of the order list. Just
  739. // do the pointers to and from the list head for now, we
  740. // will do the rest later.
  741. //
  742. lpoaShared->orderListHead.next =
  743. PTRBASE_TO_OFFSET(pColorTableOrder, &lpoaShared->orderListHead);
  744. pColorTableOrder->OrderHeader.list.prev =
  745. PTRBASE_TO_OFFSET(&lpoaShared->orderListHead, pColorTableOrder);
  746. }
  747. //
  748. // Move the heap up to the top of the buffer. The following
  749. // diagram illustrates how the order heap is split up at the
  750. // moment.
  751. //
  752. // lpoaShared->nextOrder
  753. // |<���������������������������������������>|
  754. //
  755. // moveOffset moveBytes
  756. // |<���������������>|<�����������������>|
  757. //
  758. // ���������������������������������������������������������ͻ
  759. // � � � � �
  760. // � � purged � remaining � unused �
  761. // � � orders � orders � �
  762. // � � � � � �
  763. // ���������������������������������������������������������ͼ
  764. // ^ � ^ ^
  765. // � � � �
  766. // � � � �
  767. // � � � ��� pOrder
  768. // � � �
  769. // � � ���� pNextOrderPos
  770. // � �
  771. // � ������ color table order
  772. // �
  773. // �������� lpoaShared->orderHeap (pColorTableOrder)
  774. //
  775. // If there is no color table order, pNextOrderPos is equal to
  776. // lpoaShared->orderHeap.
  777. //
  778. // moveOffset is the number of bytes to move the remaining
  779. // orders by.
  780. //
  781. // moveBytes is the number of bytes to be moved.
  782. //
  783. //
  784. moveOffset = PTRBASE_TO_OFFSET(pOrder, pNextOrderPos);
  785. moveBytes = lpoaShared->nextOrder
  786. - moveOffset
  787. - (pNextOrderPos - lpoaShared->orderHeap);
  788. TRACE_OUT(("Moving %ld bytes", moveBytes));
  789. hmemcpy(pNextOrderPos, pOrder, moveBytes);
  790. //
  791. // Update the head and tail pointers to reflect their new
  792. // positions.
  793. //
  794. pFirstOrder = (LPINT_ORDER)pNextOrderPos;
  795. pTailOrder = (LPINT_ORDER)((DWORD)pTailOrder - moveOffset);
  796. SHM_CheckPointer(pFirstOrder);
  797. SHM_CheckPointer(pTailOrder);
  798. TRACE_OUT(("New first unpurged %#.8lx, tail %#.8lx",
  799. pFirstOrder,
  800. pTailOrder));
  801. //
  802. // Since the offsets are relative to the order pointer, we only
  803. // need to modify the start and end offsets.
  804. //
  805. // Unfortunately, the possibility of a color table order at the
  806. // start of the heap complicates the chaining of pFirstOrder.
  807. // If there is a color table order, we chain pFirstOrder to the
  808. // color table order, otherwise we chain it to the start of the
  809. // order list.
  810. //
  811. lpoaShared->orderListHead.prev =
  812. PTRBASE_TO_OFFSET(pTailOrder, &lpoaShared->orderListHead);
  813. pTailOrder->OrderHeader.list.next =
  814. PTRBASE_TO_OFFSET(&lpoaShared->orderListHead, pTailOrder);
  815. if (pColorTableOrder != NULL)
  816. {
  817. pColorTableOrder->OrderHeader.list.next =
  818. PTRBASE_TO_OFFSET(pFirstOrder, pColorTableOrder);
  819. pFirstOrder->OrderHeader.list.prev =
  820. PTRBASE_TO_OFFSET(pColorTableOrder, pFirstOrder);
  821. }
  822. else
  823. {
  824. lpoaShared->orderListHead.next =
  825. PTRBASE_TO_OFFSET(pFirstOrder, &lpoaShared->orderListHead);
  826. pFirstOrder->OrderHeader.list.prev =
  827. PTRBASE_TO_OFFSET(&lpoaShared->orderListHead, pFirstOrder);
  828. }
  829. //
  830. // Sort out where the next order to be allocated will go
  831. //
  832. lpoaShared->nextOrder -= moveOffset;
  833. TRACE_OUT(("Next order: %ld", lpoaShared->nextOrder));
  834. }
  835. else
  836. {
  837. //
  838. // No orders left - this happens if we've had lots of spoiling.
  839. // We have now cleared out all the valid orders so let's
  840. // re-initialise the heap for next time.
  841. //
  842. OA_DDResetOrderList();
  843. }
  844. //
  845. // Now re-enable the spoiling of orders by SDA.
  846. //
  847. g_baSpoilByNewSDAEnabled = TRUE;
  848. CheckOaHeap(lpoaShared);
  849. WARNING_OUT(("Purged orders, total is now 0x%08x", lpoaShared->totalOrderBytes));
  850. //
  851. // Lastly, spoil the remaining orders by the screen data.
  852. // If we've gotten this far, there's a lot of data being sent
  853. // and/or we're slow. So nuke 'em.
  854. //
  855. BA_CopyBounds(aRects, &numRects, FALSE);
  856. for (i = 0; i < numRects; i++)
  857. {
  858. OA_DDSpoilOrdersByRect(aRects+i);
  859. }
  860. WARNING_OUT(("Spoiled remaining orders by SDA, total is now 0x%08x", lpoaShared->totalOrderBytes));
  861. TRACE_OUT(("Next 0x%08lx", lpoaShared->nextOrder));
  862. TRACE_OUT(("Head 0x%08lx", lpoaShared->orderListHead.next));
  863. TRACE_OUT(("Tail 0x%08lx", lpoaShared->orderListHead.prev));
  864. TRACE_OUT(("Total heap bytes 0x%08lx", lpoaShared->totalHeapOrderBytes));
  865. TRACE_OUT(("Total order bytes 0x%08lx", lpoaShared->totalOrderBytes));
  866. CheckOaHeap(lpoaShared);
  867. }
  868. pOrder = OADDAllocOrderMemInt(lpoaShared, cbOrderDataLength,
  869. cbAdditionalOrderDataLength);
  870. if ( pOrder != NULL )
  871. {
  872. //
  873. // Update the count of total order data.
  874. //
  875. SHM_CheckPointer(&lpoaShared->totalHeapOrderBytes);
  876. lpoaShared->totalHeapOrderBytes += sizeof(INT_ORDER_HEADER)
  877. + cbOrderDataLength;
  878. TRACE_OUT(("Total heap order bytes: %ld", lpoaShared->totalHeapOrderBytes));
  879. SHM_CheckPointer(&lpoaShared->totalAdditionalOrderBytes);
  880. lpoaShared->totalAdditionalOrderBytes += cbAdditionalOrderDataLength;
  881. TRACE_OUT(("Total additional order bytes: %ld", lpoaShared->totalAdditionalOrderBytes));
  882. }
  883. TRACE_OUT(("Alloc order, addr %lx, size %u", pOrder,
  884. cbOrderDataLength));
  885. CheckOaHeap(lpoaShared);
  886. OA_SHM_STOP_WRITING;
  887. DebugExitDWORD(OA_DDAllocOrderMem, (DWORD)pOrder);
  888. return(pOrder);
  889. }
  890. //
  891. //
  892. // FUNCTION: OA_DDFreeOrderMem
  893. //
  894. //
  895. // DESCRIPTION:
  896. //
  897. // Frees order memory from our own private heap.
  898. // Frees any Additional Order Memory associated with this order.
  899. //
  900. //
  901. // PARAMETERS:
  902. //
  903. // pOrder - pointer to the order to be freed.
  904. //
  905. //
  906. // RETURNS:
  907. //
  908. // Nothing.
  909. //
  910. //
  911. void OA_DDFreeOrderMem(LPINT_ORDER pOrder)
  912. {
  913. LPOA_SHARED_DATA lpoaShared;
  914. DebugEntry(OA_DDFreeOrderMem);
  915. ASSERT(pOrder);
  916. lpoaShared = OA_SHM_START_WRITING;
  917. TRACE_OUT(("Free order %lx", pOrder));
  918. CheckOaHeap(lpoaShared);
  919. //
  920. // Update the data totals.
  921. //
  922. SHM_CheckPointer(&lpoaShared->totalHeapOrderBytes);
  923. lpoaShared->totalHeapOrderBytes -= (sizeof(INT_ORDER_HEADER)
  924. + pOrder->OrderHeader.Common.cbOrderDataLength);
  925. TRACE_OUT(("Total heap order bytes: %ld", lpoaShared->totalHeapOrderBytes));
  926. SHM_CheckPointer(&lpoaShared->totalAdditionalOrderBytes);
  927. lpoaShared->totalAdditionalOrderBytes -=
  928. pOrder->OrderHeader.cbAdditionalOrderDataLength;
  929. TRACE_OUT(("Total additional order bytes: %ld", lpoaShared->totalAdditionalOrderBytes));
  930. //
  931. // Do the work.
  932. //
  933. OADDFreeOrderMemInt(lpoaShared, pOrder);
  934. CheckOaHeap(lpoaShared);
  935. OA_SHM_STOP_WRITING;
  936. DebugExitVOID(OA_DDFreeOrderMem);
  937. }
  938. //
  939. //
  940. // FUNCTION: OA_DDResetOrderList
  941. //
  942. //
  943. // DESCRIPTION:
  944. //
  945. // Frees all Orders and Additional Order Data in the Order List.
  946. // Frees up the Order Heap memory.
  947. //
  948. //
  949. // PARAMETERS:
  950. //
  951. // None.
  952. //
  953. //
  954. // RETURNS:
  955. //
  956. // Nothing.
  957. //
  958. //
  959. void OA_DDResetOrderList(void)
  960. {
  961. LPOA_SHARED_DATA lpoaShared;
  962. DebugEntry(OA_DDResetOrderList);
  963. TRACE_OUT(("Resetting order list"));
  964. lpoaShared = OA_SHM_START_WRITING;
  965. CheckOaHeap(lpoaShared);
  966. //
  967. // First free all the orders on the list.
  968. //
  969. OADDFreeAllOrders(lpoaShared);
  970. //
  971. // Ensure that the list pointers are NULL.
  972. //
  973. SHM_CheckPointer(&lpoaShared->orderListHead);
  974. if ((lpoaShared->orderListHead.next != 0) || (lpoaShared->orderListHead.prev != 0))
  975. {
  976. ERROR_OUT(("Non-NULL list pointers (%lx)(%lx)",
  977. lpoaShared->orderListHead.next,
  978. lpoaShared->orderListHead.prev));
  979. SHM_CheckPointer(&lpoaShared->orderListHead);
  980. COM_BasedListInit(&lpoaShared->orderListHead);
  981. }
  982. CheckOaHeap(lpoaShared);
  983. OA_SHM_STOP_WRITING;
  984. DebugExitVOID(OA_DDResetOrderList);
  985. }
  986. //
  987. // OA_DDSyncUpdatesNow
  988. //
  989. // Called when a sync operation is required.
  990. //
  991. // Discards all outstanding orders.
  992. //
  993. void OA_DDSyncUpdatesNow(void)
  994. {
  995. DebugEntry(OA_DDSyncUpdatesNow);
  996. TRACE_OUT(("Syncing OA updates now"));
  997. OADDFreeAllOrders(g_poaData[g_asSharedMemory->displayToCore.currentBuffer]);
  998. DebugExitVOID(OA_DDSyncUpdatesNow);
  999. }
  1000. //
  1001. //
  1002. // OA_DDRemoveListOrder(..)
  1003. //
  1004. // Removes the specified order from the Order List by marking it as spoilt.
  1005. //
  1006. // Returns:
  1007. // Pointer to the order following the removed order.
  1008. //
  1009. //
  1010. LPINT_ORDER OA_DDRemoveListOrder(LPINT_ORDER pCondemnedOrder)
  1011. {
  1012. LPOA_SHARED_DATA lpoaShared;
  1013. LPINT_ORDER pSaveOrder;
  1014. DebugEntry(OA_DDRemoveListOrder);
  1015. TRACE_OUT(("Remove list order (%lx)", pCondemnedOrder));
  1016. lpoaShared = OA_SHM_START_WRITING;
  1017. SHM_CheckPointer(pCondemnedOrder);
  1018. //
  1019. // Check for a valid order.
  1020. //
  1021. if (pCondemnedOrder->OrderHeader.Common.fOrderFlags & OF_SPOILT)
  1022. {
  1023. ERROR_OUT(("Invalid order"));
  1024. DC_QUIT;
  1025. }
  1026. //
  1027. // Get the offset value of this order.
  1028. //
  1029. SHM_CheckPointer(&lpoaShared->orderHeap);
  1030. //
  1031. // Mark the order as spoilt.
  1032. //
  1033. pCondemnedOrder->OrderHeader.Common.fOrderFlags |= OF_SPOILT;
  1034. //
  1035. // Update the count of bytes currently in the Order List.
  1036. //
  1037. SHM_CheckPointer(&lpoaShared->totalOrderBytes);
  1038. lpoaShared->totalOrderBytes -= MAX_ORDER_SIZE(pCondemnedOrder);
  1039. TRACE_OUT(("Total order bytes: %ld", lpoaShared->totalOrderBytes));
  1040. //
  1041. // Save the order so we can remove it from the linked list after having
  1042. // got the next element in the chain.
  1043. //
  1044. pSaveOrder = pCondemnedOrder;
  1045. //
  1046. // Return the next order in the list.
  1047. //
  1048. SHM_CheckPointer(&lpoaShared->orderListHead);
  1049. pCondemnedOrder = COM_BasedListNext(&lpoaShared->orderListHead,
  1050. pCondemnedOrder, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1051. if (pSaveOrder == pCondemnedOrder)
  1052. {
  1053. ERROR_OUT(("Order list has gone circular !"));
  1054. }
  1055. //
  1056. // Delete the unwanted order from the linked list.
  1057. //
  1058. COM_BasedListRemove(&pSaveOrder->OrderHeader.list);
  1059. //
  1060. // Check that the list is still consistent with the total number of
  1061. // order bytes.
  1062. //
  1063. if ( (lpoaShared->orderListHead.next != 0) &&
  1064. (lpoaShared->orderListHead.prev != 0) &&
  1065. (lpoaShared->totalOrderBytes == 0) )
  1066. {
  1067. ERROR_OUT(("List head wrong: %ld %ld", lpoaShared->orderListHead.next,
  1068. lpoaShared->orderListHead.prev));
  1069. COM_BasedListInit(&lpoaShared->orderListHead);
  1070. pCondemnedOrder = NULL;
  1071. }
  1072. DC_EXIT_POINT:
  1073. CheckOaHeap(lpoaShared);
  1074. OA_SHM_STOP_WRITING;
  1075. DebugExitDWORD(OA_DDRemoveListOrder, (DWORD)pCondemnedOrder);
  1076. return(pCondemnedOrder);
  1077. }
  1078. //
  1079. // OA_DDSpoilOrdersByRect - see oa.h
  1080. //
  1081. void OA_DDSpoilOrdersByRect(LPRECT pRect)
  1082. {
  1083. LPOA_SHARED_DATA lpoaShared;
  1084. LPINT_ORDER pOrder;
  1085. DebugEntry(OA_DDSpoilOrdersByRect);
  1086. lpoaShared = OA_SHM_START_WRITING;
  1087. CheckOaHeap(lpoaShared);
  1088. //
  1089. // We want to start spoiling from the newest order i.e. the one at the
  1090. // end of the order list.
  1091. //
  1092. pOrder = COM_BasedListLast(&lpoaShared->orderListHead,
  1093. FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1094. if (pOrder != NULL)
  1095. {
  1096. OADDSpoilFromOrder(lpoaShared, pOrder, pRect);
  1097. }
  1098. CheckOaHeap(lpoaShared);
  1099. OA_SHM_STOP_WRITING;
  1100. DebugExitVOID(OA_DDSpoilOrdersByRect);
  1101. }
  1102. //
  1103. //
  1104. // OADDAppendToOrderList(..)
  1105. //
  1106. // Commits an allocated order to the end of the Order List. The order must
  1107. // NOT be freed once it has been added. The whole list must be invalidated
  1108. // to free the committed orders.
  1109. //
  1110. //
  1111. void OADDAppendToOrderList(LPOA_SHARED_DATA lpoaShared, LPINT_ORDER pNewOrder)
  1112. {
  1113. DebugEntry(OADDAppendToOrderList);
  1114. //
  1115. // Chain entry is already set up so all we do is keep track of
  1116. // committed orders.
  1117. //
  1118. //
  1119. // Store the total number of order bytes used.
  1120. //
  1121. SHM_CheckPointer(&lpoaShared->totalOrderBytes);
  1122. lpoaShared->totalOrderBytes += MAX_ORDER_SIZE(pNewOrder);
  1123. TRACE_OUT(("Total Order Bytes: %ld", lpoaShared->totalOrderBytes));
  1124. DebugExitVOID(OADDAppendToOrderList);
  1125. }
  1126. //
  1127. //
  1128. // FUNCTION: OADDAllocOrderMemInt
  1129. //
  1130. // DESCRIPTION:
  1131. //
  1132. // Allocates memory for an internal order structure from our order heap.
  1133. //
  1134. //
  1135. // PARAMETERS:
  1136. //
  1137. // cbOrderDataLength - length in bytes of the order data to be allocated
  1138. // from the Order Heap.
  1139. //
  1140. // cbAdditionalOrderDataLength - length in bytes of additional order data
  1141. // to be allocated. If this parameter is zero no additional order memory
  1142. // is allocated.
  1143. //
  1144. //
  1145. // RETURNS:
  1146. //
  1147. // A pointer to the allocated order memory. NULL if the memory allocation
  1148. // failed.
  1149. //
  1150. //
  1151. //
  1152. LPINT_ORDER OADDAllocOrderMemInt
  1153. (
  1154. LPOA_SHARED_DATA lpoaShared,
  1155. UINT cbOrderDataLength,
  1156. UINT cbAdditionalOrderDataLength
  1157. )
  1158. {
  1159. LPINT_ORDER pOrder = NULL;
  1160. UINT cbOrderSize;
  1161. DebugEntry(OADDAllocOrderMemInt);
  1162. //
  1163. // If the additional data will take us over our Additional Data Limit
  1164. // then fail the memory allocation.
  1165. //
  1166. SHM_CheckPointer(&lpoaShared->totalAdditionalOrderBytes);
  1167. if ((lpoaShared->totalAdditionalOrderBytes + cbAdditionalOrderDataLength) >
  1168. MAX_ADDITIONAL_DATA_BYTES)
  1169. {
  1170. TRACE_OUT(("Hit Additional Data Limit, current %lu addint %u",
  1171. lpoaShared->totalAdditionalOrderBytes,
  1172. cbAdditionalOrderDataLength));
  1173. DC_QUIT;
  1174. }
  1175. //
  1176. // Calculate the number of bytes we need to allocate (including the
  1177. // order header). Round up to the nearest 4 bytes to keep the 4 byte
  1178. // alignment for the next order.
  1179. //
  1180. cbOrderSize = sizeof(INT_ORDER_HEADER) + cbOrderDataLength;
  1181. cbOrderSize = (cbOrderSize + 3) & 0xFFFFFFFC;
  1182. //
  1183. // Make sure we don't overrun our heap limit
  1184. //
  1185. SHM_CheckPointer(&lpoaShared->nextOrder);
  1186. if (lpoaShared->nextOrder + cbOrderSize > OA_HEAP_MAX)
  1187. {
  1188. WARNING_OUT(("Heap limit hit"));
  1189. DC_QUIT;
  1190. }
  1191. //
  1192. // Construct a far pointer to the allocated memory, and fill in the
  1193. // length field in the Order Header.
  1194. //
  1195. SHM_CheckPointer(&lpoaShared->orderHeap);
  1196. pOrder = (LPINT_ORDER)(lpoaShared->orderHeap + lpoaShared->nextOrder);
  1197. pOrder->OrderHeader.Common.cbOrderDataLength = cbOrderDataLength;
  1198. //
  1199. // Update the order header to point to the next section of free heap.
  1200. //
  1201. SHM_CheckPointer(&lpoaShared->nextOrder);
  1202. lpoaShared->nextOrder += cbOrderSize;
  1203. //
  1204. // Allocate any Additional Order Memory from Global Memory.
  1205. //
  1206. if (cbAdditionalOrderDataLength > 0)
  1207. {
  1208. //
  1209. // Make sure we don't overrun our heap limit
  1210. //
  1211. SHM_CheckPointer(&lpoaShared->nextOrder);
  1212. if (lpoaShared->nextOrder + cbAdditionalOrderDataLength > OA_HEAP_MAX)
  1213. {
  1214. WARNING_OUT(("Heap limit hit for additional data"));
  1215. //
  1216. // Clear the allocated order and quit.
  1217. //
  1218. SHM_CheckPointer(&lpoaShared->nextOrder);
  1219. lpoaShared->nextOrder -= cbOrderSize;
  1220. pOrder = NULL;
  1221. DC_QUIT;
  1222. }
  1223. //
  1224. // Store the space for the additional data.
  1225. //
  1226. SHM_CheckPointer(&lpoaShared->nextOrder);
  1227. pOrder->OrderHeader.additionalOrderData = lpoaShared->nextOrder;
  1228. pOrder->OrderHeader.cbAdditionalOrderDataLength =
  1229. cbAdditionalOrderDataLength;
  1230. //
  1231. // Update the next order pointer to point to the next 4-byte
  1232. // boundary.
  1233. //
  1234. SHM_CheckPointer(&lpoaShared->nextOrder);
  1235. lpoaShared->nextOrder += cbAdditionalOrderDataLength + 3;
  1236. lpoaShared->nextOrder &= 0xFFFFFFFC;
  1237. }
  1238. else
  1239. {
  1240. pOrder->OrderHeader.additionalOrderData = 0;
  1241. pOrder->OrderHeader.cbAdditionalOrderDataLength = 0;
  1242. }
  1243. TRACE_OUT(("Next order: %ld", lpoaShared->nextOrder));
  1244. #ifdef DEBUG
  1245. //
  1246. // Initialize the bounds rect to something whacky, so we can detect if
  1247. // our list ever gets out of order. Orders MUST be committed in the
  1248. // sequence that they are allocated in. Otherwise, spoilers will cause
  1249. // us to mess up the linked list, since they walk backwards and assume
  1250. // all previous orders are already committed.
  1251. //
  1252. CopyRect((LPRECT)&pOrder->OrderHeader.Common.rcsDst, &g_oaEmptyRect);
  1253. #endif // DEBUG
  1254. //
  1255. // Create the chain entry.
  1256. //
  1257. SHM_CheckPointer(&lpoaShared->orderListHead);
  1258. COM_BasedListInsertBefore(&lpoaShared->orderListHead, &pOrder->OrderHeader.list);
  1259. DC_EXIT_POINT:
  1260. DebugExitDWORD(OADDAllocOrderMemInit, (DWORD)pOrder);
  1261. return(pOrder);
  1262. }
  1263. //
  1264. //
  1265. // FUNCTION: OADDFreeOrderMemInt
  1266. //
  1267. //
  1268. // DESCRIPTION:
  1269. //
  1270. // Frees order memory from our orders heap. Frees any Additional Order
  1271. // Memory associated with this order. This must NOT be used on an order
  1272. // that has been committed to the order list.
  1273. //
  1274. //
  1275. // PARAMETERS:
  1276. //
  1277. // pOrder - pointer to the order to be freed.
  1278. //
  1279. //
  1280. // RETURNS:
  1281. //
  1282. // Nothing.
  1283. //
  1284. //
  1285. void OADDFreeOrderMemInt(LPOA_SHARED_DATA lpoaShared, LPINT_ORDER pOrder)
  1286. {
  1287. LPINT_ORDER pOrderTail;
  1288. DebugEntry(OADDFreeOrderMemInt);
  1289. //
  1290. // The order heap is real a misnomer. We know that the memory is only
  1291. // allocated in a purely sequential manner and deallocated as one large
  1292. // lump of memory.
  1293. //
  1294. // So we do not need to implement a full memory heap allocation
  1295. // mechanism. Instead, we just need to keep track of where the
  1296. // previous high water mark was before this order was freed.
  1297. //
  1298. //
  1299. // Find the tail of the current chain.
  1300. //
  1301. pOrderTail = COM_BasedListLast(&lpoaShared->orderListHead, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1302. SHM_CheckPointer(pOrderTail);
  1303. //
  1304. // We wont necessarily be freeing the last item in the order heap.
  1305. //
  1306. if (pOrder == pOrderTail)
  1307. {
  1308. //
  1309. // This is the last item in the heap, so we can set the pointer to
  1310. // the next order to be used back to the start of the order being
  1311. // freed.
  1312. //
  1313. SHM_CheckPointer(&lpoaShared->nextOrder);
  1314. lpoaShared->nextOrder = (LONG)PTRBASE_TO_OFFSET(pOrder, lpoaShared->orderHeap);
  1315. TRACE_OUT(("Next order: %ld", lpoaShared->nextOrder));
  1316. }
  1317. else
  1318. {
  1319. //
  1320. // This is not the last item in the heap - we must not reset the
  1321. // pointer to the next item to be used.
  1322. //
  1323. TRACE_OUT(("Not resetting next order (not last item in heap)"));
  1324. }
  1325. //
  1326. // Delete the item from the chain.
  1327. //
  1328. COM_BasedListRemove(&pOrder->OrderHeader.list);
  1329. DebugExitVOID(OADDFreeOrderMemInt);
  1330. }
  1331. //
  1332. // OADDFreeAllOrders
  1333. //
  1334. // Free the all the individual orders on the orders list, without
  1335. // discarding the list itself.
  1336. //
  1337. void OADDFreeAllOrders(LPOA_SHARED_DATA lpoaShared)
  1338. {
  1339. DebugEntry(OADDFreeAllOrders);
  1340. TRACE_OUT(("Freeing all orders"));
  1341. //
  1342. // Simply clear the list head.
  1343. //
  1344. COM_BasedListInit(&lpoaShared->orderListHead);
  1345. SHM_CheckPointer(&lpoaShared->orderListHead);
  1346. lpoaShared->totalHeapOrderBytes = 0;
  1347. lpoaShared->totalOrderBytes = 0;
  1348. lpoaShared->totalAdditionalOrderBytes = 0;
  1349. lpoaShared->nextOrder = 0;
  1350. DebugExitVOID(OADDFreeAllOrders);
  1351. }
  1352. BOOL OADDCompleteOverlapRect(LPTSHR_RECT16 prcsSrc, LPRECT prcsOverlap)
  1353. {
  1354. //
  1355. // Return TRUE if the source is completely enclosed by the overlap
  1356. // rectangle.
  1357. //
  1358. return( (prcsSrc->left >= prcsOverlap->left) &&
  1359. (prcsSrc->right <= prcsOverlap->right) &&
  1360. (prcsSrc->top >= prcsOverlap->top) &&
  1361. (prcsSrc->bottom <= prcsOverlap->bottom) );
  1362. }
  1363. //
  1364. // Name: OADDSpoilFromOrder
  1365. //
  1366. // Purpose: Remove any orders from the order heap which should be spoiled
  1367. // by a given rectangle..
  1368. //
  1369. // Returns: Nothing
  1370. //
  1371. // Params: IN pTargetOrder - Pointer to the first order to try to
  1372. // spoil.
  1373. // IN pRect - Pointer to the spoiling rectangle.
  1374. //
  1375. // Operation: pTargetOrder may be spoiled by this function, so be careful
  1376. // on return.
  1377. //
  1378. void OADDSpoilFromOrder
  1379. (
  1380. LPOA_SHARED_DATA lpoaShared,
  1381. LPINT_ORDER pTargetOrder,
  1382. LPRECT pSpoilRect
  1383. )
  1384. {
  1385. UINT nonProductiveScanDepth = 0;
  1386. UINT scanExitDepth;
  1387. BOOL reachedBlocker = FALSE;
  1388. DebugEntry(OADDSpoilFromOrder);
  1389. TRACE_OUT(("Spoiling rect is {%d, %d, %d, %d}",
  1390. pSpoilRect->left,
  1391. pSpoilRect->top,
  1392. pSpoilRect->right,
  1393. pSpoilRect->bottom));
  1394. //
  1395. // Work out how deep we will scan if the spoiling is non-productive.
  1396. // We go further for bigger orders over PSTN. (ie Irrespective of the
  1397. // bandwidth we do not want to do much work when the app is blasting
  1398. // out a lot of single pel orders!)
  1399. //
  1400. if (((pSpoilRect->right - pSpoilRect->left) < FULL_SPOIL_WIDTH) &&
  1401. ((pSpoilRect->bottom - pSpoilRect->top) < FULL_SPOIL_HEIGHT))
  1402. {
  1403. TRACE_OUT(("Small order so reducing spoil depth"));
  1404. scanExitDepth = OA_FAST_SCAN_DEPTH;
  1405. }
  1406. else
  1407. {
  1408. //
  1409. // Use the current default scan depth (this is based on the
  1410. // current network throughput).
  1411. //
  1412. scanExitDepth = (g_oaFlow == OAFLOW_FAST) ?
  1413. OA_FAST_SCAN_DEPTH : OA_SLOW_SCAN_DEPTH;
  1414. }
  1415. //
  1416. // Loop backwards from the base order until we have one of the
  1417. // following occurs.
  1418. // - We spoil all the preceeding orders.
  1419. // - We reach a blocker which we can't spoil.
  1420. // - We find scanExitDepth orders which we can't spoil.
  1421. //
  1422. while ((pTargetOrder != NULL)
  1423. && !reachedBlocker
  1424. && (nonProductiveScanDepth < scanExitDepth))
  1425. {
  1426. //
  1427. // We do not exit immediately when we reach a blocker because it is
  1428. // possible that we will spoil it. If we do spoil it, then we can
  1429. // quite happily try spoiling the orders which preceed it.
  1430. //
  1431. // So, just set a flag here which we will reset if we spoil the
  1432. // order.
  1433. //
  1434. reachedBlocker =
  1435. ((pTargetOrder->OrderHeader.Common.fOrderFlags & OF_BLOCKER) != 0);
  1436. //
  1437. // Only try to spoil spoilable orders.
  1438. //
  1439. if (pTargetOrder->OrderHeader.Common.fOrderFlags & OF_SPOILABLE)
  1440. {
  1441. //
  1442. // Make sure this order is committed!
  1443. //
  1444. ASSERT(!EqualRect((LPRECT)&pTargetOrder->OrderHeader.Common.rcsDst, &g_oaEmptyRect));
  1445. if (OADDCompleteOverlapRect(
  1446. &pTargetOrder->OrderHeader.Common.rcsDst, pSpoilRect))
  1447. {
  1448. //
  1449. // The order can be spoilt. If the order is a MemBlt or a
  1450. // Mem3Blt, we have to notify SBC to allow it to free up
  1451. // associated data.
  1452. //
  1453. if (ORDER_IS_MEMBLT(pTargetOrder) ||
  1454. ORDER_IS_MEM3BLT(pTargetOrder))
  1455. {
  1456. ERROR_OUT(("MEMBLT orders not supported!"));
  1457. }
  1458. TRACE_OUT(("Spoil by order {%d, %d, %d, %d}",
  1459. pTargetOrder->OrderHeader.Common.rcsDst.left,
  1460. pTargetOrder->OrderHeader.Common.rcsDst.top,
  1461. pTargetOrder->OrderHeader.Common.rcsDst.right,
  1462. pTargetOrder->OrderHeader.Common.rcsDst.bottom));
  1463. pTargetOrder = OA_DDRemoveListOrder(pTargetOrder);
  1464. //
  1465. // Reset the blocker flag - we spoiled the order, so if it
  1466. // was a blocker we can now try to spoil earlier orders.
  1467. //
  1468. reachedBlocker = FALSE;
  1469. }
  1470. else
  1471. {
  1472. nonProductiveScanDepth++;
  1473. }
  1474. }
  1475. else
  1476. {
  1477. nonProductiveScanDepth++;
  1478. }
  1479. //
  1480. // Get the previous order in the list. We have to be careful
  1481. // because we may have just removed the last item in the list, in
  1482. // which case pTargetOrder will be NULL.
  1483. //
  1484. if (pTargetOrder == NULL)
  1485. {
  1486. pTargetOrder = COM_BasedListLast(&lpoaShared->orderListHead,
  1487. FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1488. }
  1489. else
  1490. {
  1491. pTargetOrder = COM_BasedListPrev(&lpoaShared->orderListHead,
  1492. pTargetOrder, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1493. }
  1494. }
  1495. DebugExitVOID(OADDSpoilFromOrder);
  1496. }
  1497. #ifdef DEBUG
  1498. //
  1499. // This is a DEBUG-only function that walks a double-linked list and verifies
  1500. // that it is sane.
  1501. //
  1502. // We walk the list front to back, ensuring that the next item of the
  1503. // current order is the same as the previous item of the next order.
  1504. //
  1505. // Then we walk the list back to front, ensuring that the previous item of
  1506. // the current order is the same as the next item of the previous order.
  1507. //
  1508. // At the same time, we sum up the total order and total heap bytes. They
  1509. // should equal what's in the structure header.
  1510. //
  1511. void CheckOaHeap(LPOA_SHARED_DATA lpoaHeap)
  1512. {
  1513. PBASEDLIST pList;
  1514. LPINT_ORDER pNextPrev;
  1515. LPINT_ORDER pCur;
  1516. LPINT_ORDER pNext;
  1517. if (!(g_trcConfig & ZONE_OAHEAPCHECK))
  1518. return;
  1519. //
  1520. // Walk front to back
  1521. //
  1522. pList = &lpoaHeap->orderListHead;
  1523. pCur = COM_BasedListFirst(pList, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1524. while (pCur != NULL)
  1525. {
  1526. //
  1527. // Get the next item
  1528. //
  1529. pNext = COM_BasedListNext(pList, pCur, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1530. //
  1531. // Is the previous dude of the next the same as us?
  1532. //
  1533. if (pNext != NULL)
  1534. {
  1535. pNextPrev = COM_BasedListPrev(pList, pNext, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1536. ASSERT(pNextPrev == pCur);
  1537. }
  1538. pCur = pNext;
  1539. }
  1540. //
  1541. // Walk back to front
  1542. //
  1543. pCur = COM_BasedListLast(pList, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1544. while (pCur != NULL)
  1545. {
  1546. //
  1547. // Get the previous item
  1548. //
  1549. pNextPrev = COM_BasedListPrev(pList, pCur, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1550. //
  1551. // Is the next dude of the previous the same as us?
  1552. //
  1553. if (pNextPrev != NULL)
  1554. {
  1555. pNext = COM_BasedListNext(pList, pNextPrev, FIELD_OFFSET(INT_ORDER, OrderHeader.list));
  1556. ASSERT(pNext == pCur);
  1557. }
  1558. pCur = pNextPrev;
  1559. }
  1560. }
  1561. #endif