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.

1668 lines
54 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: heap.c
  8. *
  9. * This module contains the routines for an off-screen video heap manager.
  10. * It is used primarily for allocating space for device-format-bitmaps in
  11. * off-screen memory.
  12. *
  13. * Off-screen bitmaps are a big deal on NT because:
  14. *
  15. * 1) It reduces the working set. Any bitmap stored in off-screen
  16. * memory is a bitmap that isn't taking up space in main memory.
  17. *
  18. * 2) There is a speed win by using the accelerator hardware for
  19. * drawing, in place of NT's GDI code. NT's GDI is written entirely
  20. * in 'C++' and perhaps isn't as fast as it could be.
  21. *
  22. * 3) It leads naturally to nifty tricks that can take advantage of
  23. * the hardware, such as MaskBlt support and cheap double buffering
  24. * for OpenGL.
  25. *
  26. * NOTE: All heap operations must be done under some sort of synchronization,
  27. * whether it's controlled by GDI or explicitly by the driver. All
  28. * the routines in this module assume that they have exclusive access
  29. * to the heap data structures; multiple threads partying in here at
  30. * the same time would be a Bad Thing. (By default, GDI does NOT
  31. * synchronize drawing on device-created bitmaps.)
  32. *
  33. * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  34. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
  35. \*****************************************************************************/
  36. #include "precomp.h"
  37. #include "gdi.h"
  38. #include "directx.h"
  39. #include "log.h"
  40. #include "heap.h"
  41. #define ALLOC_TAG ALLOC_TAG_EH2P
  42. //-----------------------------------------------------------------------------
  43. //
  44. // void vRemoveSurfFromList(Surf* psurf)
  45. //
  46. // Removes the surface from the surface list
  47. //
  48. //-----------------------------------------------------------------------------
  49. VOID
  50. vRemoveSurfFromList(PPDev ppdev, Surf* psurf)
  51. {
  52. DBG_GDI((3, "vRemoveSurfFromList removing psruf=0x%x", psurf));
  53. //@@BEGIN_DDKSPLIT
  54. ASSERTLOCK(ppdev, vRemoveSurfFromList);
  55. //@@END_DDKSPLIT
  56. if ( psurf != NULL && psurf->flags & SF_LIST)
  57. {
  58. Surf* pHead = ppdev->psurfListHead;
  59. Surf* pTail = ppdev->psurfListTail;
  60. if ( psurf == pHead )
  61. {
  62. DBG_GDI((3, "vRemoveSurfFromList removing 1st one"));
  63. //
  64. // Remove the first one in the list
  65. //
  66. Surf* pNextSurf = psurf->psurfNext;
  67. if ( pNextSurf != NULL )
  68. {
  69. pNextSurf->psurfPrev = NULL;
  70. ppdev->psurfListHead = pNextSurf;
  71. DBG_GDI((3, "Move head to 0x%x", ppdev->psurfListHead));
  72. }
  73. else
  74. {
  75. //
  76. // This is the only psurf in our list. Let head and tail all
  77. // point to NULL after removal
  78. //
  79. DBG_GDI((3, "vRemoveSurfFromList: the only one in list"));
  80. ppdev->psurfListHead = NULL;
  81. ppdev->psurfListTail = NULL;
  82. }
  83. }// The psurf happens to be the first one in the list
  84. else if ( psurf == pTail )
  85. {
  86. DBG_GDI((3, "vRemoveSurfFromList removing last one"));
  87. //
  88. // Remove the last one in the list
  89. //
  90. ppdev->psurfListTail = psurf->psurfPrev;
  91. ppdev->psurfListTail->psurfNext = NULL;
  92. }// The psurf happens to be the last one in the list
  93. else
  94. {
  95. //
  96. // Normal case, the psurf is in the middle of a list
  97. //
  98. Surf* psurfPrev = psurf->psurfPrev;
  99. Surf* psurfNext = psurf->psurfNext;
  100. DBG_GDI((3, "vRemoveSurfFromList removing middle one"));
  101. psurfPrev->psurfNext = psurfNext;
  102. psurfNext->psurfPrev = psurfPrev;
  103. }
  104. psurf->psurfNext = NULL;
  105. psurf->psurfPrev = NULL;
  106. psurf->flags &= ~SF_LIST;
  107. }// if ( psurf != NULL )
  108. }// vRemoveSurfFromList()
  109. //-----------------------------------------------------------------------------
  110. //
  111. // void vAddSurfToList(PPDev ppdev, Surf* psurf)
  112. //
  113. // Adds the surface to the surface list
  114. //
  115. // Note: We always add the surface to the end of the list.
  116. //
  117. //-----------------------------------------------------------------------------
  118. VOID
  119. vAddSurfToList(PPDev ppdev, Surf* psurf)
  120. {
  121. //@@BEGIN_DDKSPLIT
  122. ASSERTLOCK(ppdev, vAddSurfToList);
  123. //@@END_DDKSPLIT
  124. if ( ppdev->psurfListHead == NULL )
  125. {
  126. DBG_GDI((3, "vAddSurfToList add psurf=0x%x as 1st one", psurf));
  127. //
  128. // First time add a pdsurf to the surface list
  129. //
  130. ppdev->psurfListHead = psurf;
  131. ppdev->psurfListTail = psurf;
  132. psurf->psurfPrev = NULL;
  133. psurf->psurfNext = NULL;
  134. DBG_GDI((6, "vAddSurfToList set pHead as 0x%x", ppdev->psurfListHead));
  135. }
  136. else
  137. {
  138. Surf* pTail = ppdev->psurfListTail;
  139. DBG_GDI((3, "vAddSurfToList add psurf=0x%x as the tail", psurf));
  140. //
  141. // Add this psurf to the end
  142. //
  143. pTail->psurfNext = psurf;
  144. psurf->psurfPrev = pTail;
  145. ppdev->psurfListTail = psurf;
  146. DBG_GDI((6, "vAddSurfToList done: psurf->psurfPrev=0x%x",
  147. psurf->psurfPrev));
  148. }
  149. psurf->flags |= SF_LIST;
  150. }// vAddSurfToList()
  151. //-----------------------------------------------------------------------------
  152. //
  153. // void vShiftSurfToListEnd(PPDev ppdev, Surf* psurf)
  154. //
  155. // Shifts the surface from its current position in the surface list to the
  156. // end of surface list
  157. //
  158. //-----------------------------------------------------------------------------
  159. VOID
  160. vShiftSurfToListEnd(PPDev ppdev, Surf* psurf)
  161. {
  162. //@@BEGIN_DDKSPLIT
  163. ASSERTLOCK(ppdev, vShiftSurfToListEnd);
  164. //@@END_DDKSPLIT
  165. Surf* pTail = ppdev->psurfListTail;
  166. DBG_GDI((6, "vShiftSurfToListEnd psurf=0x%x, pTail=0x%x", psurf, pTail));
  167. //
  168. // We don't need to shift a NULL psurf or the psurf is already at the end
  169. // of our surface list
  170. //
  171. if ( (psurf != NULL) && (psurf != pTail) )
  172. {
  173. Surf* pHead = ppdev->psurfListHead;
  174. DBG_GDI((6, "vShiftSurfToListEnd pHead=0x%x, pTail=0x%x",
  175. pHead, pTail));
  176. if ( psurf == pHead )
  177. {
  178. //
  179. // The surf is the first one in our list.
  180. // So, first we shift the head and let it points to the next one
  181. // in the list
  182. //
  183. ppdev->psurfListHead = psurf->psurfNext;
  184. ppdev->psurfListHead->psurfPrev = NULL;
  185. //
  186. // Let the tail point to this psurf
  187. //
  188. pTail->psurfNext = psurf;
  189. psurf->psurfPrev = pTail;
  190. psurf->psurfNext = NULL;
  191. ppdev->psurfListTail = psurf;
  192. DBG_GDI((6,"1st shifted. New pHead=0x%x", ppdev->psurfListHead));
  193. }// psurf is the 1st one in the list
  194. else
  195. {
  196. //
  197. // The surface is in the middle of the surface list
  198. //
  199. Surf* psurfPrev = psurf->psurfPrev;
  200. Surf* psurfNext = psurf->psurfNext;
  201. DBG_GDI((6, "vShiftSurfToListEnd psurfPrev=0x%x, psurfNext=0x%x",
  202. psurfPrev, psurfNext));
  203. psurfPrev->psurfNext = psurfNext;
  204. psurfNext->psurfPrev = psurfPrev;
  205. //
  206. // Add this psurf to the end
  207. //
  208. pTail->psurfNext = psurf;
  209. psurf->psurfPrev = pTail;
  210. psurf->psurfNext = NULL;
  211. ppdev->psurfListTail = psurf;
  212. }// Normal position
  213. }// psurf is NULL or already at the end
  214. }// vShiftSurfToListEnd()
  215. //-----------------------------------------------------------------------------
  216. //
  217. // void vSurfUsed
  218. //
  219. // Informs the heap manager that the surface has been accessed.
  220. //
  221. // Surface access patterns are the only hint that the heap manager receives
  222. // about the usage pattern of surfaces. From this limited information, the
  223. // heap manager must decide what surfaces to throw out of video memory when
  224. // the amount of available video memory reaches zero.
  225. //
  226. // For now, we will implement a LRU algorithm by placing any accessed
  227. // surfaces at the tail of the surface list.
  228. //
  229. //-----------------------------------------------------------------------------
  230. VOID
  231. vSurfUsed(PPDev ppdev, Surf* psurf)
  232. {
  233. //@@BEGIN_DDKSPLIT
  234. #if MULTITHREADED
  235. if(ppdev->ulLockCount)
  236. {
  237. DBG_GDI((MT_LOG_LEVEL, "vSurfUsed: re-entered! %d", ppdev->ulLockCount));
  238. }
  239. EngAcquireSemaphore(ppdev->hsemLock);
  240. ppdev->ulLockCount++;
  241. #endif
  242. //@@END_DDKSPLIT
  243. if( psurf->flags & SF_LIST )
  244. {
  245. // shift any surface that we have allocated to the end of the
  246. // list
  247. vShiftSurfToListEnd(ppdev, psurf);
  248. }
  249. //@@BEGIN_DDKSPLIT
  250. #if MULTITHREADED
  251. ppdev->ulLockCount--;
  252. EngReleaseSemaphore(ppdev->hsemLock);
  253. #endif
  254. //@@END_DDKSPLIT
  255. }// vSurfUsed()
  256. //-----------------------------------------------------------------------------
  257. //
  258. // This function copies the bits from off-screen memory to the DIB
  259. //
  260. // Parameters
  261. // ppdev-----------PPDEV
  262. // pvSrc-----------Source pointer in the off-screen bitmap
  263. // lBytesToUpLoad--Number of bytes to upload
  264. // pvDst-----------Destination pointer in the DIB
  265. //
  266. //-----------------------------------------------------------------------------
  267. VOID
  268. vUpload(PPDev ppdev,
  269. void* pvSrc,
  270. LONG lBytesToUpLoad,
  271. void* pvDst)
  272. {
  273. LONG lBytesAvailable;
  274. DWORD srcData;
  275. BYTE* pBitmapByte;
  276. USHORT* pBitmapShort;
  277. ULONG* pBitmapLong;
  278. LONG lNumOfPixel;
  279. PERMEDIA_DECL;
  280. DBG_GDI((7, "vUploadRect called"));
  281. DBG_GDI((3, "%ld bytes need to be uploaded at %x\n",
  282. lBytesToUpLoad, pvSrc));
  283. //@@BEGIN_DDKSPLIT
  284. ASSERTLOCK(ppdev, vUpload);
  285. #if MULTITHREADED && DBG
  286. ppdev->pP2dma->ppdev = ppdev;
  287. #endif
  288. //@@END_DDKSPLIT
  289. #if !defined(DMA_NOTWORKING)
  290. if(ppdev->bGdiContext)
  291. {
  292. InputBufferSync(ppdev);
  293. }
  294. else
  295. {
  296. vSyncWithPermedia(ppdev->pP2dma);
  297. }
  298. memcpy(pvDst, pvSrc, lBytesToUpLoad);
  299. #else
  300. P2_DEFAULT_FB_DEPTH;
  301. //
  302. // Set up the relevant units correctly
  303. // ColorDDAMode is DISABLED at initialisation time so there is no need
  304. // to re-load it here.
  305. //
  306. WAIT_INPUT_FIFO(3);
  307. SEND_TAG_DATA(LogicalOpMode, __PERMEDIA_DISABLE);
  308. SEND_TAG_DATA(FBWriteMode, __PERMEDIA_DISABLE); // In "read" mode
  309. SEND_TAG_DATA(FBReadMode, (permediaInfo->FBReadMode
  310. |__FB_READ_DESTINATION
  311. |__FB_COLOR));
  312. //
  313. // Enable filter mode so we can get Sync and color messages on the output
  314. // FIFO
  315. //
  316. data.Word = 0;
  317. data.FilterMode.Synchronization = __PERMEDIA_FILTER_TAG;
  318. data.FilterMode.Color = __PERMEDIA_FILTER_DATA;
  319. SEND_TAG_DATA(FilterMode, data.Word);
  320. DEXE_INPUT_FIFO();
  321. DBG_GDI((7, "pvDst = %x", pvDst));
  322. switch ( ppdev->cPelSize )
  323. {
  324. case 0:
  325. //
  326. // Initialise current pointer
  327. //
  328. pBitmapByte = (BYTE*)pvDst;
  329. lNumOfPixel = lPixelsToUpLoad;
  330. //
  331. // Loop to read in all the "lNumOfPixel" bytes
  332. //
  333. while ( lNumOfPixel > 0 )
  334. {
  335. //
  336. // Get number of bytes available in the FIFO
  337. //
  338. WAIT_OUTPUT_FIFO_NOT_EMPTY(lBytesAvailable);
  339. //
  340. // Decrease the total number of bytes we need to read
  341. //
  342. lNumOfPixel -= lBytesAvailable;
  343. //
  344. // We don't want to over read. Reset "lBytesAvailable" if we
  345. // have more available in the FIFO than we required
  346. //
  347. if ( lNumOfPixel < 0 )
  348. {
  349. lBytesAvailable += lNumOfPixel;
  350. }
  351. //
  352. // Read in "lBytesAvailable" bytes
  353. //
  354. while ( --lBytesAvailable >= 0 )
  355. {
  356. READ_OUTPUT_FIFO(srcData);
  357. *pBitmapByte++ = (BYTE)srcData;
  358. }
  359. }// while ( lNumOfPixel > 0 )
  360. break;
  361. case 1:
  362. //
  363. // Initialise current pointer
  364. //
  365. pBitmapShort = (USHORT*)pvDst;
  366. lNumOfPixel = lPixelsToUpLoad;
  367. while ( lNumOfPixel > 0 )
  368. {
  369. WAIT_OUTPUT_FIFO_NOT_EMPTY(lBytesAvailable);
  370. lNumOfPixel -= lBytesAvailable;
  371. if ( lNumOfPixel < 0 )
  372. {
  373. lBytesAvailable += lNumOfPixel;
  374. }
  375. while ( --lBytesAvailable >= 0 )
  376. {
  377. READ_OUTPUT_FIFO(srcData);
  378. *pBitmapShort++ = (USHORT)srcData;
  379. }
  380. }
  381. break;
  382. case 2:
  383. //
  384. // True color mode, use DWORD as reading UNIT, here pBitmapLong
  385. // points to the destination address, that is, the BMP data address
  386. // in main memory
  387. //
  388. pBitmapLong = (ULONG*)pvDst;
  389. lNumOfPixel = lPixelsToUpLoad;
  390. //
  391. // Loop until we upload all the pixels
  392. //
  393. while ( lNumOfPixel > 0 )
  394. {
  395. //
  396. // Wait until we have something to read
  397. //
  398. WAIT_OUTPUT_FIFO_NOT_EMPTY(lBytesAvailable);
  399. //
  400. // Check here to guarntee that we don't read more than we
  401. // asked for
  402. //
  403. lNumOfPixel -= lBytesAvailable;
  404. if ( lNumOfPixel < 0 )
  405. {
  406. lBytesAvailable += lNumOfPixel;
  407. }
  408. //
  409. // Read all these available BYTES, READ_OUTPUT_FIFO, in FIFO
  410. // to main memory
  411. //
  412. while ( --lBytesAvailable >= 0 )
  413. // while ( lBytesAvailable > 0 )
  414. {
  415. READ_OUTPUT_FIFO(*pBitmapLong);
  416. ++pBitmapLong;
  417. // lBytesAvailable -= 4;
  418. }
  419. }
  420. break;
  421. }// switch ( ppdev->cPelSize )
  422. //
  423. // Don't bother with a WAIT_INPUT_FIFO, as we know FIFO is empty.
  424. // We need to reset the chip back to its standard state. This
  425. // means: enable FB writes and set the filter mode back to allow
  426. // only syncs through.
  427. //
  428. WAIT_INPUT_FIFO(2);
  429. SEND_TAG_DATA(FBWriteMode, permediaInfo->FBWriteMode);
  430. SEND_TAG_DATA(FilterMode, 0);
  431. EXE_INPUT_FIFO();
  432. DBG_GDI((7, "vUploadRectNative: done"));
  433. #endif
  434. }// vUpload()
  435. //---------------------------------------------------------------------------
  436. //
  437. // ULONG ulVidMemAllocate
  438. //
  439. // This function allocates "lWidth" by "lHeight" bytes of video memory
  440. //
  441. // Parameters:
  442. // ppdev----------PPDEV
  443. // lWidth---------Width of the memory to allocate
  444. // lHeight--------Height of the memory to allocate
  445. // lPelSize-------Pixel Size of memory chunk
  446. // plDelta--------lDelta of this memory chunk
  447. // ppvmHeap-------Pointer to a video memory heap, local or non-local etc.
  448. // pulPackedPP----Packed products
  449. // bDiscardable---TRUE if the surface can be discarded if needed
  450. //
  451. //--------------------------------------------------------------------------
  452. ULONG
  453. ulVidMemAllocate(PDev* ppdev,
  454. LONG lWidth,
  455. LONG lHeight,
  456. LONG lPelSize,
  457. LONG* plDelta,
  458. VIDEOMEMORY** ppvmHeap,
  459. ULONG* pulPackedPP,
  460. BOOL bDiscardable )
  461. {
  462. ULONG iHeap;
  463. VIDEOMEMORY* pvmHeap;
  464. ULONG ulByteOffset;
  465. LONG lDelta;
  466. LONG lNewDelta;
  467. ULONG packedPP;
  468. SURFACEALIGNMENT alignment; // DDRAW heap management allignment stru
  469. //
  470. // Dont allocate any video memory on NT40, just let GDI do all the
  471. // allocating.
  472. //
  473. if(g_bOnNT40)
  474. return 0;
  475. memset(&alignment, 0, sizeof(alignment));
  476. //
  477. // Calculate lDelta and partical products based on lWidth
  478. // The permedia has surface width restrictions that must be met
  479. //
  480. vCalcPackedPP(lWidth, &lDelta, &packedPP);
  481. lDelta <<= lPelSize;
  482. //
  483. // Set alignment requirements
  484. // - must start at an pixel address
  485. // - pitch needs to be lDelta
  486. //
  487. alignment.Linear.dwStartAlignment = ppdev->cjPelSize;
  488. alignment.Linear.dwPitchAlignment = lDelta;
  489. //
  490. // Indicate that this allocation can be discarded if a DDraw/D3D
  491. // app really needs the memory
  492. //
  493. if( bDiscardable )
  494. {
  495. alignment.Linear.dwFlags = SURFACEALIGN_DISCARDABLE;
  496. }
  497. //
  498. // Loop through all the heaps to find available memory
  499. // Note: This ppdev->cHeap info was set in DrvGetDirectDrawInfo
  500. // when the driver is initialized
  501. //
  502. for ( iHeap = 0; iHeap < ppdev->cHeaps; iHeap++ )
  503. {
  504. pvmHeap = &ppdev->pvmList[iHeap];
  505. //
  506. // Since we are using DDRAW run time heap management code. It is
  507. // possible that the heap hasn't been initialized. For example, if
  508. // we fail in DrvEnableDirectDraw(), then the system won't initialize
  509. // the heap for us
  510. //
  511. if ( pvmHeap == NULL )
  512. {
  513. DBG_GDI((1, "Video memory hasn't been initialzied"));
  514. return 0;
  515. }
  516. //
  517. // AGP memory could be potentially used for device-bitmaps, with
  518. // two very large caveats:
  519. //
  520. // 1. No kernel-mode view is made for the AGP memory (would take
  521. // up too many PTEs and too much virtual address space).
  522. // No user-mode view is made either unless a DirectDraw
  523. // application happens to be running. Consequently, neither
  524. // GDI nor the driver can use the CPU to directly access the
  525. // bits. (It can be done through the accelerator, however.)
  526. //
  527. // 2. AGP heaps never shrink their committed allocations. The
  528. // only time AGP memory gets de-committed is when the entire
  529. // heap is empty. And don't forget that committed AGP memory
  530. // is non-pageable. Consequently, if you were to enable a
  531. // 50 MB AGP heap for DirectDraw, and were sharing that heap
  532. // for device bitmap allocations, after running a D3D game
  533. // the system would never be able to free that 50 MB of non-
  534. // pageable memory until every single device bitmap was deleted!
  535. // Just watch your Winstone scores plummet if someone plays
  536. // a D3D game first.
  537. //
  538. if ( !(pvmHeap->dwFlags & VIDMEM_ISNONLOCAL) )
  539. {
  540. //
  541. // Ask DDRAW heap management to allocate memory for us
  542. //
  543. ulByteOffset = (ULONG)HeapVidMemAllocAligned(pvmHeap,
  544. lDelta,
  545. lHeight,
  546. &alignment,
  547. &lNewDelta);
  548. DBG_GDI((3, "allocate %d bytes----got memory offset %ld real %x",
  549. lWidth * ppdev->cjPelSize * lHeight,
  550. ulByteOffset, (VOID*)(ppdev->pjScreen + ulByteOffset)));
  551. if ( ulByteOffset != 0 )
  552. {
  553. ASSERTDD(lDelta == lNewDelta,
  554. "ulVidMemAllocate: deltas don't match");
  555. *ppvmHeap = pvmHeap;
  556. *plDelta = lDelta;
  557. *pulPackedPP = packedPP;
  558. //
  559. // We are done
  560. //
  561. return (ulByteOffset);
  562. }// if ( pdsurf != NULL )
  563. }// if (!(pvmHeap->dwFlags & VIDMEM_ISNONLOCAL))
  564. }// loop through all the heaps to see if we can find available memory
  565. return 0;
  566. }// ulVidMemAllocate()
  567. //---------------------------------------------------------------------------
  568. //
  569. // VOID vDeleteSurf(DSURF* pdsurf)
  570. //
  571. // This routine frees a DSURF structure and the video or system memory inside
  572. // this DSURF
  573. //
  574. //----------------------------------------------------------------------------
  575. VOID
  576. vDeleteSurf(Surf* psurf)
  577. {
  578. DBG_GDI((6, "vDeleteSurf called with pdsurf =0x%x", psurf));
  579. //
  580. // Validate input parameters
  581. //
  582. if ( psurf == NULL )
  583. {
  584. DBG_GDI((3, "vDeleteSurf do nothing because pdsurf is NULL\n"));
  585. return;
  586. }
  587. //
  588. // Note: we don't need to call EngDeleteSurface(psurf->hsurf) to delete
  589. // the HBITMAP we created in DrvCreateDeviceBitmap() or DrvDeriveSurface()
  590. // because GDI will take care of this when it call DrvDeleteDeviceBitmap
  591. //
  592. if ( psurf->flags & SF_ALLOCATED )
  593. {
  594. if( psurf->flags & SF_SM )
  595. {
  596. ENGFREEMEM(psurf->pvScan0);
  597. }
  598. else
  599. {
  600. ASSERTDD(psurf->flags & SF_VM, "expected video memeory surface");
  601. //
  602. // Update the uniqueness to show that space has been freed, so
  603. // that we may decide to see if some DIBs can be moved back into
  604. // off-screen memory:
  605. //
  606. psurf->ppdev->iHeapUniq++;
  607. //
  608. // Free the video memory by specifing which heap and the pointer
  609. // to the chunk of video memory
  610. //
  611. DBG_GDI((3, "Free offset %ld from video mem\n", psurf->ulByteOffset));
  612. VidMemFree(psurf->pvmHeap->lpHeap, (FLATPTR)psurf->ulByteOffset);
  613. }// It is video memory
  614. }
  615. //
  616. // Free the GDI wrap around video memory
  617. //
  618. ENGFREEMEM(psurf);
  619. return;
  620. }// vDeleteSurf()
  621. //--------------------------------------------------------------------------
  622. //
  623. // pCreateSurf(PDEV* ppdev, LONG lWidth, LONG lHeight)
  624. // This routine returns allocates a chunk of video memory and returns a DSURF*
  625. //
  626. // Parameters:
  627. // ppdev-------PDEV*
  628. // lWidth------Width of the bitmap to be allocated
  629. // lHeight-----Height of the bitmap to be allocated
  630. //
  631. //--------------------------------------------------------------------------
  632. Surf*
  633. pCreateSurf(PDev* ppdev,
  634. LONG lWidth,
  635. LONG lHeight)
  636. {
  637. ULONG ulByteOffset;
  638. Surf* psurf;
  639. LONG lDelta;
  640. ULONG ulPackedPP;
  641. VIDEOMEMORY* pvmHeap;
  642. //
  643. // First, try to get video memory
  644. //
  645. ulByteOffset = ulVidMemAllocate(ppdev,
  646. lWidth, lHeight, ppdev->cPelSize,
  647. &lDelta, &pvmHeap, &ulPackedPP, TRUE);
  648. if ( ulByteOffset != 0 )
  649. {
  650. //
  651. // Use system memory to allocate a wrap (DSURF) so that gdi
  652. // can track all the info later
  653. //
  654. psurf = (Surf*)ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(Surf),
  655. ALLOC_TAG);
  656. if ( psurf != NULL )
  657. {
  658. DBG_GDI((3, "pdsurf is %x\n", psurf));
  659. //
  660. // Fill up the DSURF structure and our job is done
  661. //
  662. psurf->flags = SF_VM | SF_ALLOCATED;
  663. psurf->ppdev = ppdev;
  664. psurf->cx = lWidth;
  665. psurf->cy = lHeight;
  666. psurf->ulByteOffset = ulByteOffset;
  667. psurf->pvmHeap = pvmHeap;
  668. psurf->lDelta = lDelta;
  669. psurf->ulPackedPP = ulPackedPP;
  670. psurf->ulPixOffset = (ULONG)(ulByteOffset >> ppdev->cPelSize);
  671. psurf->ulPixDelta = lDelta >> ppdev->cPelSize;
  672. psurf->psurfNext = NULL;
  673. psurf->psurfPrev = NULL;
  674. //
  675. // We are done
  676. //
  677. return(psurf);
  678. }// if ( pdsurf != NULL )
  679. //
  680. // Something weird happened that we can't get memory from
  681. // the system. We should free the video memory before quit
  682. //
  683. VidMemFree(pvmHeap->lpHeap, (FLATPTR)ulByteOffset);
  684. }// if ( ulByteOffset != 0 )
  685. return (NULL);
  686. }// pCreateSurf()
  687. //---------------------------------------------------------------------------
  688. //
  689. // BOOL bMoveOldestBMPOut
  690. //
  691. // This routine moves the oldest DFB in the video memory to the system memory
  692. // and store it as a DIB
  693. //
  694. //---------------------------------------------------------------------------
  695. BOOL
  696. bMoveOldestBMPOut(PDev* ppdev)
  697. {
  698. BOOL bResult = FALSE;
  699. if(ppdev->psurfListHead != NULL)
  700. bResult = bDemote(ppdev->psurfListHead);
  701. return bResult;
  702. }// bMoveOldestBMPOut()
  703. //--------------------------Public*Routine-------------------------------------
  704. //
  705. // HBITMAP DrvCreateDeviceBitmap
  706. //
  707. // Function called by GDI to create a device-format-bitmap (DFB). We will
  708. // always try to allocate the bitmap in off-screen; if we can't, we simply
  709. // fail the call and GDI will create and manage the bitmap itself.
  710. //
  711. // Note: We do not have to zero the bitmap bits. GDI will automatically
  712. // call us via DrvBitBlt to zero the bits (which is a security
  713. // consideration).
  714. //
  715. // Parameters:
  716. // dhpdev---Identifies the PDEV that describes the physical device that an
  717. // application has designated as the primary target for a bitmap. The
  718. // format of the bitmap must be compatible with this physical device.
  719. // sizl-----Specifies the height and width of the desired bitmap, in pixels.
  720. // iFormat--Specifies the bitmap format, which indicates the required number of
  721. // bits of color information per pixel. This value can be one of the
  722. // following: Value Meaning
  723. // BMF_1BPP Monochrome.
  724. // BMF_4BPP 4 bits per pixel.
  725. // BMF_8BPP 8 bits per pixel.
  726. // BMF_16BPP 16 bits per pixel.
  727. // BMF_24BPP 24 bits per pixel.
  728. // BMF_32BPP 32 bits per pixel.
  729. // BMF_4RLE 4 bits per pixel; run length encoded.
  730. // BMF_8RLE 8 bits per pixel; run length encoded.
  731. //
  732. // Return Value:
  733. // The return value is a handle that identifies the created bitmap if the
  734. // function is successful. If the driver chooses to let GDI create and manage
  735. // the bitmap, the return value is zero. If an error occurs, the return value
  736. // is 0xFFFFFFFF, and GDI logs an error code.
  737. //
  738. //------------------------------------------------------------------------------
  739. HBITMAP
  740. DrvCreateDeviceBitmap(DHPDEV dhpdev,
  741. SIZEL sizl,
  742. ULONG iFormat)
  743. {
  744. PDev* ppdev = (PDev*)dhpdev;
  745. Surf* psurf;
  746. HBITMAP hbmDevice = NULL;
  747. BYTE* pjSurface;
  748. PERMEDIA_DECL;
  749. DBG_GDI((6, "DrvCreateDeviceBitmap()called"));
  750. //
  751. // First check If we're in full-screen mode ( ppdev->bEnabled = FALSE )
  752. // If yes, we hardly have any off-screen memory in which to allocate a DFB.
  753. // LATER: We could still allocate an OH node and put the bitmap on the DIB
  754. // DFB list for later promotion.
  755. // Also check that off-screen DFBs are configured ( STAT_DEV_BITMAPS). This
  756. // flag is turned off in bCheckHighResolutionCapability() (enable.c) when
  757. // the resolution is too high for the accelerator
  758. //
  759. // if ( !ppdev->bEnabled || !(ppdev->flStatus & STAT_DEV_BITMAPS) )
  760. if ( !ppdev->bEnabled )
  761. {
  762. DBG_GDI((2, "DrvCreateDeviceBitmap(): return 0, full screen mode"));
  763. return (0);
  764. }
  765. //
  766. // Second check If we're in DirectDraw exclusive mode
  767. //
  768. if ( ppdev->bDdExclusiveMode )
  769. {
  770. DBG_GDI((2, "DrvCreateDeviceBitmap(): return 0, DirectDraw exclusive mode"));
  771. return (0);
  772. }
  773. //
  774. // We only support device bitmaps that are the same colour depth
  775. // as our display.
  776. //
  777. // Actually, those are the only kind GDI will ever call us with,
  778. // but we may as well check. Note that this implies you'll never
  779. // get a crack at 1bpp bitmaps.
  780. //
  781. if ( iFormat != ppdev->iBitmapFormat )
  782. {
  783. DBG_GDI((2, "DrvCreateDeviceBitmap(): can't create bmp of format %d size(%d,%d)",
  784. iFormat, sizl.cx, sizl.cy));
  785. DBG_GDI((2, "only bitmaps of format %d supported!",
  786. ppdev->iBitmapFormat));
  787. return (0);
  788. }
  789. //
  790. // We don't want anything 8x8 or smaller -- they're typically brush
  791. // patterns which we don't particularly want to stash in off-screen
  792. // memory:
  793. //
  794. // Note if you're tempted to extend this philosophy to surfaces
  795. // larger than 8x8: in NT5, software cursors will use device-bitmaps
  796. // when possible, which is a big win when they're in video-memory
  797. // because we avoid the horrendous reads from video memory whenever
  798. // the cursor has to be redrawn. But the problem is that these
  799. // are small! (Typically 16x16 to 32x32.)
  800. //
  801. if ( (sizl.cx <= 8) && (sizl.cy <= 8) )
  802. {
  803. DBG_GDI((2, "DrvCreateDeviceBitmap rtn 0 because BMP size is small"));
  804. return (0);
  805. }
  806. else if ( ((sizl.cx >= 2048) || (sizl.cy >= 1024)) )
  807. {
  808. //
  809. // On Permedia don't create anything bigger than we can rasterize
  810. // because the rasteriser cannot handle coordinates higher than these
  811. //
  812. DBG_GDI((2, "DrvCreateDeviceBitmap rtn 0 for BMP too large %d %d",
  813. sizl.cx, sizl.cy));
  814. return (0);
  815. }
  816. //@@BEGIN_DDKSPLIT
  817. #if MULTITHREADED
  818. if(ppdev->ulLockCount)
  819. {
  820. DBG_GDI((MT_LOG_LEVEL, "DrvCreateDeviceBitmap: re-entered! %d", ppdev->ulLockCount));
  821. }
  822. EngAcquireSemaphore(ppdev->hsemLock);
  823. ppdev->ulLockCount++;
  824. #endif
  825. //@@END_DDKSPLIT
  826. //
  827. // Allocate a chunk of video memory for storing this bitmap
  828. //
  829. do
  830. {
  831. psurf = pCreateSurf(ppdev, sizl.cx, sizl.cy);
  832. if ( psurf != NULL )
  833. {
  834. //
  835. // Create a GDI wrap of a device managed bitmap
  836. //
  837. hbmDevice = EngCreateDeviceBitmap((DHSURF)psurf, sizl, iFormat);
  838. if ( hbmDevice != NULL )
  839. {
  840. //
  841. // Since we're running on a card that can map all of off-screen
  842. // video-memory, give a pointer to the bits to GDI so that
  843. // it can draw directly on the bits when it wants to.
  844. //
  845. // Note that this requires that we hook DrvSynchronize and
  846. // set HOOK_SYNCHRONIZE.
  847. //
  848. pjSurface = psurf->ulByteOffset + ppdev->pjScreen;
  849. DBG_GDI((3, "width=%ld pel=%ld, pjSurface=%x",
  850. sizl.cy, ppdev->cjPelSize, pjSurface));
  851. ULONG flags = MS_NOTSYSTEMMEMORY;
  852. //@@BEGIN_DDKSPLIT
  853. #if MULTITHREADED
  854. flags |= MS_SHAREDACCESS;
  855. #endif
  856. //@@END_DDKSPLIT
  857. if ( EngModifySurface((HSURF)hbmDevice,
  858. ppdev->hdevEng,
  859. ppdev->flHooks,
  860. flags,
  861. (DHSURF)psurf,
  862. pjSurface,
  863. psurf->lDelta,
  864. NULL))
  865. {
  866. psurf->hsurf = (HSURF)hbmDevice;
  867. vAddSurfToList(ppdev, psurf);
  868. DBG_GDI((6, "DrvCteDeviceBmp succeed, hsurf=%x, dsurf=%x",
  869. hbmDevice, psurf));
  870. vLogSurfCreated(psurf);
  871. break;
  872. }// if ( EngAssociateSurface() )
  873. DBG_GDI((0, "DrvCreateDeviceBitmap,EngModifySurface failed"));
  874. //
  875. // Since associate surface failed, we should delete the surface
  876. //
  877. EngDeleteSurface((HSURF)hbmDevice);
  878. hbmDevice = NULL;
  879. }// if ( hbmDevice != NULL )
  880. //
  881. // Failed in CreateDeviceBitmap, we should free all the memory
  882. //
  883. vDeleteSurf(psurf);
  884. DBG_GDI((0, "DrvCreateDeviceBitmap,EngCreateDeviceBitmap failed"));
  885. break;
  886. }// if ( pdsurf != NULL )
  887. } while (bMoveOldestBMPOut(ppdev));
  888. #if DBG
  889. if(hbmDevice == NULL)
  890. {
  891. DBG_GDI((1, "DrvCreateDeviceBitmap failed, no memory"));
  892. }
  893. #endif
  894. //@@BEGIN_DDKSPLIT
  895. #if MULTITHREADED
  896. ppdev->ulLockCount--;
  897. EngReleaseSemaphore(ppdev->hsemLock);
  898. #endif
  899. //@@END_DDKSPLIT
  900. return (hbmDevice);
  901. }// DrvCreateDeviceBitmap()
  902. //--------------------------Public*Routine-------------------------------------
  903. //
  904. // VOID DrvDeleteDeviceBitmap()
  905. //
  906. // This function deletes a device bitmap created by DrvCreateDeviceBitmap
  907. //
  908. // Parameters
  909. // dhsurf------Identifies the bitmap to be deleted. This handle identifies the
  910. // bitmap created by DrvCreateDeviceBitmap.
  911. //
  912. // Comments
  913. // A display driver must implement DrvDeleteDeviceBitmap if it supplies
  914. // DrvCreateDeviceBitmap.
  915. //
  916. // GDI will never pass this function a DHSURF which is the same as the
  917. // screen (Surf*)
  918. //
  919. //-----------------------------------------------------------------------------
  920. VOID
  921. DrvDeleteDeviceBitmap(DHSURF dhsurf)
  922. {
  923. Surf* psurf;
  924. PDev* ppdev;
  925. Surf* pCurrent;
  926. psurf = (Surf*)dhsurf;
  927. ppdev = psurf->ppdev;
  928. DBG_GDI((6, "DrvDeleteDeviceBitamp(%lx)", psurf));
  929. //@@BEGIN_DDKSPLIT
  930. #if MULTITHREADED
  931. if(ppdev->ulLockCount)
  932. {
  933. DBG_GDI((MT_LOG_LEVEL, "DrvDeleteDeviceBitmap: re-entered! %d", ppdev->ulLockCount));
  934. }
  935. EngAcquireSemaphore(ppdev->hsemLock);
  936. ppdev->ulLockCount++;
  937. #endif
  938. //@@END_DDKSPLIT
  939. vRemoveSurfFromList(ppdev, psurf);
  940. vLogSurfDeleted(psurf);
  941. vDeleteSurf(psurf);
  942. //@@BEGIN_DDKSPLIT
  943. #if MULTITHREADED
  944. ppdev->ulLockCount--;
  945. EngReleaseSemaphore(ppdev->hsemLock);
  946. #endif
  947. //@@END_DDKSPLIT
  948. }// DrvDeleteDeviceBitmap()
  949. //-----------------------------------------------------------------------------
  950. //
  951. // VOID vBlankScreen(PDev* ppdev)
  952. //
  953. // This function balnk the screen by setting the memory contents to zero
  954. //
  955. //-----------------------------------------------------------------------------
  956. VOID
  957. vBlankScreen(PDev* ppdev)
  958. {
  959. //
  960. // Synchronize the hardware first
  961. //
  962. if( ppdev->bGdiContext )
  963. {
  964. InputBufferSync(ppdev);
  965. }
  966. else
  967. {
  968. #if MULTITHREADED && DBG
  969. ppdev->pP2dma->ppdev = ppdev;
  970. #endif
  971. vSyncWithPermedia(ppdev->pP2dma);
  972. }
  973. //
  974. // Set the video memory contents, screen portion, to zero
  975. //
  976. memset(ppdev->pjScreen, 0x0,
  977. ppdev->cyScreen * ppdev->lDelta);
  978. }// vBlankScreen()
  979. //-----------------------------------------------------------------------------
  980. //
  981. // BOOL bAssertModeOffscreenHeap
  982. //
  983. // This function is called whenever we switch in or out of full-screen
  984. // mode. We have to convert all the off-screen bitmaps to DIBs when
  985. // we switch to full-screen (because we may be asked to draw on them even
  986. // when in full-screen, and the mode switch would probably nuke the video
  987. // memory contents anyway).
  988. //
  989. //-----------------------------------------------------------------------------
  990. BOOL
  991. bAssertModeOffscreenHeap(PDev* ppdev,
  992. BOOL bEnable)
  993. {
  994. BOOL bResult = TRUE;
  995. if ( !bEnable )
  996. {
  997. bResult = bDemoteAll(ppdev);
  998. //
  999. // We need to clean the screen. bAssertModeOffscreenHeap() is called
  1000. // when DrvAssertMode(FALSE), which means we either switch to a full
  1001. // screen DOS window or this PDEV will be deleted.
  1002. //
  1003. if ( bResult )
  1004. {
  1005. vBlankScreen(ppdev);
  1006. }
  1007. }
  1008. return bResult;
  1009. }// bAssertModeOffscreenHeap()
  1010. //-----------------------------------------------------------------------------
  1011. //
  1012. // VOID vDisableOffscreenHeap
  1013. //
  1014. // Frees any resources allocated by the off-screen heap.
  1015. //
  1016. //-----------------------------------------------------------------------------
  1017. VOID
  1018. vDisableOffscreenHeap(PDev* ppdev)
  1019. {
  1020. #if 0
  1021. ASSERTDD(ppdev->psurfListHead == NULL,
  1022. "vDisableOffscreenHeap: expected surface list to be empty");
  1023. ASSERTDD(ppdev->psurfListTail == NULL,
  1024. "vDisableOffscreenHeap: expected surface list to be empty");
  1025. #endif
  1026. }// vDisableOffscreenHeap()
  1027. //-----------------------------------------------------------------------------
  1028. //
  1029. // BOOL bEnableOffscreenHeap
  1030. //
  1031. // Off-screen heap initialization
  1032. //
  1033. //-----------------------------------------------------------------------------
  1034. BOOL
  1035. bEnableOffscreenHeap(PDev* ppdev)
  1036. {
  1037. DBG_GDI((6, "bEnableOffscreenHeap called"));
  1038. ppdev->psurfListHead = NULL;
  1039. ppdev->psurfListTail = NULL;
  1040. return TRUE;
  1041. }// bEnableOffscreenHeap()
  1042. //-----------------------------------------------------------------------------
  1043. //
  1044. // BOOL bDownLoad
  1045. //
  1046. // Download a GDI owned bmp (GOB) to the video memory if we have room on the
  1047. // video off-screen heap
  1048. //
  1049. // Returns: FALSE if there wasn't room, TRUE if successfully downloaded.
  1050. //
  1051. //-----------------------------------------------------------------------------
  1052. #if defined(AFTER_BETA3)
  1053. BOOL
  1054. bDownLoad(PDev* ppdev,
  1055. Surf* psurf)
  1056. {
  1057. ULONG ulByteOffset;
  1058. LONG lDelta;
  1059. ULONG ulPackedPP;
  1060. VIDEOMEMORY* pvmHeap;
  1061. DBG_GDI((6, "bDownLoad called with psurf 0x%x", psurf));
  1062. ASSERTDD(psurf->flags & SF_SM,
  1063. "Can't move a bitmap off-screen when it's already off-screen");
  1064. if ( !(psurf->flags & SF_ALLOCATED) )
  1065. {
  1066. return (FALSE);
  1067. }
  1068. //
  1069. // If we're in full-screen mode, we can't move anything to off-screen
  1070. // memory:
  1071. //
  1072. if ( !ppdev->bEnabled )
  1073. {
  1074. return(FALSE);
  1075. }
  1076. //
  1077. // If we're in DirectDraw exclusive mode, we can't move anything to
  1078. // off-screen memory:
  1079. //
  1080. if ( ppdev->bDdExclusiveMode )
  1081. {
  1082. return(FALSE);
  1083. }
  1084. //
  1085. // Allocate video memory first
  1086. //
  1087. ulByteOffset = ulVidMemAllocate(ppdev, psurf->cx, psurf->cy, ppdev->cPelSize,
  1088. &lDelta, &pvmHeap, &ulPackedPP, TRUE);
  1089. if ( ulByteOffset == 0 )
  1090. {
  1091. //
  1092. // No more free video memory, we have to return
  1093. //
  1094. DBG_GDI((1, "No more free video memory"));
  1095. return(FALSE);
  1096. }
  1097. ULONG flags = MS_NOTSYSTEMMEMORY; // It's video-memory
  1098. //@@BEGIN_DDKSPLIT
  1099. #if MULTITHREADED
  1100. flags |= MS_SHAREDACCESS;
  1101. #endif
  1102. //@@END_DDKSPLIT
  1103. if ( !EngModifySurface(psurf->hsurf,
  1104. ppdev->hdevEng,
  1105. ppdev->flHooks,
  1106. flags,
  1107. (DHSURF)psurf,
  1108. ulByteOffset + ppdev->pjScreen,
  1109. lDelta,
  1110. NULL))
  1111. {
  1112. //
  1113. // Failed in EngModifySurface, we should free the video memory we got
  1114. //
  1115. VidMemFree(psurf->pvmHeap->lpHeap, (FLATPTR)ulByteOffset);
  1116. return(FALSE);
  1117. }
  1118. //
  1119. // Download BMP from system memory to video memory
  1120. //
  1121. memcpy((void*)(ppdev->pjScreen + psurf->ulByteOffset),
  1122. psurf->pvScan0, lDelta * psurf->cy);
  1123. //
  1124. // Free the system memory
  1125. //
  1126. ENGFREEMEM(psurf->pvScan0);
  1127. //
  1128. // Change the attributes for this PDSURF data structures
  1129. //
  1130. psurf->flags &= ~SF_SM;
  1131. psurf->flags |= SF_VM;
  1132. psurf->ulByteOffset = ulByteOffset;
  1133. psurf->pvmHeap = pvmHeap;
  1134. psurf->lDelta = lDelta;
  1135. psurf->ulPackedPP = ulPackedPP;
  1136. psurf->ulPixOffset = (ULONG)(ulByteOffset >> ppdev->cPelSize);
  1137. psurf->ulPixDelta = lDelta >> ppdev->cPelSize;
  1138. psurf->psurfNext = NULL;
  1139. psurf->psurfPrev = NULL;
  1140. vAddSurfToList(ppdev, psurf);
  1141. return (TRUE);
  1142. }// bDownLoad()
  1143. #endif
  1144. //--------------------------Public Routine-------------------------------------
  1145. //
  1146. // HBITMAP DrvDeriveSurface
  1147. //
  1148. // This function derives and creates a GDI surface from the specified
  1149. // DirectDraw surface.
  1150. //
  1151. // Parameters
  1152. // pDirectDraw-----Points to a DD_DIRECTDRAW_GLOBAL structure that describes
  1153. // the DirectDraw object.
  1154. // pSurface--------Points to a DD_SURFACE_LOCAL structure that describes the
  1155. // DirectDraw surface around which to wrap a GDI surface.
  1156. //
  1157. // Return Value
  1158. // DrvDeriveSurface returns a handle to the created GDI surface upon success.
  1159. // It returns NULL if the call fails or if the driver cannot accelerate GDI
  1160. // drawing to the specified DirectDraw surface.
  1161. //
  1162. // Comments
  1163. // DrvDeriveSurface allows the driver to create a GDI surface around a
  1164. // DirectDraw video memory or AGP surface object in order to allow accelerated
  1165. // GDI drawing to the surface. If the driver does not hook this call, all GDI
  1166. // drawing to DirectDraw surfaces is done in software using the DIB engine.
  1167. //
  1168. // GDI calls DrvDeriveSurface with RGB surfaces only.
  1169. //
  1170. // The driver should call DrvCreateDeviceBitmap to create a GDI surface of the
  1171. // same size and format as that of the DirectDraw surface. Space for the
  1172. // actual pixels need not be allocated since it already exists.
  1173. //
  1174. //-----------------------------------------------------------------------------
  1175. HBITMAP
  1176. DrvDeriveSurface(DD_DIRECTDRAW_GLOBAL* pDirectDraw,
  1177. DD_SURFACE_LOCAL* pSurface)
  1178. {
  1179. PDev* ppdev;
  1180. Surf* psurf;
  1181. HBITMAP hbmDevice;
  1182. DD_SURFACE_GLOBAL* pSurfaceGlobal;
  1183. SIZEL sizl;
  1184. DBG_GDI((6, "DrvDeriveSurface: with pDirectDraw 0x%x, pSurface 0x%x",
  1185. pDirectDraw, pSurface));
  1186. ppdev = (PDev*)pDirectDraw->dhpdev;
  1187. pSurfaceGlobal = pSurface->lpGbl;
  1188. //
  1189. // GDI should never call us for a non-RGB surface, but let's assert just
  1190. // to make sure they're doing their job properly.
  1191. //
  1192. ASSERTDD(!(pSurfaceGlobal->ddpfSurface.dwFlags & DDPF_FOURCC),
  1193. "GDI called us with a non-RGB surface!");
  1194. // The GDI driver does not accelerate surfaces in AGP memory,
  1195. // thus we fail the call
  1196. if (pSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
  1197. {
  1198. DBG_GDI((6, "DrvDeriveSurface return NULL, surface in AGP memory"));
  1199. return 0;
  1200. }
  1201. // The GDI driver does not accelerate managed surface,
  1202. // thus we fail the call
  1203. if (pSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
  1204. {
  1205. DBG_GDI((6, "DrvDeriveSurface return NULL, surface is managed"));
  1206. return 0;
  1207. }
  1208. //
  1209. // The rest of our driver expects GDI calls to come in with the same
  1210. // format as the primary surface. So we'd better not wrap a device
  1211. // bitmap around an RGB format that the rest of our driver doesn't
  1212. // understand. Also, we must check to see that it is not a surface
  1213. // whose pitch does not match the primary surface.
  1214. //
  1215. // NOTE: Most surfaces created by this driver are allocated as 2D surfaces
  1216. // whose lPitch's are equal to the screen pitch. However, overlay surfaces
  1217. // are allocated such that there lPitch's are usually different then the
  1218. // screen pitch. The hardware can not accelerate drawing operations to
  1219. // these surfaces and thus we fail to derive these surfaces.
  1220. //
  1221. if ( (pSurfaceGlobal->ddpfSurface.dwRGBBitCount
  1222. == (DWORD)ppdev->cjPelSize * 8) )
  1223. {
  1224. psurf = (Surf*)ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(Surf), ALLOC_TAG);
  1225. if ( psurf != NULL )
  1226. {
  1227. sizl.cx = pSurfaceGlobal->wWidth;
  1228. sizl.cy = pSurfaceGlobal->wHeight;
  1229. hbmDevice = EngCreateDeviceBitmap((DHSURF)psurf,
  1230. sizl,
  1231. ppdev->iBitmapFormat);
  1232. if ( hbmDevice != NULL )
  1233. {
  1234. VOID* pvScan0;
  1235. if (pSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
  1236. {
  1237. // this actually is in user memory, so don't add offset
  1238. pvScan0 = (VOID *)pSurfaceGlobal->fpVidMem;
  1239. }
  1240. else
  1241. {
  1242. pvScan0 = ppdev->pjScreen + pSurfaceGlobal->fpVidMem;
  1243. }
  1244. //
  1245. // Note that HOOK_SYNCHRONIZE must always be hooked when we
  1246. // give GDI a pointer to the bitmap bits. We don't need to
  1247. // do it here since HOOK_SYNCHRONIZE is always set in our
  1248. // pdev->flHooks
  1249. //
  1250. ULONG flags = MS_NOTSYSTEMMEMORY;
  1251. //@@BEGIN_DDKSPLIT
  1252. #if MULTITHREADED
  1253. flags |= MS_SHAREDACCESS;
  1254. #endif
  1255. //@@END_DDKSPLIT
  1256. if ( EngModifySurface((HSURF)hbmDevice,
  1257. ppdev->hdevEng,
  1258. ppdev->flHooks,
  1259. flags,
  1260. (DHSURF)psurf,
  1261. pvScan0,
  1262. pSurfaceGlobal->lPitch,
  1263. NULL) )
  1264. {
  1265. ULONG ulPackedPP;
  1266. LONG lDelta;
  1267. psurf->hsurf = (HSURF)hbmDevice;
  1268. psurf->flags = SF_DIRECTDRAW | SF_VM;
  1269. psurf->ppdev = ppdev;
  1270. psurf->cx = pSurfaceGlobal->wWidth;
  1271. psurf->cy = pSurfaceGlobal->wHeight;
  1272. psurf->ulByteOffset= (ULONG)(pSurfaceGlobal->fpVidMem);
  1273. psurf->pvmHeap = pSurfaceGlobal->lpVidMemHeap;
  1274. psurf->psurfNext = NULL;
  1275. psurf->psurfPrev = NULL;
  1276. psurf->lDelta = pSurfaceGlobal->lPitch;
  1277. vCalcPackedPP(psurf->cx, &lDelta, &ulPackedPP);
  1278. psurf->ulPackedPP = ulPackedPP;
  1279. psurf->ulPixOffset = (ULONG)(psurf->ulByteOffset
  1280. >> ppdev->cPelSize);
  1281. psurf->ulPixDelta = psurf->lDelta
  1282. >> ppdev->cPelSize;
  1283. DBG_GDI((6, "DrvDeriveSurface return succeed"));
  1284. vLogSurfCreated(psurf);
  1285. if(MAKE_BITMAPS_OPAQUE)
  1286. {
  1287. SURFOBJ* surfobj = EngLockSurface((HSURF) hbmDevice);
  1288. ASSERTDD(surfobj->iType == STYPE_BITMAP,
  1289. "expected STYPE_BITMAP");
  1290. surfobj->iType = STYPE_DEVBITMAP;
  1291. EngUnlockSurface(surfobj);
  1292. }
  1293. return(hbmDevice);
  1294. }// EngModifySurface succeed
  1295. DBG_GDI((0, "DrvDeriveSurface: EngModifySurface failed"));
  1296. EngDeleteSurface((HSURF)hbmDevice);
  1297. }
  1298. DBG_GDI((0, "DrvDeriveSurface: EngAllocMem failed"));
  1299. ENGFREEMEM(psurf);
  1300. }// if ( pdsurf != NULL )
  1301. }// Check surface format
  1302. DBG_GDI((6, "DrvDeriveSurface return NULL"));
  1303. DBG_GDI((6,"pSurfaceGlobal->ddpfSurface.dwRGBBitCount = %d, lPitch =%ld",
  1304. pSurfaceGlobal->ddpfSurface.dwRGBBitCount,pSurfaceGlobal->lPitch));
  1305. DBG_GDI((6, "ppdev->cjPelSize * 8 = %d, lDelta =%d",
  1306. ppdev->cjPelSize * 8, ppdev->lDelta));
  1307. return(0);
  1308. }// DrvDeriveSurface()
  1309. //-----------------------------------------------------------------------------
  1310. //
  1311. // VOID vDemote
  1312. //
  1313. // Attempt to move the given surface from VM to SM
  1314. //
  1315. //-----------------------------------------------------------------------------
  1316. BOOL
  1317. bDemote(Surf * psurf)
  1318. {
  1319. LONG lDelta;
  1320. VOID* pvScan0;
  1321. BOOL bResult = FALSE;
  1322. ASSERTDD( psurf->flags & SF_VM, "source to be VM");
  1323. ASSERTDD( psurf->flags & SF_ALLOCATED, "source must have been allocated");
  1324. //
  1325. // Make the system-memory scans quadword aligned:
  1326. //
  1327. lDelta = (psurf->lDelta + 7) & ~7;
  1328. DBG_GDI((7, "Allocate %ld bytes in Eng, lDelta=%ld\n",
  1329. lDelta * psurf->cy, lDelta));
  1330. //
  1331. // Allocate system memory to hold the bitmap
  1332. // Note: there's no point in zero-initializing this memory:
  1333. //
  1334. pvScan0 = ENGALLOCMEM(0, lDelta * psurf->cy, ALLOC_TAG);
  1335. if ( pvScan0 != NULL )
  1336. {
  1337. //
  1338. // The following 'EngModifySurface' call tells GDI to
  1339. // modify the surface to point to system-memory for
  1340. // the bits, and changes what Drv calls we want to
  1341. // hook for the surface.
  1342. //
  1343. // By specifying the surface address, GDI will convert the
  1344. // surface to an STYPE_BITMAP surface (if necessary) and
  1345. // point the bits to the memory we just allocated. The
  1346. // next time we see it in a DrvBitBlt call, the 'dhsurf'
  1347. // field will still point to our 'pdsurf' structure.
  1348. //
  1349. // Note that we hook only CopyBits and BitBlt when we
  1350. // convert the device-bitmap to a system-memory surface.
  1351. // This is so that we don't have to worry about getting
  1352. // DrvTextOut, DrvLineTo, etc. calls on bitmaps that
  1353. // we've converted to system-memory -- GDI will just
  1354. // automatically do the drawing for us.
  1355. //
  1356. // However, we are still interested in seeing DrvCopyBits
  1357. // and DrvBitBlt calls involving this surface, because
  1358. // in those calls we take the opportunity to see if it's
  1359. // worth putting the device-bitmap back into video memory
  1360. // (if some room has been freed up).
  1361. //
  1362. if ( EngModifySurface(psurf->hsurf,
  1363. psurf->ppdev->hdevEng,
  1364. HOOK_COPYBITS | HOOK_BITBLT,
  1365. 0, // It's system-memory
  1366. (DHSURF)psurf,
  1367. pvScan0,
  1368. lDelta,
  1369. NULL))
  1370. {
  1371. //
  1372. // First, copy the bits from off-screen memory to the DIB
  1373. //
  1374. DBG_GDI((3, "Free %d bytes, offset %ld real %x",
  1375. lDelta * psurf->cy, psurf->ulByteOffset,
  1376. (VOID*)(psurf->ppdev->pjScreen + psurf->ulByteOffset)));
  1377. vUpload(psurf->ppdev, (void*)(psurf->ppdev->pjScreen + psurf->ulByteOffset),
  1378. lDelta * psurf->cy, pvScan0);
  1379. DBG_GDI((6, "bMoveOldest() free vidmem %ld",
  1380. psurf->ulByteOffset));
  1381. //
  1382. // Now free the off-screen memory:
  1383. //
  1384. VidMemFree(psurf->pvmHeap->lpHeap,
  1385. (FLATPTR)psurf->ulByteOffset);
  1386. vRemoveSurfFromList(psurf->ppdev, psurf);
  1387. //
  1388. // Setup the pdsurf properly because it is a DIB now
  1389. //
  1390. psurf->flags &= ~SF_VM;
  1391. psurf->flags |= SF_SM;
  1392. psurf->pvScan0 = pvScan0;
  1393. vLogSurfMovedToSM(psurf);
  1394. bResult = TRUE;
  1395. }// EngModifySurface()
  1396. else
  1397. {
  1398. //
  1399. // Somehow, EngModifySurface() failed. Free the memory
  1400. //
  1401. ENGFREEMEM(pvScan0);
  1402. ASSERTDD(0, "bMoveOldest() EngModifySurface failed\n");
  1403. }
  1404. }// if ( pvScan0 != NULL )
  1405. return bResult;
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. //
  1409. // VOID vPromote
  1410. //
  1411. // Attempt to move the given surface from SM to VM
  1412. //
  1413. //-----------------------------------------------------------------------------
  1414. VOID
  1415. vPromote(Surf * psurf)
  1416. {
  1417. ASSERTDD( psurf->flags & SF_VM, "source to be VM");
  1418. ASSERTDD( psurf->flags & SF_ALLOCATED, "source must have been allocated");
  1419. ASSERTDD(!psurf->ppdev->bDdExclusiveMode,
  1420. "cannot promote when DirectDraw is in exclusive mode");
  1421. // nothing for now
  1422. }
  1423. //-----------------------------------------------------------------------------
  1424. //
  1425. // BOOL bDemoteAll
  1426. //
  1427. // Attempts to move all surfaces to SM
  1428. //
  1429. //-----------------------------------------------------------------------------
  1430. BOOL
  1431. bDemoteAll(PPDev ppdev)
  1432. {
  1433. BOOL bRet;
  1434. //@@BEGIN_DDKSPLIT
  1435. #if MULTITHREADED
  1436. EngAcquireSemaphore(ppdev->hsemLock);
  1437. ppdev->ulLockCount++;
  1438. #endif
  1439. //@@END_DDKSPLIT
  1440. while (ppdev->psurfListHead != NULL)
  1441. if(!bDemote(ppdev->psurfListHead))
  1442. break;
  1443. bRet = (ppdev->psurfListHead == NULL);
  1444. //@@BEGIN_DDKSPLIT
  1445. #if MULTITHREADED
  1446. ppdev->ulLockCount--;
  1447. EngReleaseSemaphore(ppdev->hsemLock);
  1448. #endif
  1449. //@@END_DDKSPLIT
  1450. return bRet;
  1451. }