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.

1889 lines
70 KiB

  1. /****************************************************************************/
  2. // nddapi.c
  3. //
  4. // RDP DD exported functions.
  5. //
  6. // Copyright (c) 1996-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precmpdd.h>
  9. #define hdrstop
  10. #define TRC_FILE "nddapi"
  11. #include <adcg.h>
  12. #include <atrcapi.h>
  13. #include <winddi.h>
  14. #include <ndddata.c>
  15. #include <nddapi.h>
  16. #include <nshmapi.h>
  17. #include <nsbcdisp.h>
  18. #include <ncmdisp.h>
  19. #include <nwdwioct.h>
  20. #include <nschdisp.h>
  21. #include <nbadisp.h>
  22. #include <noadisp.h>
  23. #include <nssidisp.h>
  24. #include <noedisp.h>
  25. #include <nchdisp.h>
  26. #include <nddifn.h>
  27. #include <nbainl.h>
  28. #ifdef DC_DEBUG
  29. /****************************************************************************/
  30. /* Useful function for outputting lines to the debugger */
  31. /****************************************************************************/
  32. void DrvDebugPrint(char * str, ...)
  33. {
  34. va_list ap;
  35. va_start(ap, str);
  36. EngDebugPrint("RDPDD: ", str, ap);
  37. }
  38. void WDIcaBreakOnDebugger()
  39. {
  40. ULONG dummyBytesReturned;
  41. ULONG status;
  42. DC_BEGIN_FN("WDIcaBreakOnDebugger");
  43. status = EngFileIoControl( ddWdHandle,
  44. IOCTL_WDTS_DD_ICABREAKONDEBUGGER, 0, 0, 0, 0,
  45. &dummyBytesReturned);
  46. if (STATUS_SUCCESS != status) {
  47. TRC_ERR((TB, "IOCTL_WDTS_DD_ICABREAKONDEBUGGER returned %lu",
  48. status ));
  49. }
  50. DC_END_FN();
  51. }
  52. #endif
  53. /****************************************************************************/
  54. /* DrvEnableDriver - see NT DDK documentation. */
  55. /* */
  56. /* This is the only directly exported entry point to the display driver. */
  57. /* All other entry points are exported through the data returned from this */
  58. /* function. */
  59. /****************************************************************************/
  60. BOOL DrvEnableDriver(ULONG iEngineVersion, ULONG cj, DRVENABLEDATA *pded)
  61. {
  62. DC_BEGIN_FN("DrvEnableDriver");
  63. #ifdef DC_DEBUG
  64. // Initialize the trace level.
  65. ddTrcType = TT_API1 | TT_API2 | TT_API3 | TT_API4;
  66. DD_SET_STATE(DD_ENABLE_DRIVER);
  67. #endif
  68. #ifdef DDINT3
  69. _asm int 3;
  70. #endif
  71. // Check that the engine version is correct - we refuse to load on
  72. // other versions because we will almost certainly not work.
  73. if (iEngineVersion < DDI_DRIVER_VERSION_SP3)
  74. return FALSE;
  75. // Fill in as much as we can. Start with the entry points.
  76. if (cj >= FIELDOFFSET(DRVENABLEDATA, pdrvfn) +
  77. FIELDSIZE(DRVENABLEDATA, pdrvfn)) {
  78. pded->pdrvfn = (DRVFN *)ddDriverFns;
  79. TRC_DBG((TB, "Passing back driver functions %p", pded->pdrvfn));
  80. }
  81. // Size of our entry point array.
  82. if (cj >= FIELDOFFSET(DRVENABLEDATA, c) + FIELDSIZE(DRVENABLEDATA, c)) {
  83. pded->c = DD_NUM_DRIVER_INTERCEPTS;
  84. TRC_DBG((TB, "Passing back function count %lu", pded->c));
  85. }
  86. // DDI version this driver was targeted for is passed back to engine.
  87. // Future graphics engines may break calls down to old driver format.
  88. if (cj >= FIELDOFFSET(DRVENABLEDATA, iDriverVersion) +
  89. FIELDSIZE(DRVENABLEDATA, iDriverVersion)) {
  90. pded->iDriverVersion = DDI_DRIVER_VERSION_SP3;
  91. TRC_DBG((TB, "Using driver type %lu", pded->iDriverVersion));
  92. }
  93. TRC_NRM((TB, "Num driver intercepts: %d", DD_NUM_DRIVER_INTERCEPTS));
  94. DC_END_FN();
  95. return TRUE;
  96. }
  97. /****************************************************************************/
  98. // DrvDisableDriver - see NT DDK documentation.
  99. /****************************************************************************/
  100. VOID DrvDisableDriver(VOID)
  101. {
  102. DC_BEGIN_FN("DrvDisableDriver");
  103. // Release any resources allocated in DrvEnableDriver.
  104. TRC_NRM((TB, "DrvDisableDriver"));
  105. DDTerm();
  106. DC_END_FN();
  107. }
  108. /****************************************************************************/
  109. /* DrvEnablePDEV - see NT DDK documentation. */
  110. /* */
  111. /* Initializes a bunch of fields for GDI, based on the mode we've been */
  112. /* asked to do. This is the first thing called after DrvEnableDriver, when */
  113. /* GDI wants to get some information about us. */
  114. /* */
  115. /* (This function mostly returns back information; DrvEnableSurface is used */
  116. /* for initializing the hardware and driver components.) */
  117. /****************************************************************************/
  118. DHPDEV DrvEnablePDEV(
  119. DEVMODEW *pdm,
  120. PWSTR pwszLogAddr,
  121. ULONG cPat,
  122. HSURF *phsurfPatterns,
  123. ULONG cjCaps,
  124. ULONG *pdevcaps,
  125. ULONG cjDevInfo,
  126. DEVINFO *pdi,
  127. HDEV hdev,
  128. PWSTR pwszDeviceName,
  129. HANDLE hDriver)
  130. {
  131. DHPDEV rc = NULL;
  132. PDD_PDEV pPDev = NULL;
  133. GDIINFO gdiInfoNew;
  134. INT32 cModes;
  135. PVIDEO_MODE_INFORMATION pVideoModeInformation = NULL;
  136. INT32 cbModeSize;
  137. DC_BEGIN_FN("DrvEnablePDEV");
  138. // Make sure that we have large enough data to reference.
  139. if (cjCaps >= sizeof(GDIINFO) && cjDevInfo >= sizeof(DEVINFO)) {
  140. // Allocate a physical device structure; store the hDriver in it.
  141. pPDev = EngAllocMem(0, sizeof(DD_PDEV), DD_ALLOC_TAG);
  142. if (pPDev != NULL) {
  143. // Don't zero the palette since we'll be setting that up soon.
  144. memset(pPDev, 0, sizeof(DD_PDEV) - sizeof(pPDev->Palette));
  145. pPDev->hDriver = hDriver;
  146. }
  147. else {
  148. TRC_ERR((TB, "DrvEnablePDEV - Failed EngAllocMem"));
  149. DC_QUIT;
  150. }
  151. }
  152. else {
  153. TRC_ERR((TB, "Buffer size too small %lu %lu", cjCaps, cjDevInfo));
  154. DC_QUIT;
  155. }
  156. // Set up the current screen mode information based upon the supplied
  157. // mode settings.
  158. DDInitializeModeFields(pPDev, (GDIINFO *)pdevcaps, &gdiInfoNew, pdi, pdm);
  159. memcpy(pdevcaps, &gdiInfoNew, min(sizeof(GDIINFO), cjCaps));
  160. // Since DrvGetModes is only called when the DD is test-loaded, we must
  161. // get a mode count here so that we can determine if we're loaded into
  162. // the console session.
  163. cModes = DDGetModes(hDriver, &pVideoModeInformation, &cbModeSize);
  164. if (cModes == -1) {
  165. TRC_NRM((TB, "We are a chained console driver"));
  166. ddConsole = TRUE;
  167. // see DDK : must be set for a mirror driver
  168. pdi->flGraphicsCaps |= GCAPS_LAYERED;
  169. // to support alpha cursor
  170. pdi->flGraphicsCaps2 |= GCAPS2_ALPHACURSOR;
  171. } else {
  172. if (cModes == 0) {
  173. TRC_ERR((TB, "Failed to get the video modes."));
  174. DC_QUIT;
  175. }
  176. }
  177. #if 0
  178. // Dump the returned GDIINFO details to the debugger.
  179. TRC_ALT((TB, "Returned GDIINFO:"));
  180. TRC_ALT((TB, " ulVersion %#x", gdiInfoNew.ulVersion));
  181. TRC_ALT((TB, " ulTechnology %#x", gdiInfoNew.ulTechnology));
  182. TRC_ALT((TB, " ulHorzSize %#x", gdiInfoNew.ulHorzSize));
  183. TRC_ALT((TB, " ulVertSize %#x", gdiInfoNew.ulVertSize));
  184. TRC_ALT((TB, " ulHorzRes %#x", gdiInfoNew.ulHorzRes));
  185. TRC_ALT((TB, " ulVertRes %#x", gdiInfoNew.ulVertRes));
  186. TRC_ALT((TB, " cBitsPixel %#x", gdiInfoNew.cBitsPixel));
  187. TRC_ALT((TB, " cPlanes %#x", gdiInfoNew.cPlanes));
  188. TRC_ALT((TB, " ulNumColors %#x", gdiInfoNew.ulNumColors));
  189. TRC_ALT((TB, " flRaster %#x", gdiInfoNew.flRaster));
  190. TRC_ALT((TB, " ulLogPixelsX %#x", gdiInfoNew.ulLogPixelsX));
  191. TRC_ALT((TB, " ulLogPixelsY %#x", gdiInfoNew.ulLogPixelsY));
  192. TRC_ALT((TB, " flTextCaps %#x", gdiInfoNew.flTextCaps));
  193. TRC_ALT((TB, " ulDACRed %#x", gdiInfoNew.ulDACRed));
  194. TRC_ALT((TB, " ulDACGreen %#x", gdiInfoNew.ulDACGreen));
  195. TRC_ALT((TB, " ulDACBlue %#x", gdiInfoNew.ulDACBlue));
  196. TRC_ALT((TB, " ulAspectX %#x", gdiInfoNew.ulAspectX));
  197. TRC_ALT((TB, " ulAspectY %#x", gdiInfoNew.ulAspectY));
  198. TRC_ALT((TB, " ulAspectXY %#x", gdiInfoNew.ulAspectXY));
  199. TRC_ALT((TB, " xStyleStep %#x", gdiInfoNew.xStyleStep));
  200. TRC_ALT((TB, " yStyleStep %#x", gdiInfoNew.yStyleStep));
  201. TRC_ALT((TB, " denStyleStep %#x", gdiInfoNew.denStyleStep));
  202. TRC_ALT((TB, " ptlPhysOffset.x %#x", gdiInfoNew.ptlPhysOffset.x));
  203. TRC_ALT((TB, " ptlPhysOffset.y %#x", gdiInfoNew.ptlPhysOffset.y));
  204. TRC_ALT((TB, " szlPhysSize.cx %#x", gdiInfoNew.szlPhysSize.cx));
  205. TRC_ALT((TB, " szlPhysSize.cy %#x", gdiInfoNew.szlPhysSize.cy));
  206. TRC_ALT((TB, " ulNumPalReg %#x", gdiInfoNew.ulNumPalReg));
  207. TRC_ALT((TB, " ulVRefresh %#x", gdiInfoNew.ulVRefresh));
  208. TRC_ALT((TB, " ulBltAlignment %#x", gdiInfoNew.ulBltAlignment));
  209. TRC_ALT((TB, " ulPanningHorzRes %#x", gdiInfoNew.ulPanningHorzRes));
  210. TRC_ALT((TB, " ulPanningVertRes %#x", gdiInfoNew.ulPanningVertRes));
  211. #endif
  212. // Set the default palette.
  213. if (DDInitializePalette(pPDev, pdi)) {
  214. // We have successfully initialized - return the new PDEV.
  215. rc = (DHPDEV)pPDev;
  216. TRC_NRM((TB, "PDEV 0x%p screen format %lu", pPDev,
  217. pPDev->iBitmapFormat));
  218. }
  219. else {
  220. TRC_ERR((TB, "Failed to initialize palette"));
  221. DC_QUIT;
  222. }
  223. DC_EXIT_POINT:
  224. // This is a temporary buffer. We use it to call DDGetModes in order
  225. // to find out if we are in chained mode or not. We always free it.
  226. if (pVideoModeInformation != NULL) {
  227. EngFreeMem(pVideoModeInformation);
  228. pVideoModeInformation = NULL;
  229. }
  230. // Release any resources if we failed to initialize.
  231. if (rc != NULL) {
  232. DD_UPD_STATE(DD_ENABLE_PDEV);
  233. }
  234. else {
  235. // In case pPDev is allocated this will free first try to free the
  236. // palette (if any) and then it will free pPDev.
  237. DrvDisablePDEV((DHPDEV)pPDev);
  238. DD_UPD_STATE(DD_ENABLE_PDEV_ERR);
  239. }
  240. TRC_DBG((TB, "Returning %p", rc));
  241. DC_END_FN();
  242. return rc;
  243. }
  244. /****************************************************************************/
  245. // DrvDisablePDEV - see NT DDK documentation
  246. //
  247. // Release the resources allocated in DrvEnablePDEV. If a surface has been
  248. // enabled DrvDisableSurface will have already been called. Note that this
  249. // function will be called when previewing modes in the Display Applet, but
  250. // not at system shutdown. Note: In an error, we may call this before
  251. // DrvEnablePDEV is done.
  252. /****************************************************************************/
  253. VOID DrvDisablePDEV(DHPDEV dhpdev)
  254. {
  255. PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
  256. DC_BEGIN_FN("DrvDisablePDEV");
  257. TRC_NRM((TB, "Disabling PDEV %p", dhpdev));
  258. // Free the resources we allocated for the display.
  259. if (pPDev != NULL) {
  260. // Destroy the default palette, if created.
  261. if (pPDev->hpalDefault != 0) {
  262. EngDeletePalette(pPDev->hpalDefault);
  263. pPDev->hpalDefault = 0;
  264. }
  265. EngFreeMem(pPDev);
  266. }
  267. DC_END_FN();
  268. }
  269. /****************************************************************************/
  270. /* DrvCompletePDEV - see NT DDK documentation */
  271. /* */
  272. /* Stores the HPDEV, the engine's handle for this PDEV, in the DHPDEV. */
  273. /****************************************************************************/
  274. VOID DrvCompletePDEV(DHPDEV dhpdev, HDEV hdev)
  275. {
  276. DC_BEGIN_FN("DrvCompletePDEV");
  277. // Store the device handle for our display handle.
  278. TRC_NRM((TB, "Completing PDEV %p", dhpdev));
  279. ((PDD_PDEV)dhpdev)->hdevEng = hdev;
  280. DD_UPD_STATE(DD_COMPLETE_PDEV);
  281. DC_END_FN();
  282. }
  283. /****************************************************************************/
  284. /* DrvShadowConnect - called when the display driver should start */
  285. /* shadowing. */
  286. /* */
  287. /* Primary job seems to be getting the shadow target WD up and running by */
  288. /* pretending the display driver is coming up for the first time. Also */
  289. /* */
  290. /* Params: IN - pClientThinwireData (DD data from client) */
  291. /* IN - ThinwireDataLength (length of data) */
  292. /****************************************************************************/
  293. BOOL DrvShadowConnect(PVOID pClientThinwireData, ULONG ThinwireDataLength)
  294. {
  295. TSHARE_DD_SHADOWSYNC_IN shadowSync;
  296. ULONG bytesReturned;
  297. NTSTATUS status;
  298. BOOL rc = FALSE;
  299. DC_BEGIN_FN("DrvShadowConnect");
  300. DD_UPD_STATE(DD_SHADOW_SETUP);
  301. // Make sure we are still connected! TODO: Restrict to only one shadow for
  302. // now...
  303. TRC_ERR((TB, "Shadow Connect: %p [%ld]",
  304. pClientThinwireData,
  305. ThinwireDataLength));
  306. #ifdef DC_DEBUG
  307. // NT BUG 539912 - track calls to DD fns.
  308. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_SHADOWCONNECT,
  309. pClientThinwireData, ThinwireDataLength, ddConnected, pddTSWdShadow);
  310. #endif
  311. if ((ddConnected) && (pddTSWdShadow == NULL)) {
  312. // Drive the DD and WD into a disconnected state. Indicate this is in
  313. // preparation for a shadow session to disable saving the persistent key
  314. // database, etc. It also has the effect of destroying the SHM and
  315. // taking down all of the related cache information and encoding state.
  316. ddIgnoreShadowDisconnect = FALSE;
  317. TRC_ERR((TB, "Disconnecting stack prior to shadow"));
  318. DDDisconnect(TRUE);
  319. TRC_ERR((TB, "Done disconnecting"));
  320. // Reconnect to the WD to establish the shadow session
  321. TRC_ERR((TB, "Reinitializing primary/shadow stacks: ddConnected(%ld)",
  322. ddConnected));
  323. // If both stacks connected successfully, reestablish the SHM and
  324. // recreate the caches and encoding state.
  325. if (DDInit(NULL, TRUE, FALSE, (PTSHARE_VIRTUAL_MODULE_DATA) pClientThinwireData,
  326. ThinwireDataLength)) {
  327. #ifdef DC_HICOLOR
  328. // Get the shadower caps - in particular, it may have changed its
  329. // cache caps because of a color depth change
  330. PTSHARE_VIRTUAL_MODULE_DATA pShadowCaps;
  331. ULONG dataLen = 256;
  332. // Supply a small amount of memory so the Wd can tell us how much
  333. // it actually needs - we can't just use the returned length from
  334. // EngFileIoControl since when the IOCTL gets passed to both the
  335. // primary and shadow stacks, the shadow's result overwrites the
  336. // primary's result. Doh!
  337. pShadowCaps = EngAllocMem(FL_ZERO_MEMORY,
  338. dataLen,
  339. DD_ALLOC_TAG);
  340. if (pShadowCaps)
  341. {
  342. // First pass tells us the size we need for the caps
  343. TRC_ERR((TB, "Getting shadow caps len..."));
  344. status = EngFileIoControl(ddWdHandle,
  345. IOCTL_WDTS_DD_QUERY_SHADOW_CAPS,
  346. NULL, 0,
  347. pShadowCaps, dataLen,
  348. &dataLen);
  349. if (pShadowCaps->capsLength)
  350. {
  351. TRC_ERR((TB, "Getting shadow caps..."));
  352. // remember this is the *caps* len - we need a bit
  353. // extra for the rest of a vurtual module data structure
  354. dataLen = pShadowCaps->capsLength + sizeof(unsigned);
  355. // Free the old memory!
  356. EngFreeMem(pShadowCaps);
  357. pShadowCaps = EngAllocMem(FL_ZERO_MEMORY,
  358. dataLen,
  359. DD_ALLOC_TAG);
  360. if (pShadowCaps)
  361. {
  362. // now we'll get the data
  363. status = EngFileIoControl(ddWdHandle,
  364. IOCTL_WDTS_DD_QUERY_SHADOW_CAPS,
  365. NULL, 0,
  366. pShadowCaps, dataLen,
  367. &dataLen);
  368. }
  369. else
  370. {
  371. TRC_ERR((TB, "Couldn't get memory for shadow caps"));
  372. status = STATUS_NO_MEMORY;
  373. }
  374. }
  375. else
  376. {
  377. TRC_ERR((TB, "Unexpected status %08lx", status));
  378. status = STATUS_BUFFER_OVERFLOW;
  379. }
  380. }
  381. else
  382. {
  383. TRC_ERR((TB, "Couldn't get memory for shadow caps"));
  384. status = STATUS_NO_MEMORY;
  385. }
  386. if (status != STATUS_SUCCESS)
  387. {
  388. TRC_ERR((TB, "Couldn't get updated shadow caps"));
  389. DC_QUIT;
  390. }
  391. #endif
  392. // Tell the shadow target and shadow client(s) to synchronize
  393. TRC_ERR((TB, "Shadow Connect - WD Sync Start"));
  394. shadowSync.pShm = pddShm;
  395. #ifdef DC_HICOLOR
  396. shadowSync.capsLen = pShadowCaps->capsLength;
  397. shadowSync.pShadowCaps = &pShadowCaps->combinedCapabilities;
  398. #endif
  399. status = EngFileIoControl(ddWdHandle,
  400. IOCTL_WDTS_DD_SHADOW_SYNCHRONIZE, &shadowSync,
  401. sizeof(shadowSync), NULL, 0, &bytesReturned);
  402. TRC_ERR((TB, "Shadow Connect - WD Sync End"));
  403. #ifdef DC_HICOLOR
  404. // release the caps memory
  405. if (pShadowCaps)
  406. {
  407. EngFreeMem(pShadowCaps);
  408. }
  409. #endif
  410. // Free all pending orders. This is OK as we will get a full redraw
  411. // when the shadow starts
  412. BAResetBounds();
  413. // With Direct Encoding, at this point the orders in the order
  414. // heap have already changed the encoding state, blowing away
  415. // orders at this point will cause inconsistent state of the encoding
  416. // table between the server and client. This is because we keep
  417. // the last order type sent, so blowing away orders here means
  418. // order type will not be sent to the client, but the server encoding
  419. // table and state still kept the last order state. It's almost
  420. // impossible to rewind the orders at this point. So, we simply have
  421. // to send the orders to the client to keep order encoding state
  422. // consistent.
  423. //OA_DDSyncUpdatesNow();
  424. if (status != STATUS_SUCCESS) {
  425. TRC_ERR((TB,"Could not synchronize primary/shadow stacks: %lx",
  426. status));
  427. }
  428. rc = NT_SUCCESS(status);
  429. }
  430. else {
  431. TRC_ERR((TB,"Could not connect to primary/shadow stacks"));
  432. }
  433. }
  434. // TODO: This is a temporary restriction until we allow n-way shadowing.
  435. // Rejecting this connection causes us to get an associated
  436. // DrvShadowDisconnect() which we need to ignore. See bug 229479
  437. else {
  438. TRC_ERR((TB, "Shadow Connect: already shadowing -> reject!"));
  439. ddIgnoreShadowDisconnect = TRUE;
  440. rc = STATUS_CTX_SHADOW_DENIED;
  441. }
  442. #ifdef DC_HICOLOR
  443. DC_EXIT_POINT:
  444. #endif
  445. DD_CLR_STATE(DD_SHADOW_SETUP);
  446. DC_END_FN();
  447. return rc;
  448. }
  449. /****************************************************************************/
  450. /* DrvShadowDisconnect - called when the display driver should stop */
  451. /* shadowing. */
  452. /* */
  453. /* Primary job seems to be telling the shadow target WD that shadowing is */
  454. /* stopping and potentially restoring the former capability set for the */
  455. /* target. */
  456. /* */
  457. /* Params: IN - pClientThinwireData (DD data from client) */
  458. /* IN - ThinwireDataLength (length of data) */
  459. /****************************************************************************/
  460. BOOL DrvShadowDisconnect(PVOID pThinwireData, ULONG ThinwireDataLength)
  461. {
  462. NTSTATUS status;
  463. ULONG bytesReturned;
  464. TSHARE_DD_DISCONNECT_IN disconnIn;
  465. DC_BEGIN_FN("DrvShadowDisconnect");
  466. // Now tell the WD we're disconnecting. We don't do anything with a
  467. // failure here - there's no point - we're already disconnecting!
  468. TRC_ERR((TB, "Shadow Disconnect: %p [%ld]", pThinwireData,
  469. ThinwireDataLength));
  470. #ifdef DC_DEBUG
  471. // NT BUG 539912 - track calls to DD fns.
  472. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_SHADOWDISCONNECT,
  473. pThinwireData, ThinwireDataLength, ddConnected, ddIgnoreShadowDisconnect);
  474. #endif
  475. if (ddConnected) {
  476. // For now we are limited to one shadow per session. Any subsequent
  477. // attempts will be rejected, but we must ignore the associated
  478. // and unnecessary disconnect!
  479. if (!ddIgnoreShadowDisconnect) {
  480. pddShm->pShadowInfo = NULL;
  481. disconnIn.pShm = pddShm;
  482. disconnIn.bShadowDisconnect = FALSE;
  483. status = EngFileIoControl(ddWdHandle,
  484. IOCTL_WDTS_DD_SHADOW_DISCONNECT, &disconnIn,
  485. sizeof(disconnIn), NULL, 0, &bytesReturned);
  486. TRC_ERR((TB, "Status on Shadow Disc IOCtl to WD %lu", status));
  487. pddTSWdShadow = NULL;
  488. // Update capabilities now that a party left the share
  489. TRC_ERR((TB, "Updating new capabilities"));
  490. // Initiate a disconnect for shadow exiting
  491. DDDisconnect(TRUE);
  492. TRC_ERR((TB, "Done disconnecting"));
  493. // Reconnect to the WD to establish the primary session
  494. TRC_ERR((TB, "Reinitializing primary stack: ddConnected(%ld)",
  495. ddConnected));
  496. // If primary stack connected successfully, reestablish the SHM and
  497. // recreate the caches and encoding state.
  498. if (DDInit(NULL, TRUE, FALSE, NULL, 0)) {
  499. TRC_NRM((TB, "Reintialized the DD"));
  500. status = STATUS_SUCCESS;
  501. }
  502. else {
  503. TRC_ERR((TB, "Failed to initialize DD Components"));
  504. status = STATUS_UNSUCCESSFUL;
  505. }
  506. }
  507. else {
  508. ddIgnoreShadowDisconnect = FALSE;
  509. status = STATUS_SUCCESS;
  510. }
  511. }
  512. // else we have already been disconnected so just return an error
  513. else {
  514. status = STATUS_FILE_CLOSED;
  515. }
  516. DC_END_FN();
  517. return NT_SUCCESS(status);
  518. }
  519. /****************************************************************************/
  520. /* DrvEnableSurface - see NT DDK documentation */
  521. /* */
  522. /* Creates the drawing surface and initializes driver components. This */
  523. /* function is called after DrvEnablePDEV, and performs the final device */
  524. /* initialization. */
  525. /****************************************************************************/
  526. HSURF DrvEnableSurface(DHPDEV dhpdev)
  527. {
  528. PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
  529. SIZEL sizl, tempSizl;
  530. HSURF rc = 0;
  531. ULONG memSize;
  532. PBYTE newFrameBuf;
  533. HANDLE SectionObject = NULL;
  534. DC_BEGIN_FN("DrvEnableSurface");
  535. TRC_NRM((TB, "Enabling surface for %p", dhpdev));
  536. DD_UPD_STATE(DD_ENABLE_SURFACE_IN);
  537. // Have GDI create the actual SURFOBJ.
  538. sizl.cx = pPDev->cxScreen;
  539. sizl.cy = pPDev->cyScreen;
  540. /************************************************************************/
  541. /* An RDP display driver has a bitmap where GDI does all its drawing, */
  542. /* since it is the only driver in the IWS. We need to allocate the */
  543. /* bitmap ourselves in order to know its address. */
  544. /* */
  545. /* We allocate a Frame Buffer at DrvEnableSurface time to make */
  546. /* sure that the frame buffer surface is same as the device surface */
  547. /* GDI thinks. This will prevent a lot of mismatch reconnect condition */
  548. /************************************************************************/
  549. #ifdef DC_HICOLOR
  550. if ((pPDev->cClientBitsPerPel != ddFrameBufBpp + 1) ||
  551. (pddFrameBuf == NULL) ||
  552. (ddFrameBufX < sizl.cx) || (ddFrameBufY < sizl.cy))
  553. #else
  554. if ((pPDev->cClientBitsPerPel != ddFrameBufBpp) ||
  555. (ddFrameBufX != sizl.cx) || (ddFrameBufY != sizl.cy))
  556. #endif
  557. {
  558. // Allocate a new one. Note that we do not free the old one here -
  559. // that's done in DrvDisableSurface.
  560. memSize = TS_BYTES_IN_BITMAP(pPDev->cxScreen,
  561. pPDev->cyScreen,
  562. pPDev->cClientBitsPerPel);
  563. newFrameBuf = (PBYTE)EngAllocSectionMem(&SectionObject,
  564. FL_ZERO_MEMORY,
  565. memSize,
  566. DD_ALLOC_TAG);
  567. if (newFrameBuf == NULL) {
  568. TRC_ERR((TB, "DrvEnableSurface - "
  569. "Failed FrameBuf EngAllocSectionMem for %lu bytes", memSize));
  570. newFrameBuf = (PBYTE)EngAllocMem(FL_ZERO_MEMORY,
  571. memSize,
  572. DD_ALLOC_TAG);
  573. SectionObject = NULL;
  574. }
  575. #ifdef DC_DEBUG
  576. // NT BUG 539912 - Instance count section memory objects
  577. else {
  578. dbg_ddSectionAllocs++;
  579. TRC_DBG(( TB, "DrvEnableSurface - %d outstanding surfaces allocated",
  580. dbg_ddSectionAllocs ));
  581. DBG_DD_FNCALL_HIST_ADD( DBG_DD_ALLOC_SECTIONOBJ,
  582. dbg_ddSectionAllocs, 0, newFrameBuf, SectionObject);
  583. }
  584. #endif
  585. TRC_NRM((TB, "Reallocate Frame Buffer %p, SectionObject %p", newFrameBuf, SectionObject));
  586. if (newFrameBuf == NULL) {
  587. TRC_ERR((TB, "DrvEnableSurface - "
  588. "Failed FrameBuf EngAllocMem for %lu bytes", memSize));
  589. if (pddFrameBuf == NULL) {
  590. // Reset the frame buffer size back to 0.
  591. ddFrameBufX = ddFrameBufY = 0;
  592. }
  593. DC_QUIT;
  594. }
  595. pddFrameBuf = newFrameBuf;
  596. ddFrameBufX = sizl.cx;
  597. ddFrameBufY = sizl.cy;
  598. ddFrameBufBpp = pPDev->cClientBitsPerPel;
  599. ddFrameIFormat = pPDev->iBitmapFormat;
  600. ddSectionObject = SectionObject;
  601. }
  602. // Create the frame buffer surface.
  603. tempSizl.cx = ddFrameBufX;
  604. tempSizl.cy = ddFrameBufY;
  605. pPDev->hsurfFrameBuf = (HSURF)EngCreateBitmap(tempSizl,
  606. TS_BYTES_IN_SCANLINE(ddFrameBufX, ddFrameBufBpp),
  607. ddFrameIFormat, BMF_TOPDOWN, (PVOID)pddFrameBuf);
  608. if (pPDev->hsurfFrameBuf == 0) {
  609. TRC_ERR((TB, "Could not allocate surface"));
  610. DC_QUIT;
  611. }
  612. // Update Frame Buffer pointers in PDEV.
  613. pPDev->pFrameBuf = pddFrameBuf;
  614. pPDev->SectionObject = ddSectionObject;
  615. // Associate the frame buffer with the pdev.
  616. if (EngAssociateSurface(pPDev->hsurfFrameBuf, pPDev->hdevEng, 0)) {
  617. // Get a pointer to the frame buffer SURFOBJ.
  618. pPDev->psoFrameBuf = EngLockSurface(pPDev->hsurfFrameBuf);
  619. }
  620. else {
  621. TRC_ERR((TB, "EngAssociateSurface failed: hsurfFrameBuf(%p)",
  622. pPDev->hsurfFrameBuf));
  623. DC_QUIT;
  624. }
  625. /************************************************************************/
  626. /* Create a device surface. This is what we will pass back to the */
  627. /* Graphics Engine. The fact that it is a device surface forces all */
  628. /* drawing to come through the display driver. */
  629. /* */
  630. /* We pass the Frame Buffer SURFOBJ pointer as the DHSURF, so we can */
  631. /* easily convert the (SURFOBJ *) parameters in the Drv... functions */
  632. /* into real Frame Buffer SURFOBJ pointers: */
  633. /* */
  634. /* psoFrameBuf = (SURFOBJ *)(psoTrg->dhsurf); */
  635. /************************************************************************/
  636. pPDev->hsurfDevice = EngCreateDeviceSurface((DHSURF)pPDev->psoFrameBuf,
  637. sizl, pPDev->iBitmapFormat);
  638. // Now associate the device surface and the PDEV.
  639. if (!EngAssociateSurface(pPDev->hsurfDevice, pPDev->hdevEng,
  640. pPDev->flHooks)) {
  641. TRC_ERR((TB, "DrvEnableSurface - Failed EngAssociateSurface"));
  642. DC_QUIT;
  643. }
  644. TRC_NRM((TB, "hsurfFrameBuf(%p) hsurfDevice(%p) psoFrameBuf(%p)",
  645. pPDev->hsurfFrameBuf, pPDev->hsurfDevice, pPDev->psoFrameBuf));
  646. // Finally initialize the DD components, if necessary.
  647. if (ddInitPending) {
  648. TRC_NRM((TB, "DD init pending"));
  649. ddInitPending = FALSE;
  650. if (!DDInit(pPDev, FALSE, FALSE, NULL, 0)) {
  651. TRC_ERR((TB, "Failed to initialize DD Components"));
  652. DC_QUIT;
  653. }
  654. }
  655. else {
  656. // Don't do this is we're not connected.
  657. if (ddConnected && pddShm != NULL) {
  658. TRC_ALT((TB, "Re-enable surface"));
  659. // Initialization not pending - this must be a desktop change.
  660. // Flush the SDA & Order Heap.
  661. TRC_ALT((TB, "New surface"));
  662. BAResetBounds();
  663. // With Direct Encoding, at this point the orders in the order
  664. // heap have already changed the encoding state, blowing away
  665. // orders at this point will cause inconsistent state of the encoding
  666. // table between the server and client. This is because we keep
  667. // the last order type sent, so blowing away orders here means
  668. // order type will not be sent to the client, but the server encoding
  669. // table and state still kept the last order state. It's almost
  670. // impossible to rewind the orders at this point. So, we simply have
  671. // to send the orders to the client to keep order encoding state
  672. // consistent.
  673. //OA_DDSyncUpdatesNow();
  674. // SBC_DDSync(); // TODO: Determine how this affects shadowing!!!
  675. DD_UPD_STATE(DD_REINIT);
  676. }
  677. else {
  678. TRC_ALT((TB, "Not connected"));
  679. }
  680. }
  681. // We have successfully associated the surface so return it to the GDI.
  682. rc = pPDev->hsurfDevice;
  683. DD_UPD_STATE(DD_ENABLE_SURFACE_OUT);
  684. TRC_NRM((TB, "Enabled surface for %p, FB %p", pPDev, pPDev->pFrameBuf));
  685. DC_EXIT_POINT:
  686. // Tidy up any resources if we failed.
  687. if (rc == 0) {
  688. DrvDisableSurface((DHPDEV) pPDev);
  689. DD_UPD_STATE(DD_ENABLE_SURFACE_ERR);
  690. }
  691. DC_END_FN();
  692. return rc;
  693. }
  694. /****************************************************************************/
  695. /* DrvDisableSurface - see NT DDK documentation */
  696. /* */
  697. /* Free resources allocated by DrvEnableSurface. Release the surface. */
  698. /* */
  699. /* Note that this function will be called when previewing modes in the */
  700. /* Display Applet, but not at system shutdown. If you need to reset the */
  701. /* hardware at shutdown, you can do it in the miniport by providing a */
  702. /* 'HwResetHw' entry point in the VIDEO_HW_INITIALIZATION_DATA structure. */
  703. /* */
  704. /* Note: In an error case, we may call this before DrvEnableSurface is */
  705. /* completely done. */
  706. /****************************************************************************/
  707. VOID DrvDisableSurface(DHPDEV dhpdev)
  708. {
  709. BOOL rc;
  710. PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
  711. DC_BEGIN_FN("DrvDisableSurface");
  712. TRC_NRM((TB, "Disabling surface for %p", dhpdev));
  713. if (pPDev->psoFrameBuf != NULL) {
  714. EngUnlockSurface(pPDev->psoFrameBuf);
  715. pPDev->psoFrameBuf = NULL;
  716. }
  717. if (pPDev->hsurfDevice != 0) {
  718. TRC_DBG((TB, "Deleting device surface"));
  719. EngDeleteSurface(pPDev->hsurfDevice);
  720. pPDev->hsurfDevice = 0;
  721. }
  722. // Delete the Frame Buffer only if it is not still in use.
  723. if (pPDev->hsurfFrameBuf != 0) {
  724. TRC_DBG((TB, "Deleting frame buffer surface"));
  725. EngDeleteSurface(pPDev->hsurfFrameBuf);
  726. pPDev->hsurfFrameBuf = 0;
  727. }
  728. if ((pPDev->pFrameBuf != NULL) && (pPDev->pFrameBuf != pddFrameBuf)) {
  729. if (pPDev->SectionObject != NULL) {
  730. TRC_NRM((TB, "Freeing section frame buffer %p", pPDev->pFrameBuf));
  731. rc = EngFreeSectionMem(pPDev->SectionObject, (PVOID)pPDev->pFrameBuf);
  732. if (!rc) {
  733. TRC_ABORT((TB, "EngFreeSectionMem failed, section object will "
  734. "leak"));
  735. #ifdef DC_DEBUG
  736. WDIcaBreakOnDebugger();
  737. #endif // DC_DEBUG
  738. }
  739. #ifdef DC_DEBUG
  740. else {
  741. // NT BUG 539912 - Instance count section memory objects
  742. dbg_ddSectionAllocs--;
  743. TRC_DBG(( TB, "DrvDisableSurface - %d outstanding surfaces allocated",
  744. dbg_ddSectionAllocs ));
  745. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FREE_SECTIONOBJ_SURFACE,
  746. dbg_ddSectionAllocs, 0, pddFrameBuf, ddSectionObject);
  747. }
  748. #endif
  749. pPDev->SectionObject = NULL;
  750. } else {
  751. TRC_NRM((TB, "Freeing frame buffer %p", pPDev->pFrameBuf));
  752. EngFreeMem((PVOID)pPDev->pFrameBuf);
  753. }
  754. pPDev->pFrameBuf = NULL;
  755. }
  756. DC_END_FN();
  757. }
  758. /****************************************************************************/
  759. // DDHandleWDSync
  760. //
  761. // Moves rare WD SHM data update notifications out of the perf path.
  762. /****************************************************************************/
  763. void DDHandleWDSync()
  764. {
  765. ULONG bytesReturned;
  766. NTSTATUS Status;
  767. DC_BEGIN_FN("DDHandleWDSync");
  768. // Now look for any updated fields that might be available.
  769. if (pddShm->oe.newCapsData) {
  770. TRC_DBG((TB, "Update for OE, %d", pddShm->oe.newCapsData));
  771. OE_Update();
  772. }
  773. if (pddShm->sbc.newCapsData) {
  774. TRC_NRM((TB, "newCapsData for SBC"));
  775. SBC_Update(NULL);
  776. }
  777. if (pddShm->sbc.syncRequired) {
  778. TRC_NRM((TB, "syncRequired for SBC"));
  779. SBC_DDSync(FALSE);
  780. }
  781. if (pddShm->sbc.fClearCache) {
  782. unsigned i;
  783. // reset the flag
  784. pddShm->sbc.fClearCache = FALSE;
  785. // walk through each cache to determine if that cache
  786. // needs to be cleared
  787. for (i = 0; i < pddShm->sbc.NumBitmapCaches; i++) {
  788. if (pddShm->sbc.bitmapCacheInfo[i].fClearCache) {
  789. TRC_NRM((TB, "clear cache with cacheID=%d", i));
  790. // clear the entries in the cache
  791. CH_ClearCache(pddShm->sbc.bitmapCacheInfo[i].
  792. cacheHandle);
  793. // reset the clear cache flag in SBC
  794. pddShm->sbc.bitmapCacheInfo[i].fClearCache = FALSE;
  795. }
  796. }
  797. // send an IOCTL to RDPWD for screen redraw
  798. Status = EngFileIoControl(ddWdHandle,
  799. IOCTL_WDTS_DD_REDRAW_SCREEN,
  800. NULL, 0, NULL, 0, &bytesReturned);
  801. if (Status != STATUS_SUCCESS) {
  802. TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
  803. }
  804. }
  805. if (pddShm->sbc.fDisableOffscreen) {
  806. // reset the flag
  807. pddShm->sbc.fDisableOffscreen = FALSE;
  808. // disable offscreen rendering support
  809. pddShm->sbc.offscreenCacheInfo.supportLevel = TS_OFFSCREEN_DEFAULT;
  810. // send an IOCTL to RDPWD for screen redraw
  811. Status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_REDRAW_SCREEN,
  812. NULL, 0, NULL, 0, &bytesReturned);
  813. if (Status != STATUS_SUCCESS) {
  814. TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
  815. }
  816. }
  817. #ifdef DRAW_NINEGRID
  818. if (pddShm->sbc.fDisableDrawNineGrid) {
  819. // reset the flag
  820. pddShm->sbc.fDisableDrawNineGrid = FALSE;
  821. // disable offscreen rendering support
  822. pddShm->sbc.drawNineGridCacheInfo.supportLevel = TS_DRAW_NINEGRID_DEFAULT;
  823. // send an IOCTL to RDPWD for screen redraw
  824. Status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_REDRAW_SCREEN,
  825. NULL, 0, NULL, 0, &bytesReturned);
  826. if (Status != STATUS_SUCCESS) {
  827. TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
  828. }
  829. }
  830. #endif
  831. #ifdef DRAW_GDIPLUS
  832. if (pddShm->sbc.fDisableDrawGdiplus) {
  833. // reset the flag
  834. pddShm->sbc.fDisableDrawGdiplus = FALSE;
  835. // disable gdiplus support
  836. pddShm->sbc.drawGdiplusInfo.supportLevel = TS_DRAW_GDIPLUS_DEFAULT;
  837. // send an IOCTL to RDPWD for screen redraw
  838. Status = EngFileIoControl(ddWdHandle, IOCTL_WDTS_DD_REDRAW_SCREEN,
  839. NULL, 0, NULL, 0, &bytesReturned);
  840. if (Status != STATUS_SUCCESS) {
  841. TRC_ERR((TB, "Redraw Screen IOCtl returned %lu", Status));
  842. }
  843. }
  844. #endif
  845. // Check SSI flags.
  846. if (pddShm->ssi.saveBitmapSizeChanged ||
  847. pddShm->ssi.resetInterceptor) {
  848. TRC_DBG((TB, "Update for SSI, %d:%d",
  849. pddShm->ssi.saveBitmapSizeChanged,
  850. pddShm->ssi.resetInterceptor));
  851. SSI_Update(FALSE);
  852. }
  853. DC_END_FN();
  854. }
  855. /****************************************************************************/
  856. // DrvEscape - see NT DDK documentation.
  857. /****************************************************************************/
  858. ULONG DrvEscape(
  859. SURFOBJ *pso,
  860. ULONG iEsc,
  861. ULONG cjIn,
  862. PVOID pvIn,
  863. ULONG cjOut,
  864. PVOID pvOut)
  865. {
  866. ULONG rc = FALSE;
  867. ULONG escCode = 0;
  868. ULONG bytesReturned;
  869. NTSTATUS status;
  870. TSHARE_DD_TIMER_INFO timerInfo;
  871. TSHARE_DD_OUTPUT_IN outputIn;
  872. PDD_PDEV pPDev;
  873. DC_BEGIN_FN("DrvEscape");
  874. // DrvEscape sometimes gets called after the driver has terminated,
  875. // especially with ESC_TIMEROBJ_SIGNALLED.
  876. if (ddConnected) {
  877. pPDev = (PDD_PDEV)pso->dhpdev;
  878. // Performance path in this function is the desktop thread timer
  879. // trigger.
  880. if (iEsc == ESC_TIMEROBJ_SIGNALED) {
  881. TRC_DBG((TB, "Got a timer kick - IOCtl to WD"));
  882. TRC_ASSERT((NULL != pso), (TB, "NULL pso"));
  883. rc = TRUE;
  884. // Race condition: we got output (or, more likely, a timer pop)
  885. // after a disconnect. Just ignore it.
  886. if (NULL != pddShm) {
  887. status = SCH_DDOutputAvailable(pPDev, TRUE);
  888. // If this fails, either
  889. // - the failure was in the WD, and it's up to the WD to
  890. // correct it (or quit the session)
  891. // - the failure was in the infrastructure carrying the
  892. // IOCtl to the WD. There's nothing we can do in this
  893. // case other than try on the next output call.
  894. if (status != STATUS_SUCCESS) {
  895. TRC_ERR((TB, "Error on sending output IOCtl, status %lu",
  896. status));
  897. }
  898. if (!pddShm->fShmUpdate) {
  899. DC_QUIT;
  900. }
  901. else {
  902. DDHandleWDSync();
  903. pddShm->fShmUpdate = FALSE;
  904. }
  905. }
  906. DC_QUIT;
  907. }
  908. }
  909. else {
  910. TRC_ERR((TB, "DrvEscape %s (%d) called after DD terminated",
  911. iEsc == QUERYESCSUPPORT ? "QUERYESCSUPPORT " :
  912. iEsc == ESC_TIMEROBJ_SIGNALED ? "ESC_TIMEROBJ_SIGNALED" :
  913. iEsc == ESC_SET_WD_TIMEROBJ ? "ESC_SET_WD_TIMEROBJ " :
  914. "- Unknown -",
  915. iEsc));
  916. // Return FALSE for QUERYESCSUPPORT, TRUE for others (otherwise
  917. // USER asserts).
  918. rc = (iEsc == QUERYESCSUPPORT ? FALSE : TRUE);
  919. DC_QUIT;
  920. }
  921. // Process the non-performance-path escape codes.
  922. switch (iEsc) {
  923. case QUERYESCSUPPORT:
  924. // Do we support the function? If so, mark the function as OK.
  925. escCode = *((PUINT32)pvIn);
  926. TRC_DBG((TB, "Query for escape code %lu", escCode));
  927. if ((escCode == ESC_TIMEROBJ_SIGNALED) ||
  928. (escCode == ESC_SET_WD_TIMEROBJ)) {
  929. // Supported functions - return TRUE.
  930. TRC_DBG((TB, "We support escape code %lu", escCode));
  931. rc = TRUE;
  932. }
  933. break;
  934. case ESC_SET_WD_TIMEROBJ:
  935. {
  936. DD_UPD_STATE(DD_TIMEROBJ);
  937. // We have been given the timer details from Win32: pass them
  938. // to the WD. Note, only allow this to occur once to prevent
  939. // evil apps from trying to fake this call.
  940. if (pddWdTimer == NULL) {
  941. if (cjIn != sizeof(PKTIMER)) {
  942. TRC_ERR((TB, "Unexpected size %lu arrived", cjIn));
  943. }
  944. else {
  945. // Got the timer object OK. Save the handle here, and
  946. // then IOCtl across to the WD to tell it the handle.
  947. TRC_DBG((TB, "Timer object %p arrived", pvIn));
  948. pddWdTimer = (PKTIMER)pvIn;
  949. TRC_ASSERT((ddWdHandle != NULL), (TB, "NULL WD handle"));
  950. timerInfo.pKickTimer = pddWdTimer;
  951. status = EngFileIoControl(ddWdHandle,
  952. IOCTL_WDTS_DD_TIMER_INFO, &timerInfo,
  953. sizeof(TSHARE_DD_TIMER_INFO), NULL, 0,
  954. &bytesReturned);
  955. if (status != STATUS_SUCCESS) {
  956. TRC_ERR((TB, "Timer Info IOCtl returned %lu", status));
  957. // Looking at the current NT code, there is NO WAY of
  958. // reporting an error on this operation. If we return
  959. // 0 from DrvEscape, then USER will assert. Great.
  960. }
  961. }
  962. }
  963. rc = TRUE;
  964. }
  965. break;
  966. #ifdef DC_DEBUG
  967. // This event is generated by Bungle, a test app which displays the
  968. // contents of the frame buffer. Here we return it the address of
  969. // the frame buffer so it can do the displaying.
  970. case 3:
  971. {
  972. ULONG cBytes;
  973. TRC_ALT((TB, "copy frame buffer requested"));
  974. pPDev = (PDD_PDEV)pso->dhpdev;
  975. cBytes = (ULONG)(pPDev->cxScreen * pPDev->cyScreen);
  976. if (cjOut != cBytes) {
  977. TRC_ERR((TB, "Wrong memory block size"));
  978. }
  979. else {
  980. memcpy(pvOut, pPDev->pFrameBuf, cBytes);
  981. rc = TRUE;
  982. }
  983. }
  984. break;
  985. #ifdef i386
  986. // This event will be generated by the DbgBreak program. It forces
  987. // us to break to the kernel debugger in the right WinStation
  988. // context and in the DD, thus letting us set break points in a
  989. // sensible fashion!
  990. case 4:
  991. TRC_ALT((TB, "break to debugger requested"));
  992. _asm int 3;
  993. break;
  994. #endif
  995. #endif // DC_DEBUG
  996. case ESC_GET_DEVICEBITMAP_SUPPORT:
  997. {
  998. SIZEL bitmapSize;
  999. if (cjIn >= sizeof(ICA_DEVICE_BITMAP_INFO)) {
  1000. if (cjOut >= sizeof(ULONG)) {
  1001. bitmapSize.cx = (*((PICA_DEVICE_BITMAP_INFO)pvIn)).cx;
  1002. bitmapSize.cy = (*((PICA_DEVICE_BITMAP_INFO)pvIn)).cy;
  1003. rc = TRUE;
  1004. if (OEDeviceBitmapCachable(pPDev, bitmapSize, pPDev->iBitmapFormat)) {
  1005. *((PULONG)pvOut) = TRUE;
  1006. }
  1007. else {
  1008. *((PULONG)pvOut) = FALSE;
  1009. }
  1010. }
  1011. else {
  1012. TRC_ERR((TB, "Wrong output block size"));
  1013. }
  1014. }
  1015. else {
  1016. TRC_ERR((TB, "Wrong input block size"));
  1017. }
  1018. }
  1019. break;
  1020. default:
  1021. TRC_ERR((TB, "Unrecognised request %lu", iEsc));
  1022. break;
  1023. }
  1024. DC_EXIT_POINT:
  1025. DC_END_FN();
  1026. return rc;
  1027. }
  1028. /****************************************************************************/
  1029. /* DrvGetModes - see NT DDK documentation */
  1030. /* */
  1031. /* Returns the list of available modes for the device. */
  1032. /****************************************************************************/
  1033. ULONG DrvGetModes(HANDLE hDriver, ULONG cjSize, DEVMODEW *pdm)
  1034. {
  1035. INT32 cModes;
  1036. INT32 cbOutputSize = 0;
  1037. PVIDEO_MODE_INFORMATION pVideoModeInformation = NULL;
  1038. PVIDEO_MODE_INFORMATION pVideoTemp;
  1039. INT32 cOutputModes = cjSize / sizeof(DEVMODEW);
  1040. INT32 cbModeSize;
  1041. DC_BEGIN_FN("DrvGetModes");
  1042. TRC_NRM((TB, "DrvGetModes"));
  1043. // Get the list of valid modes.
  1044. cModes = DDGetModes(hDriver, &pVideoModeInformation, &cbModeSize);
  1045. // Should only ever return zero modes or one mode:
  1046. // If we're chained into the console session, we'll see zero modes so
  1047. // we return 0 to indicate that we will do whatever was set up in the
  1048. // registry before we got loaded. Otherwise, if we got more than one mode
  1049. // we bail out now.
  1050. if (cModes == -1) {
  1051. TRC_NRM((TB, "DrvGetModes returning 0 modes"));
  1052. ddConsole = TRUE;
  1053. DC_QUIT;
  1054. }
  1055. if (cModes != 1) {
  1056. TRC_ERR((TB, "DrvGetModes failed to get mode information"));
  1057. ddConsole = FALSE;
  1058. DC_QUIT;
  1059. }
  1060. if (pdm == NULL) {
  1061. // Return the size of the buffer required to receive all our modes.
  1062. cbOutputSize = cModes * sizeof(DEVMODEW);
  1063. TRC_DBG((TB, "Require %ld bytes for data", cbOutputSize));
  1064. }
  1065. else {
  1066. // Now copy the information for the supported modes back into the
  1067. // output buffer.
  1068. cbOutputSize = 0;
  1069. pVideoTemp = pVideoModeInformation;
  1070. do {
  1071. if (pVideoTemp->Length != 0) {
  1072. // Check we still have room in the buffer.
  1073. if (cOutputModes == 0) {
  1074. TRC_DBG((TB, "No more room %ld modes left", cModes));
  1075. break;
  1076. }
  1077. // Clear the structure.
  1078. memset(pdm, 0, sizeof(DEVMODEW));
  1079. // Set the name of the device to the name of the DLL.
  1080. memcpy(pdm->dmDeviceName, DD_DLL_NAME, sizeof(DD_DLL_NAME));
  1081. // Fill in the rest of the mode info.
  1082. pdm->dmSpecVersion = DM_SPECVERSION;
  1083. pdm->dmDriverVersion = DM_SPECVERSION;
  1084. pdm->dmSize = sizeof(DEVMODEW);
  1085. pdm->dmDriverExtra = 0;
  1086. pdm->dmBitsPerPel = pVideoTemp->BitsPerPlane;
  1087. pdm->dmPelsWidth = pVideoTemp->VisScreenWidth;
  1088. pdm->dmPelsHeight = pVideoTemp->VisScreenHeight;
  1089. pdm->dmDisplayFrequency = pVideoTemp->Frequency;
  1090. pdm->dmDisplayFlags = 0;
  1091. pdm->dmFields = DM_BITSPERPEL |
  1092. DM_PELSWIDTH |
  1093. DM_PELSHEIGHT |
  1094. DM_DISPLAYFREQUENCY |
  1095. DM_DISPLAYFLAGS ;
  1096. TRC_NRM((TB, "Returned mode info:"));
  1097. TRC_NRM((TB, " pdm->dmBitsPerPel: %u", pdm->dmBitsPerPel));
  1098. TRC_NRM((TB, " pdm->dmPelsWidth: %u", pdm->dmPelsWidth));
  1099. TRC_NRM((TB, " pdm->dmPelsHeight: %u", pdm->dmPelsHeight));
  1100. TRC_NRM((TB, " pdm->dmDisplayFrequency: %u",
  1101. pdm->dmDisplayFrequency));
  1102. // Go to the next DEVMODE entry in the buffer.
  1103. cOutputModes--;
  1104. pdm = (LPDEVMODEW) ( ((UINT_PTR)pdm) + sizeof(DEVMODEW));
  1105. cbOutputSize += sizeof(DEVMODEW);
  1106. }
  1107. pVideoTemp = (PVIDEO_MODE_INFORMATION)
  1108. (((PCHAR)pVideoTemp) + cbModeSize);
  1109. } while (--cModes);
  1110. }
  1111. DC_EXIT_POINT:
  1112. if (pVideoModeInformation != NULL) {
  1113. TRC_DBG((TB, "Freeing mode list"));
  1114. EngFreeMem(pVideoModeInformation);
  1115. }
  1116. DC_END_FN();
  1117. return cbOutputSize;
  1118. }
  1119. /****************************************************************************/
  1120. // DrvAssertMode - see NT DDK documentation.
  1121. /****************************************************************************/
  1122. BOOL DrvAssertMode(DHPDEV dhpdev, BOOL bEnable)
  1123. {
  1124. PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
  1125. BOOL bRc;
  1126. SURFOBJ *psoFrameBuf;
  1127. SURFOBJ *psoDevice;
  1128. DC_BEGIN_FN("DrvAssertMode");
  1129. TRC_NRM((TB, "pPDev %p, bEnable %d", pPDev, bEnable));
  1130. #ifdef DC_DEBUG
  1131. // NT BUG 539912 - track calls to DD fns.
  1132. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_ASSERTMODE,
  1133. dhpdev, bEnable, pddFrameBuf, ddSectionObject);
  1134. #endif
  1135. if (bEnable) {
  1136. // The surface is being re-enabled.
  1137. TRC_ALT((TB, "Enabling pPDev %p", pPDev));
  1138. // Re-associate the surface handles with the device handle.
  1139. if (!EngAssociateSurface(pPDev->hsurfFrameBuf, pPDev->hdevEng, 0)) {
  1140. TRC_ERR((TB, "Failed to associate surface %p and dev %p",
  1141. pPDev->hsurfFrameBuf, pPDev->hdevEng));
  1142. bRc = FALSE;
  1143. DC_QUIT;
  1144. }
  1145. if (!EngAssociateSurface(pPDev->hsurfDevice, pPDev->hdevEng,
  1146. pPDev->flHooks)) {
  1147. TRC_ERR((TB, "Failed to associate surface %p and dev %p",
  1148. pPDev->hsurfDevice, pPDev->hdevEng));
  1149. bRc = FALSE;
  1150. DC_QUIT;
  1151. }
  1152. TRC_ALT((TB, "Associated surfaces %p & %p with dev %p",
  1153. pPDev->hsurfDevice, pPDev->hsurfFrameBuf, pPDev->hdevEng));
  1154. TRC_ASSERT((pddFrameBuf != NULL), (TB, "NULL frame buffer"));
  1155. // Fixup the Frame Buffer surface object to point to the current
  1156. // Frame Buffer.
  1157. psoFrameBuf = pPDev->psoFrameBuf;
  1158. TRC_ASSERT((psoFrameBuf != NULL), (TB,"NULL psoFrameBuf"));
  1159. TRC_ASSERT((psoFrameBuf->iType == STYPE_BITMAP),
  1160. (TB, "Wrong FB surface iType, %d", psoFrameBuf->iType));
  1161. psoFrameBuf->sizlBitmap.cx = ddFrameBufX;
  1162. psoFrameBuf->sizlBitmap.cy = ddFrameBufY;
  1163. psoFrameBuf->cjBits = TS_BYTES_IN_BITMAP(ddFrameBufX,
  1164. ddFrameBufY,
  1165. ddFrameBufBpp);
  1166. psoFrameBuf->pvBits = pddFrameBuf;
  1167. psoFrameBuf->pvScan0 = pddFrameBuf;
  1168. psoFrameBuf->lDelta = TS_BYTES_IN_SCANLINE(ddFrameBufX, ddFrameBufBpp);
  1169. #ifdef DC_HICOLOR
  1170. TRC_ERR((TB, "New DD frameBufBpp %d", ddFrameBufBpp));
  1171. switch (ddFrameBufBpp) {
  1172. case 4:
  1173. psoFrameBuf->iBitmapFormat = BMF_4BPP;
  1174. break;
  1175. case 8:
  1176. psoFrameBuf->iBitmapFormat = BMF_8BPP;
  1177. break;
  1178. case 15:
  1179. case 16:
  1180. psoFrameBuf->iBitmapFormat = BMF_16BPP;
  1181. break;
  1182. case 24:
  1183. psoFrameBuf->iBitmapFormat = BMF_24BPP;
  1184. break;
  1185. default:
  1186. TRC_ERR((TB, "Unsupported frame buf bpp %u - default to 8",
  1187. ddFrameBufBpp));
  1188. psoFrameBuf->iBitmapFormat = BMF_8BPP;
  1189. break;
  1190. }
  1191. #else
  1192. psoFrameBuf->iBitmapFormat = ddFrameBufBpp == 8 ? BMF_8BPP : BMF_4BPP;
  1193. #endif
  1194. // Fixup the device surface object with the characteristics of the
  1195. // current Frame Buffer.
  1196. psoDevice = EngLockSurface(pPDev->hsurfDevice);
  1197. TRC_ASSERT((psoDevice != NULL), (TB,"Null device surfac"));
  1198. TRC_ASSERT((psoDevice->iType == STYPE_DEVICE),
  1199. (TB, "Wrong device surface iType, %d", psoDevice->iType));
  1200. TRC_ASSERT((psoDevice->pvBits == NULL),
  1201. (TB, "Device surface has bits, %p", psoDevice->pvBits));
  1202. TRC_ASSERT((psoDevice->dhsurf == (DHSURF)psoFrameBuf),
  1203. (TB, "Wrong dhSurf, expect/is %p/%p",
  1204. psoFrameBuf, psoDevice->dhsurf));
  1205. // We assert now since we should always get the same iBitmapFormat
  1206. // as 8BPP. This will change once we have 24bit color support.
  1207. // Then this needs to be looked at it and fix anything as necessary
  1208. TRC_ASSERT((psoDevice->iBitmapFormat == psoFrameBuf->iBitmapFormat),
  1209. (TB, "iBitmapFormat has changed"));
  1210. // We shouldn't change the device surface size. This has already
  1211. // been advertised to GDI, changing this will cause AV in GDI,
  1212. // since GDI has cached the surface size.
  1213. //psoDevice->sizlBitmap = psoFrameBuf->sizlBitmap;
  1214. //psoDevice->iBitmapFormat = psoFrameBuf->iBitmapFormat;
  1215. EngUnlockSurface(psoDevice);
  1216. // We should never overwrite the frame-buffer pointer or section
  1217. // object; This could cause a memory leak. If we hit this assert,
  1218. // we can investigate if this does in fact lead to a memory leak.
  1219. TRC_ASSERT(((pPDev->pFrameBuf == pddFrameBuf) &&
  1220. (pPDev->SectionObject == ddSectionObject)),
  1221. (TB, "Frame buffer or section object pointer overwritten"));
  1222. #ifdef DC_DEBUG
  1223. // NT BUG 539912 - because the above assert is not hit in stress, we
  1224. // change this case to produce an IcaBreakOnDebugger
  1225. if (pPDev->pFrameBuf != pddFrameBuf ||
  1226. pPDev->SectionObject != ddSectionObject) {
  1227. WDIcaBreakOnDebugger();
  1228. }
  1229. #endif
  1230. // Make sure the PDev points to the current Frame Buffer.
  1231. pPDev->pFrameBuf = pddFrameBuf;
  1232. TRC_ALT((TB, "Pointed PDev %p to Frame Buf %p", pPDev,
  1233. pPDev->pFrameBuf));
  1234. // Make sure the pDev points to the current SectionObject
  1235. pPDev->SectionObject = ddSectionObject;
  1236. TRC_ALT((TB, "Pointed PDev %p to Section Object %p", pPDev,
  1237. pPDev->SectionObject));
  1238. }
  1239. bRc = TRUE;
  1240. DC_EXIT_POINT:
  1241. DC_END_FN();
  1242. return bRc;
  1243. }
  1244. /****************************************************************************/
  1245. /* Name: DrvDisconnect */
  1246. /* */
  1247. /* Purpose: Process a disconnect from W32 - clean up the output capture */
  1248. /* code and the connection to the WD. */
  1249. /* */
  1250. /* Returns: TRUE if all is well */
  1251. /* */
  1252. /* Params: IN - channel handle */
  1253. /* IN - file object for channel */
  1254. /* */
  1255. /* Operation: Gives all sub-components notice of the disconnect, and then */
  1256. /* IOCtls to the WD to tell it that we're going. */
  1257. /****************************************************************************/
  1258. BOOL DrvDisconnect(HANDLE channelHandle, PVOID pChannelFileObject)
  1259. {
  1260. DC_BEGIN_FN("DrvDisconnect");
  1261. TRC_NRM((TB, "DrvDisconnect called"));
  1262. #ifdef DC_DEBUG
  1263. // NT BUG 539912 - track calls to DD fns.
  1264. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_DISCONNECT,
  1265. channelHandle, pChannelFileObject, ddConnected, 0);
  1266. #endif
  1267. // Check that we're connected.
  1268. if (ddConnected) {
  1269. // Terminate the dependent components.
  1270. DDDisconnect(FALSE);
  1271. }
  1272. else {
  1273. TRC_ERR((TB, "Disconnect called when not connected"));
  1274. DD_UPD_STATE(DD_DISCONNECT_ERR);
  1275. }
  1276. DC_END_FN();
  1277. return TRUE;
  1278. } /* DrvDisconnect */
  1279. /****************************************************************************/
  1280. /* Name: DrvConnect - see Citrix documentation/code */
  1281. /* */
  1282. /* Purpose: Called when a Winstation is first connected */
  1283. /* */
  1284. /* Returns: TRUE if all is well */
  1285. /* */
  1286. /* Params: IN - channel handle to use to IOCtl to WD */
  1287. /* IN - file object for channel - used on EngFileWrite */
  1288. /* IN - video file object */
  1289. /* IN - cache statistics memory. NB This is doc'd as OUT, but */
  1290. /* the code actually passes a ptr in. */
  1291. /* */
  1292. /* Operation: Save the key parameters */
  1293. /* */
  1294. /* Note that this function is called before DrvEnablePDEV and */
  1295. /* DrvEnableSurface, hence it is not a good place to initialize */
  1296. /* TShare components. This is done later, in DDInit, called */
  1297. /* from DrvEnableSurface. */
  1298. /****************************************************************************/
  1299. BOOL DrvConnect(
  1300. HANDLE channelHandle,
  1301. PVOID pChannelFileObject,
  1302. PVOID pVideoFileObject,
  1303. PVOID pThinWireCache)
  1304. {
  1305. PCACHE_STATISTICS pPerformanceCounters;
  1306. DC_BEGIN_FN("DrvConnect");
  1307. TRC_NRM((TB, "DrvConnect"));
  1308. #ifdef DC_DEBUG
  1309. // NT BUG 539912 - track calls to DD fns.
  1310. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_CONNECT,
  1311. channelHandle, pChannelFileObject, pVideoFileObject, pThinWireCache);
  1312. #endif
  1313. /************************************************************************/
  1314. /* Check for sensible values - the chained DD could get loaded other */
  1315. /* than on a connect call */
  1316. /************************************************************************/
  1317. if ((channelHandle == NULL) ||
  1318. (pChannelFileObject == NULL) ||
  1319. (pVideoFileObject == NULL) ||
  1320. (pThinWireCache == NULL)) {
  1321. TRC_ERR((TB, "Null input params"));
  1322. #ifdef DC_DEBUG
  1323. TRC_ALT((TB, "But load anyway!"));
  1324. return TRUE;
  1325. #endif
  1326. return FALSE;
  1327. }
  1328. #ifdef DC_DEBUG
  1329. if (ddState & DD_DISCONNECT_OUT)
  1330. DD_SET_STATE(DD_WAS_DISCONNECTED);
  1331. DD_UPD_STATE(DD_CONNECT);
  1332. #endif
  1333. // Save the channel handle, and perf counters for later - the other
  1334. // params are currently not needed.
  1335. ddWdHandle = pChannelFileObject;
  1336. pPerformanceCounters = pThinWireCache;
  1337. pPerformanceCounters->ProtocolType = PROTOCOL_ICA;
  1338. pPerformanceCounters->Length = sizeof(ICA_CACHE);
  1339. pddCacheStats = pPerformanceCounters->Specific.IcaCacheStats.ThinWireCache;
  1340. // Note that init is pending.
  1341. ddInitPending = TRUE;
  1342. // Note that we're connected.
  1343. ddConnected = TRUE;
  1344. DC_END_FN();
  1345. return TRUE;
  1346. } /* DrvConnect */
  1347. /****************************************************************************/
  1348. /* Name: DrvReconnect */
  1349. /* */
  1350. /* Pass the IOCtl to the WD, and save off the returned values, as on */
  1351. /* connect. */
  1352. /****************************************************************************/
  1353. BOOL DrvReconnect(HANDLE channelHandle, PVOID pChannelFileObject)
  1354. {
  1355. BOOL rc;
  1356. DC_BEGIN_FN("DrvReconnect");
  1357. TRC_NRM((TB, "DrvReconnect"));
  1358. #ifdef DC_DEBUG
  1359. // NT BUG 539912 - track calls to DD fns.
  1360. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_RECONNECT,
  1361. channelHandle, pChannelFileObject, ddConnected, ddConsole);
  1362. #endif
  1363. // In case the dd has not been unloaded at the end of the previous
  1364. // console shadow, we're getting called to handle this.
  1365. if (ddConsole && ddConnected) {
  1366. // no need to reconnect
  1367. rc = TRUE;
  1368. TRC_ASSERT((ddWdHandle == pChannelFileObject),
  1369. (TB,"Reconnecting with different WD handle for Console Shadow)"));
  1370. DC_QUIT;
  1371. }
  1372. #ifdef DC_DEBUG
  1373. if (ddState & DD_DISCONNECT_OUT)
  1374. DD_SET_STATE(DD_WAS_DISCONNECTED);
  1375. DD_UPD_STATE(DD_RECONNECT_IN);
  1376. #endif
  1377. // Save the channel handle for later - the other params are currently
  1378. // not needed.
  1379. ddWdHandle = pChannelFileObject;
  1380. // Note that we're connected. Do this whether we reconnect
  1381. // successfully or not, as DrvDisconnect is called if we fail to */
  1382. // reconnect.
  1383. ddConnected = TRUE;
  1384. // Reinitialize RDPDD.
  1385. rc = DDInit(NULL, TRUE, ddConsole?TRUE: FALSE, NULL, 0);
  1386. if (!rc) {
  1387. TRC_ERR((TB, "Failed to reinitialize DD"));
  1388. }
  1389. DD_UPD_STATE(DD_RECONNECT_OUT);
  1390. DC_EXIT_POINT:
  1391. DC_END_FN();
  1392. return rc;
  1393. } /* DrvReconnect */
  1394. /****************************************************************************/
  1395. /* DrvResetPDEV - see NT DDK documentation */
  1396. /* */
  1397. /* Allows us to reject dynamic screen changes if necessary */
  1398. /****************************************************************************/
  1399. BOOL DrvResetPDEV(DHPDEV dhpdevOld, DHPDEV dhpdevNew)
  1400. {
  1401. BOOL rc = TRUE;
  1402. ULONG bytesReturned;
  1403. NTSTATUS Status;
  1404. ICA_CHANNEL_END_SHADOW_DATA Data;
  1405. DC_BEGIN_FN("DrvResetPDEV");
  1406. // On the console, we can only allow the display driver to change modes
  1407. // while the connection is not up.
  1408. if (ddConsole && ddConnected) {
  1409. TRC_ALT((TB, "Mode change during console shadow: ending console shadow now"));
  1410. Data.StatusCode = STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE;
  1411. Data.bLogError = TRUE;
  1412. Status = EngFileIoControl(ddWdHandle,
  1413. IOCTL_ICA_CHANNEL_END_SHADOW,
  1414. &Data, sizeof(Data),
  1415. NULL, 0,
  1416. &bytesReturned);
  1417. }
  1418. else {
  1419. TRC_ALT((TB, "Allowing mode change"));
  1420. }
  1421. DC_END_FN();
  1422. return rc;
  1423. }
  1424. /****************************************************************************/
  1425. /* DrvGetDirectDrawInfo - see NT DDK documentation. */
  1426. /* */
  1427. /* Function called by DirectDraw to returns the capabilities of the */
  1428. /* graphics hardware */
  1429. /* */
  1430. /****************************************************************************/
  1431. BOOL
  1432. DrvGetDirectDrawInfo(
  1433. DHPDEV dhpdev,
  1434. DD_HALINFO* pHalInfo,
  1435. DWORD* pdwNumHeaps,
  1436. VIDEOMEMORY* pvmList, // Will be NULL on first call
  1437. DWORD* pdwNumFourCC,
  1438. DWORD* pdwFourCC) // Will be NULL on first call
  1439. {
  1440. BOOL rc = TRUE;
  1441. PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
  1442. BOOL bCanFlip=0;
  1443. DC_BEGIN_FN("DrvGetDirectDrawInfo");
  1444. TRC_NRM((TB, "DrvGetDirectDrawInfo"));
  1445. // DirectDraw only supports 8, 16, 24 or 32 bpp
  1446. if ( (8 != pPDev->cClientBitsPerPel) &&
  1447. (16 != pPDev->cClientBitsPerPel) &&
  1448. (24 != pPDev->cClientBitsPerPel) &&
  1449. (32 != pPDev->cClientBitsPerPel) )
  1450. {
  1451. rc = FALSE;
  1452. DC_QUIT;
  1453. }
  1454. // DirectDraw is not supported if our frame buffer is not allocated as
  1455. // section mem.
  1456. if (pPDev->SectionObject == NULL) {
  1457. TRC_ERR((TB, "The section object is null."));
  1458. rc = FALSE;
  1459. DC_QUIT;
  1460. }
  1461. pHalInfo->dwSize = sizeof(*pHalInfo);
  1462. // Current primary surface attributes. Since HalInfo is zero-initialized
  1463. // by GDI, we only have to fill in the fields which should be non-zero:
  1464. pHalInfo->vmiData.pvPrimary = pPDev->pFrameBuf;
  1465. pHalInfo->vmiData.dwDisplayWidth = pPDev->cxScreen;
  1466. pHalInfo->vmiData.dwDisplayHeight = pPDev->cyScreen;
  1467. pHalInfo->vmiData.lDisplayPitch = pPDev->psoFrameBuf->lDelta;
  1468. pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
  1469. pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
  1470. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = pPDev->cClientBitsPerPel;
  1471. if (pPDev->iBitmapFormat == BMF_8BPP)
  1472. {
  1473. pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
  1474. }
  1475. // These masks will be zero at 8bpp:
  1476. pHalInfo->vmiData.ddpfDisplay.dwRBitMask = pPDev->flRed;
  1477. pHalInfo->vmiData.ddpfDisplay.dwGBitMask = pPDev->flGreen;
  1478. pHalInfo->vmiData.ddpfDisplay.dwBBitMask = pPDev->flBlue;
  1479. if (pPDev->iBitmapFormat == BMF_32BPP)
  1480. {
  1481. pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask
  1482. = ~(pPDev->flRed | pPDev->flGreen | pPDev->flBlue);
  1483. }
  1484. else
  1485. {
  1486. pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask = 0;
  1487. }
  1488. //We don't support flip
  1489. bCanFlip = FALSE;
  1490. // We don't have any video memory for offscreen use
  1491. *pdwNumHeaps = 0;
  1492. // Capabilities supported:
  1493. pHalInfo->ddCaps.dwFXCaps = 0;
  1494. // No hardware support
  1495. pHalInfo->ddCaps.dwCaps = DDCAPS_NOHARDWARE;
  1496. pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  1497. if (bCanFlip)
  1498. {
  1499. pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP;
  1500. }
  1501. // FourCCs supported:
  1502. *pdwNumFourCC = 0;
  1503. // We see rdpdd passes 4bpp to directx in stress, which it does't support
  1504. // so we assert here
  1505. TRC_ASSERT(((pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount != 4) &&
  1506. (pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount != 15)),
  1507. (TB, "RDPDD shoould not pass bpp %d to DirectX",
  1508. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount));
  1509. DC_EXIT_POINT:
  1510. DC_END_FN();
  1511. return rc;
  1512. }
  1513. /****************************************************************************/
  1514. /* DrvEnableDirectDraw - see NT DDK documentation. */
  1515. /* */
  1516. /* GDI calls DrvEnableDirectDraw to obtain pointers to the DirectDraw */
  1517. /* callbacks that the driver supports. */
  1518. /* */
  1519. /****************************************************************************/
  1520. BOOL DrvEnableDirectDraw(
  1521. DHPDEV dhpdev,
  1522. DD_CALLBACKS* pCallBacks,
  1523. DD_SURFACECALLBACKS* pSurfaceCallBacks,
  1524. DD_PALETTECALLBACKS* pPaletteCallBacks)
  1525. {
  1526. BOOL rc = TRUE;
  1527. PDD_PDEV pPDev = (PDD_PDEV)dhpdev;
  1528. DC_BEGIN_FN("DrvEnableDirectDraw");
  1529. TRC_NRM((TB, "DrvEnableDirectDraw"));
  1530. #ifdef DC_DEBUG
  1531. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_ENABLEDIRECTDRAW,
  1532. 0, 0, pPDev->SectionObject, ddSectionObject);
  1533. #endif
  1534. // DirectDraw is not supported if our frame buffer is not allocated as
  1535. // section mem.
  1536. if (pPDev->SectionObject == NULL ) {
  1537. TRC_ERR((TB, "The section object is NULL!"));
  1538. rc = FALSE;
  1539. DC_QUIT;
  1540. }
  1541. pCallBacks->MapMemory = DdMapMemory;
  1542. pCallBacks->dwFlags = DDHAL_CB32_MAPMEMORY;
  1543. pSurfaceCallBacks->Lock = DdLock;
  1544. pSurfaceCallBacks->Unlock = DdUnlock;
  1545. pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_LOCK
  1546. | DDHAL_SURFCB32_UNLOCK;
  1547. DC_EXIT_POINT:
  1548. DC_END_FN();
  1549. return rc;
  1550. }
  1551. /****************************************************************************/
  1552. /* DrvDisableDirectDraw - see NT DDK documentation. */
  1553. /* */
  1554. /****************************************************************************/
  1555. VOID DrvDisableDirectDraw(
  1556. DHPDEV dhpdev)
  1557. {
  1558. DC_BEGIN_FN("DrvDisableDirectDraw");
  1559. TRC_NRM((TB, "DrvDisableDirectDraw"));
  1560. #ifdef DC_DEBUG
  1561. DBG_DD_FNCALL_HIST_ADD( DBG_DD_FNCALL_DRV_DISABLEDIRECTDRAW,
  1562. 0, 0, 0, ddSectionObject);
  1563. #endif
  1564. //Do nothing here
  1565. DC_END_FN();
  1566. }