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.

1701 lines
56 KiB

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