Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2928 lines
93 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mcdsrv.c
  3. *
  4. * This module contains the trusted component of the MCD server-side engine.
  5. * This module performs handle management and parameter-checking and validation
  6. * to the extent possible. This module also makes the calls to the device
  7. * driver, and provides callbacks to the driver for things such as handle
  8. * referencing.
  9. *
  10. * Goals
  11. * -----
  12. *
  13. * Pervasive throughout this implementation is the influence of the
  14. * following goals:
  15. *
  16. * 1. Robustness
  17. *
  18. * Windows NT is first and foremost a robust operating system. There
  19. * is a simple measure for this: a robust system should never crash.
  20. * Because the display driver is a trusted component of the operating
  21. * system, and because the MCD is directly callable from OpenGL from
  22. * the client side of the OS (and thus untrusted), this has a significant
  23. * impact on the way we must do things.
  24. *
  25. * 2. Performance
  26. *
  27. * Performance is the 'raison d'etre' of the MCD; we have tried to
  28. * have as thin a layer above the rendering code as we could.
  29. *
  30. * 3. Portability
  31. *
  32. * This implementation is intended portable to different processor types,
  33. * and to the Windows 95 operating system.
  34. *
  35. * Obviously, Windows 95 implementations may choose to have a different
  36. * order of priority for these goals, and so some of the robustness
  37. * code may be eliminated. But it is still recommended that it be kept;
  38. * the overhead is reasonably minimal, and people really don't like it
  39. * when their systems crash...
  40. *
  41. * The Rules of Robustness
  42. * -----------------------
  43. *
  44. * 1. Nothing given by the caller can be trusted.
  45. *
  46. * For example, handles cannot be trusted to be valid. Handles passed
  47. * in may actually be for objects not owned by the caller. Pointers
  48. * and offsets may not be correctly aligned. Pointers, offsets, and
  49. * coordinates may be out of bounds.
  50. *
  51. * 2. Parameters can be asynchronously modified at any time.
  52. *
  53. * Many commands come from shared memory sections, and any data therein
  54. * may be asynchronously modified by other threads in the calling
  55. * application. As such, parameters may never be validated in-place
  56. * in the shared section, because the application may corrupt the data
  57. * after validation but before its use. Instead, parameters must always
  58. * be first copied out of the window, and then validated on the safe
  59. * copy.
  60. *
  61. * 3. We must clean up.
  62. *
  63. * Applications may die at any time before calling the appropriate
  64. * clean up functions. As such, we have to be prepared to clean up
  65. * any resources ourselves when the application dies.
  66. *
  67. * Copyright (c) 1994, 1995, 1996 Microsoft Corporation
  68. *
  69. \**************************************************************************/
  70. #include <stddef.h>
  71. #include <stdarg.h>
  72. #include <windows.h>
  73. #include <wtypes.h>
  74. #include <winddi.h>
  75. #include <mcdesc.h>
  76. #include "mcdrv.h"
  77. #include <mcd2hack.h>
  78. #include "mcd.h"
  79. #include "mcdint.h"
  80. #include "mcdrvint.h"
  81. // Checks MCD version to see if the driver can accept direct buffer
  82. // access. Direct access was introduced in 1.1.
  83. #define SUPPORTS_DIRECT(pGlobal) \
  84. ((pGlobal)->verMinor >= 0x10 || (pGlobal)->verMajor > 1)
  85. ////////////////////////////////////////////////////////////////////////////
  86. //
  87. //
  88. // Declarations for internal support functions for an MCD locking mechanism
  89. // that can be used to synchronize multiple processes/thread that use MCD.
  90. //
  91. //
  92. ////////////////////////////////////////////////////////////////////////////
  93. ULONG MCDSrvLock(MCDWINDOWPRIV *);
  94. VOID MCDSrvUnlock(MCDWINDOWPRIV *);
  95. ////////////////////////////////////////////////////////////////////////////
  96. //
  97. // Declarations for internal per-driver-instance list that all global
  98. // data is kept in. The list is indexed by pso.
  99. //
  100. ////////////////////////////////////////////////////////////////////////////
  101. // Space for one old-style driver to hold its information statically.
  102. MCDGLOBALINFO gStaticGlobalInfo;
  103. BOOL MCDSrvInitGlobalInfo(void);
  104. void MCDSrvUninitGlobalInfo(void);
  105. MCDGLOBALINFO *MCDSrvAddGlobalInfo(SURFOBJ *pso);
  106. MCDGLOBALINFO *MCDSrvGetGlobalInfo(SURFOBJ *pso);
  107. ////////////////////////////////////////////////////////////////////////////
  108. //
  109. //
  110. // Server subsystem entry points.
  111. //
  112. //
  113. ////////////////////////////////////////////////////////////////////////////
  114. //****************************************************************************
  115. //
  116. // MCD initialization functions.
  117. //
  118. // NT 4.0 MCD support exported MCDEngInit which display drivers call
  119. // to initialize the MCD server-side code. MCDEngInit only allowed
  120. // one driver instance to initialize and never uninitialized.
  121. //
  122. // This doesn't work very well with mode changes or multimon so for
  123. // NT 5.0 MCDEngInitEx was added. MCDEngInitEx has two differences
  124. // from MCDEngInit:
  125. // 1. MCDEngInitEx takes a table of global driver functions instead of
  126. // just the MCDrvGetEntryPoints function. Currently the table only
  127. // has one entry for MCDrvGetEntryPoints but it allows for future
  128. // expansion.
  129. // 2. Calling MCDEngInitEx implies that the driver will call MCDEngUninit
  130. // so that per-driver-instance state can be cleaned up.
  131. //
  132. //****************************************************************************
  133. BOOL MCDEngInternalInit(SURFOBJ *pso,
  134. MCDGLOBALDRIVERFUNCS *pMCDGlobalDriverFuncs,
  135. BOOL bAddPso)
  136. {
  137. MCDSURFACE mcdSurface;
  138. MCDDRIVER mcdDriver;
  139. MCDGLOBALINFO *pGlobal;
  140. mcdSurface.pWnd = NULL;
  141. mcdSurface.pwo = NULL;
  142. mcdSurface.surfaceFlags = 0;
  143. mcdSurface.pso = pso;
  144. memset(&mcdDriver, 0, sizeof(MCDDRIVER));
  145. mcdDriver.ulSize = sizeof(MCDDRIVER);
  146. if (pMCDGlobalDriverFuncs->pMCDrvGetEntryPoints == NULL ||
  147. !pMCDGlobalDriverFuncs->pMCDrvGetEntryPoints(&mcdSurface, &mcdDriver))
  148. {
  149. MCDBG_PRINT("MCDEngInit: Could not get driver entry points.");
  150. return FALSE;
  151. }
  152. if (bAddPso)
  153. {
  154. if (!MCDSrvInitGlobalInfo())
  155. {
  156. return FALSE;
  157. }
  158. pGlobal = MCDSrvAddGlobalInfo(pso);
  159. if (pGlobal == NULL)
  160. {
  161. MCDSrvUninitGlobalInfo();
  162. return FALSE;
  163. }
  164. }
  165. else
  166. {
  167. pGlobal = &gStaticGlobalInfo;
  168. }
  169. // Guaranteed to be zero-filled and pso set so only fill in interesting
  170. // fields.
  171. // verMajor and verMinor can not be filled out yet so they are
  172. // left at zero to indicate the most conservative possible version
  173. // number. They are filled in with correct information when DRIVERINFO
  174. // is processed.
  175. pGlobal->mcdDriver = mcdDriver;
  176. pGlobal->mcdGlobalFuncs = *pMCDGlobalDriverFuncs;
  177. return TRUE;
  178. }
  179. #define MGDF_SIZE (sizeof(ULONG)+sizeof(void *))
  180. BOOL WINAPI MCDEngInitEx(SURFOBJ *pso,
  181. MCDGLOBALDRIVERFUNCS *pMCDGlobalDriverFuncs,
  182. void *pReserved)
  183. {
  184. if (pso == NULL ||
  185. pMCDGlobalDriverFuncs->ulSize != MGDF_SIZE ||
  186. pReserved != NULL)
  187. {
  188. return FALSE;
  189. }
  190. return MCDEngInternalInit(pso, pMCDGlobalDriverFuncs, TRUE);
  191. }
  192. BOOL WINAPI MCDEngInit(SURFOBJ *pso,
  193. MCDRVGETENTRYPOINTSFUNC pGetDriverEntryFunc)
  194. {
  195. MCDGLOBALDRIVERFUNCS mgdf;
  196. // The old-style initialization function is being called so
  197. // we must assume that the uninit function will not be called.
  198. // This means that we cannot allocate resources for the global
  199. // info list since we won't be able to clean them up. Without
  200. // a global info list we are restricted to using global variables
  201. // and thus only one old-style init is allowed per load.
  202. if (pso == NULL ||
  203. pGetDriverEntryFunc == NULL ||
  204. gStaticGlobalInfo.pso != NULL)
  205. {
  206. return FALSE;
  207. }
  208. gStaticGlobalInfo.pso = pso;
  209. memset(&mgdf, 0, sizeof(mgdf));
  210. mgdf.ulSize = sizeof(ULONG)+sizeof(void *);
  211. mgdf.pMCDrvGetEntryPoints = pGetDriverEntryFunc;
  212. return MCDEngInternalInit(pso, &mgdf, FALSE);
  213. }
  214. //****************************************************************************
  215. // BOOL MCDEngEscFilter(SURFOBJ *, ULONG, ULONG, VOID *, ULONG cjOut,
  216. // VOID *pvOut)
  217. //
  218. // MCD escape filter. This function should return TRUE for any
  219. // escapes functions which this filter processed, FALSE otherwise (in which
  220. // case the caller should continue to process the escape).
  221. //****************************************************************************
  222. BOOL WINAPI MCDEngEscFilter(SURFOBJ *pso, ULONG iEsc,
  223. ULONG cjIn, VOID *pvIn,
  224. ULONG cjOut, VOID *pvOut, ULONG_PTR *pRetVal)
  225. {
  226. MCDEXEC MCDExec;
  227. MCDESC_HEADER *pmeh;
  228. MCDESC_HEADER_NTPRIVATE *pmehPriv;
  229. switch (iEsc)
  230. {
  231. case QUERYESCSUPPORT:
  232. // Note: we don't need to check cjIn for this case since
  233. // NT's GDI validates this for use.
  234. return (BOOL)(*pRetVal = (*(ULONG *) pvIn == MCDFUNCS));
  235. case MCDFUNCS:
  236. MCDExec.pmeh = pmeh = (MCDESC_HEADER *)pvIn;
  237. // This is an MCD function. Under Windows NT, we've
  238. // got an MCDESC_HEADER_NTPRIVATE structure which we may need
  239. // to use if the escape does not use driver-created
  240. // memory.
  241. // Package the things we need into the MCDEXEC structure:
  242. pmehPriv = (MCDESC_HEADER_NTPRIVATE *)(pmeh + 1);
  243. MCDExec.ppwoMulti = (WNDOBJ **)pmehPriv->pExtraWndobj;
  244. MCDExec.MCDSurface.pwo = pmehPriv->pwo;
  245. if (pmeh->dwWindow != 0)
  246. {
  247. MCDWINDOWOBJ *pmwo;
  248. // The client side code has given us back the handle
  249. // to the MCDWINDOW structure as an identifier. Since it
  250. // came from user-mode it is suspect and must be validated
  251. // before continuing.
  252. pmwo = (MCDWINDOWOBJ *)
  253. MCDEngGetPtrFromHandle((MCDHANDLE)pmeh->dwWindow,
  254. MCDHANDLE_WINDOW);
  255. if (pmwo == NULL)
  256. {
  257. return FALSE;
  258. }
  259. MCDExec.pWndPriv = &pmwo->MCDWindowPriv;
  260. }
  261. else
  262. {
  263. MCDExec.pWndPriv = NULL;
  264. }
  265. MCDExec.MCDSurface.pso = pso;
  266. MCDExec.MCDSurface.pWnd = (MCDWINDOW *)MCDExec.pWndPriv;
  267. MCDExec.MCDSurface.surfaceFlags = 0;
  268. MCDExec.pvOut = pvOut;
  269. MCDExec.cjOut = cjOut;
  270. if (!pmeh->hSharedMem) {
  271. *pRetVal = (ULONG)FALSE;
  272. if (!pmehPriv->pBuffer)
  273. return (ULONG)TRUE;
  274. if (pmehPriv->bufferSize < sizeof(MCDCMDI))
  275. return (ULONG)TRUE;
  276. MCDExec.pCmd = (MCDCMDI *)(pmehPriv->pBuffer);
  277. MCDExec.pCmdEnd = (MCDCMDI *)((char *)MCDExec.pCmd +
  278. pmehPriv->bufferSize);
  279. MCDExec.inBufferSize = pmehPriv->bufferSize;
  280. MCDExec.hMCDMem = (MCDHANDLE)NULL;
  281. } else
  282. MCDExec.hMCDMem = pmeh->hSharedMem;
  283. ENTER_MCD_LOCK();
  284. *pRetVal = MCDSrvProcess(&MCDExec);
  285. LEAVE_MCD_LOCK();
  286. return TRUE;
  287. default:
  288. return (ULONG)FALSE;
  289. break;
  290. }
  291. return (ULONG)FALSE; // Should never get here...
  292. }
  293. //****************************************************************************
  294. // BOOL MCDEngSetMemStatus(MCDMEM *pMCDMem, ULONG status);
  295. //
  296. // Sets the memory status to the desired value. This is called by the
  297. // driver to set and reset the busy flags for a chunk of memory to allow
  298. // DMA.
  299. //****************************************************************************
  300. BOOL WINAPI MCDEngSetMemStatus(MCDMEM *pMCDMem, ULONG status)
  301. {
  302. MCDMEMOBJ *pMemObj;
  303. ULONG retVal;
  304. pMemObj = (MCDMEMOBJ *)((char *)pMCDMem - sizeof(MCDHANDLETYPE));
  305. if (pMemObj->type != MCDHANDLE_MEM) {
  306. return FALSE;
  307. }
  308. switch (status) {
  309. case MCDRV_MEM_BUSY:
  310. pMemObj->lockCount++;
  311. break;
  312. case MCDRV_MEM_NOT_BUSY:
  313. pMemObj->lockCount--;
  314. break;
  315. default:
  316. return (ULONG)FALSE;
  317. }
  318. return TRUE;
  319. }
  320. ////////////////////////////////////////////////////////////////////////////
  321. //
  322. //
  323. // Private server-side funtions.
  324. //
  325. //
  326. ////////////////////////////////////////////////////////////////////////////
  327. //****************************************************************************
  328. // CallGetBuffers
  329. //
  330. // Wrapper for MCDrvGetBuffers that does appropriate checks, setup,
  331. // cache management and data translation.
  332. //****************************************************************************
  333. PRIVATE
  334. ULONG CallGetBuffers(MCDEXEC *pMCDExec, MCDRC *pRc, MCDRECTBUFFERS *pBuf)
  335. {
  336. ULONG ulRet;
  337. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvGetBuffers)
  338. {
  339. MCDBG_PRINT("MCDrvGetBuffers: missing entry point.");
  340. return FALSE;
  341. }
  342. // Clip lists need to be valid so drivers can do different
  343. // things based on whether the surface is trivially visible or not.
  344. GetScissorClip(pMCDExec->pWndPriv, pMCDExec->pRcPriv);
  345. // Should be casting to MCDRECTBUFFERS with correct
  346. // 1.1 header.
  347. ulRet = (ULONG)(*pMCDExec->pGlobal->mcdDriver.pMCDrvGetBuffers)
  348. (&pMCDExec->MCDSurface, pRc, (MCDBUFFERS *)pBuf);
  349. // Update cached buffers information on success.
  350. if (ulRet)
  351. {
  352. if (SUPPORTS_DIRECT(pMCDExec->pGlobal))
  353. {
  354. // This is a 1.1 or greater driver and has returned
  355. // full MCDRECTBUFFERS information. Cache it
  356. // for possible later use.
  357. pMCDExec->pWndPriv->bBuffersValid = TRUE;
  358. pMCDExec->pWndPriv->mbufCache = *pBuf;
  359. }
  360. else
  361. {
  362. MCDBUFFERS mbuf;
  363. MCDRECTBUFFERS *mrbuf;
  364. // This is a 1.0 driver and has only returned
  365. // MCDBUFFERS information. Expand it into
  366. // an MCDRECTBUFFERS. The rectangles don't
  367. // really matter to software so they can
  368. // be zeroed.
  369. mbuf = *(MCDBUFFERS *)pBuf;
  370. mrbuf = pBuf;
  371. *(MCDBUF *)&mrbuf->mcdFrontBuf = mbuf.mcdFrontBuf;
  372. memset(&mrbuf->mcdFrontBuf.bufPos, 0, sizeof(RECTL));
  373. *(MCDBUF *)&mrbuf->mcdBackBuf = mbuf.mcdBackBuf;
  374. memset(&mrbuf->mcdBackBuf.bufPos, 0, sizeof(RECTL));
  375. *(MCDBUF *)&mrbuf->mcdDepthBuf = mbuf.mcdDepthBuf;
  376. memset(&mrbuf->mcdDepthBuf.bufPos, 0, sizeof(RECTL));
  377. }
  378. }
  379. return ulRet;
  380. }
  381. //****************************************************************************
  382. // ULONG_PTR MCDSrvProcess(MCDEXEC *pMCDExec)
  383. //
  384. // This is the main MCD function handler. At this point, there should
  385. // be no platform-specific code since these should have been resolved by
  386. // the entry function.
  387. //****************************************************************************
  388. PRIVATE
  389. ULONG_PTR MCDSrvProcess(MCDEXEC *pMCDExec)
  390. {
  391. UCHAR *pMaxMem;
  392. UCHAR *pMinMem;
  393. MCDESC_HEADER *pmeh = pMCDExec->pmeh;
  394. MCDRC *pRc;
  395. MCDMEM *pMCDMem;
  396. MCDMEMOBJ *pMemObj;
  397. MCDRCPRIV *pRcPriv;
  398. ULONG_PTR ulRet;
  399. // If the command buffer is in shared memory, dereference the memory
  400. // from the handle and check the bounds.
  401. if (pMCDExec->hMCDMem)
  402. {
  403. GET_MEMOBJ_RETVAL(pMemObj, pmeh->hSharedMem, FALSE);
  404. pMinMem = pMemObj->MCDMem.pMemBase;
  405. // Note: we ignore the memory size in the header since it doesn't
  406. // really help us...
  407. pMaxMem = pMinMem + pMemObj->MCDMem.memSize;
  408. pMCDExec->pCmd = (MCDCMDI *)((char *)pmeh->pSharedMem);
  409. pMCDExec->pCmdEnd = (MCDCMDI *)pMaxMem;
  410. CHECK_MEM_RANGE_RETVAL(pMCDExec->pCmd, pMinMem, pMaxMem, FALSE);
  411. pMCDExec->inBufferSize = pmeh->sharedMemSize;
  412. pMCDExec->pMemObj = pMemObj;
  413. } else
  414. pMCDExec->pMemObj = (MCDMEMOBJ *)NULL;
  415. // Get the rendering context if we have one, and process the command:
  416. if (pmeh->hRC)
  417. {
  418. MCDRCOBJ *pRcObj;
  419. pRcObj = (MCDRCOBJ *)MCDEngGetPtrFromHandle(pmeh->hRC, MCDHANDLE_RC);
  420. if (!pRcObj)
  421. {
  422. MCDBG_PRINT("MCDSrvProcess: Invalid rendering context handle %x.",
  423. pmeh->hRC);
  424. return FALSE;
  425. }
  426. pMCDExec->pRcPriv = pRcPriv = pRcObj->pRcPriv;
  427. if (!pRcPriv->bValid)
  428. {
  429. MCDBG_PRINT("MCDSrvProcess: RC has been invalidated for this window.");
  430. return FALSE;
  431. }
  432. if ((!pMCDExec->pWndPriv)) {
  433. if (pMCDExec->pCmd->command != MCD_BINDCONTEXT) {
  434. MCDBG_PRINT("MCDSrvProcess: NULL WndObj with RC.");
  435. return FALSE;
  436. }
  437. } else {
  438. // Validate the window in the RC with the window for this escape:
  439. if ((pRcPriv->hWnd != pMCDExec->pWndPriv->hWnd) &&
  440. (pMCDExec->pCmd->command != MCD_BINDCONTEXT))
  441. {
  442. MCDBG_PRINT("MCDSrvProcess: Invalid RC for this window.");
  443. return FALSE;
  444. }
  445. }
  446. // For Win95, we need to poll for the clip region:
  447. // Clipping needs to be un-broken
  448. if (pMCDExec->MCDSurface.pwo != NULL)
  449. {
  450. MCDEngUpdateClipList(pMCDExec->MCDSurface.pwo);
  451. }
  452. pMCDExec->MCDSurface.surfaceFlags |= pRcPriv->surfaceFlags;
  453. } else {
  454. pMCDExec->pRcPriv = (MCDRCPRIV *)NULL;
  455. }
  456. // Get global driver information.
  457. if (pMCDExec->pWndPriv != NULL)
  458. {
  459. pMCDExec->pGlobal = pMCDExec->pWndPriv->pGlobal;
  460. }
  461. else if (pMCDExec->pRcPriv != NULL)
  462. {
  463. pMCDExec->pGlobal = pMCDExec->pRcPriv->pGlobal;
  464. }
  465. else
  466. {
  467. pMCDExec->pGlobal =
  468. MCDSrvGetGlobalInfo(pMCDExec->MCDSurface.pso);
  469. if (pMCDExec->pGlobal == NULL)
  470. {
  471. MCDBG_PRINT("Unable to find global information");
  472. return FALSE;
  473. }
  474. }
  475. // If direct surface information was included then
  476. // fill out the extra surface information in the MCDSURFACE
  477. // NOCLIP setting?
  478. #if MCD_VER_MAJOR >= 2 || (MCD_VER_MAJOR == 1 && MCD_VER_MINOR >= 0x10)
  479. pMCDExec->MCDSurface.direct.mcdFrontBuf.bufFlags = 0;
  480. pMCDExec->MCDSurface.direct.mcdBackBuf.bufFlags = 0;
  481. pMCDExec->MCDSurface.direct.mcdDepthBuf.bufFlags = 0;
  482. pMCDExec->MCDSurface.frontId = 0;
  483. pMCDExec->MCDSurface.backId = 0;
  484. pMCDExec->MCDSurface.depthId = 0;
  485. if (pmeh->flags & MCDESC_FL_SURFACES)
  486. {
  487. pMCDExec->MCDSurface.surfaceFlags |= MCDSURFACE_DIRECT;
  488. // Refresh cached buffer information if it's invalid
  489. // and we need it
  490. if (pmeh->msrfColor.hSurf == NULL &&
  491. pmeh->msrfDepth.hSurf == NULL)
  492. {
  493. if (pMCDExec->pWndPriv == NULL)
  494. {
  495. return FALSE;
  496. }
  497. if (!pMCDExec->pWndPriv->bBuffersValid)
  498. {
  499. MCDRECTBUFFERS mbuf;
  500. if (!CallGetBuffers(pMCDExec, NULL, &mbuf))
  501. {
  502. return FALSE;
  503. }
  504. }
  505. pMCDExec->MCDSurface.direct = pMCDExec->pWndPriv->mbufCache;
  506. }
  507. else
  508. {
  509. if (pmeh->msrfColor.hSurf != NULL)
  510. {
  511. pMCDExec->MCDSurface.frontId = (DWORD)
  512. pmeh->msrfColor.hSurf;
  513. pMCDExec->MCDSurface.direct.mcdFrontBuf.bufFlags =
  514. MCDBUF_ENABLED;
  515. pMCDExec->MCDSurface.direct.mcdFrontBuf.bufOffset =
  516. pmeh->msrfColor.lOffset;
  517. pMCDExec->MCDSurface.direct.mcdFrontBuf.bufStride =
  518. pmeh->msrfColor.lStride;
  519. pMCDExec->MCDSurface.direct.mcdFrontBuf.bufPos =
  520. pmeh->msrfColor.rclPos;
  521. }
  522. if (pmeh->msrfDepth.hSurf != NULL)
  523. {
  524. pMCDExec->MCDSurface.depthId = (DWORD)
  525. pmeh->msrfDepth.hSurf;
  526. pMCDExec->MCDSurface.direct.mcdDepthBuf.bufFlags =
  527. MCDBUF_ENABLED;
  528. pMCDExec->MCDSurface.direct.mcdDepthBuf.bufOffset =
  529. pmeh->msrfDepth.lOffset;
  530. pMCDExec->MCDSurface.direct.mcdDepthBuf.bufStride =
  531. pmeh->msrfDepth.lStride;
  532. pMCDExec->MCDSurface.direct.mcdDepthBuf.bufPos =
  533. pmeh->msrfDepth.rclPos;
  534. }
  535. }
  536. }
  537. #endif // 1.1
  538. /////////////////////////////////////////////////////////////////
  539. // If the drawing-batch flag is set, call the main driver drawing
  540. // routine:
  541. /////////////////////////////////////////////////////////////////
  542. if (pmeh->flags & MCDESC_FL_BATCH)
  543. {
  544. CHECK_FOR_RC(pMCDExec);
  545. CHECK_FOR_MEM(pMCDExec);
  546. GetScissorClip(pMCDExec->pWndPriv, pMCDExec->pRcPriv);
  547. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvDraw)
  548. {
  549. if (pMCDExec->pGlobal->mcdDriver.pMCDrvSync)
  550. {
  551. (*pMCDExec->pGlobal->mcdDriver.pMCDrvSync)(&pMCDExec->MCDSurface,
  552. &pMCDExec->pRcPriv->MCDRc);
  553. }
  554. return (ULONG_PTR)pMCDExec->pCmd;
  555. }
  556. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvDraw)(&pMCDExec->MCDSurface,
  557. &pMCDExec->pRcPriv->MCDRc, &pMemObj->MCDMem,
  558. (UCHAR *)pMCDExec->pCmd, (UCHAR *)pMCDExec->pCmdEnd);
  559. }
  560. if (pmeh->flags & MCDESC_FL_CREATE_CONTEXT)
  561. {
  562. MCDCREATECONTEXT *pmcc = (MCDCREATECONTEXT *)pMCDExec->pCmd;
  563. MCDRCINFOPRIV *pMcdRcInfo = pmcc->pRcInfo;
  564. CHECK_SIZE_IN(pMCDExec, MCDCREATECONTEXT);
  565. CHECK_SIZE_OUT(pMCDExec, MCDRCINFOPRIV);
  566. try {
  567. EngProbeForRead(pMcdRcInfo, sizeof(MCDRCINFOPRIV),
  568. sizeof(ULONG));
  569. RtlCopyMemory(pMCDExec->pvOut, pMcdRcInfo,
  570. sizeof(MCDRCINFOPRIV));
  571. } except (EXCEPTION_EXECUTE_HANDLER) {
  572. MCDBG_PRINT("MCDrvCreateContext: Invalid memory for MCDRCINFO.");
  573. return FALSE;
  574. }
  575. pMcdRcInfo = (MCDRCINFOPRIV *)pMCDExec->pvOut;
  576. pMcdRcInfo->mri.requestFlags = 0;
  577. return (ULONG_PTR)MCDSrvCreateContext(&pMCDExec->MCDSurface,
  578. pMcdRcInfo, pMCDExec->pGlobal,
  579. pmcc->ipfd, pmcc->iLayer,
  580. pmcc->escCreate.hwnd,
  581. pmcc->escCreate.flags,
  582. pmcc->mcdFlags);
  583. }
  584. ////////////////////////////////////////////////////////////////////
  585. // Now, process all of the non-batched drawing and utility commands:
  586. ////////////////////////////////////////////////////////////////////
  587. switch (pMCDExec->pCmd->command) {
  588. case MCD_DESCRIBEPIXELFORMAT:
  589. CHECK_SIZE_IN(pMCDExec, MCDPIXELFORMATCMDI);
  590. if (pMCDExec->pvOut) {
  591. CHECK_SIZE_OUT(pMCDExec, MCDPIXELFORMAT);
  592. }
  593. {
  594. MCDPIXELFORMATCMDI *pMCDPixelFormat =
  595. (MCDPIXELFORMATCMDI *)pMCDExec->pCmd;
  596. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvDescribePixelFormat)
  597. return 0;
  598. return (*pMCDExec->pGlobal->mcdDriver.pMCDrvDescribePixelFormat)
  599. (&pMCDExec->MCDSurface,
  600. pMCDPixelFormat->iPixelFormat,
  601. pMCDExec->cjOut,
  602. pMCDExec->pvOut, 0);
  603. }
  604. case MCD_DRIVERINFO:
  605. CHECK_SIZE_OUT(pMCDExec, MCDDRIVERINFOI);
  606. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvInfo)
  607. return FALSE;
  608. ulRet = (*pMCDExec->pGlobal->mcdDriver.pMCDrvInfo)
  609. (&pMCDExec->MCDSurface,
  610. (MCDDRIVERINFO *)pMCDExec->pvOut);
  611. if (ulRet)
  612. {
  613. // Copy driver function information so that the client
  614. // side can optimize calls by checking for functions on the
  615. // client side.
  616. memcpy(&((MCDDRIVERINFOI *)pMCDExec->pvOut)->mcdDriver,
  617. &pMCDExec->pGlobal->mcdDriver, sizeof(MCDDRIVER));
  618. // Save version information in global info.
  619. pMCDExec->pGlobal->verMajor =
  620. ((MCDDRIVERINFO *)pMCDExec->pvOut)->verMajor;
  621. pMCDExec->pGlobal->verMinor =
  622. ((MCDDRIVERINFO *)pMCDExec->pvOut)->verMinor;
  623. }
  624. return ulRet;
  625. case MCD_DELETERC:
  626. CHECK_FOR_RC(pMCDExec);
  627. return (ULONG_PTR)DestroyMCDObj(pmeh->hRC, MCDHANDLE_RC);
  628. case MCD_ALLOC:
  629. CHECK_SIZE_IN(pMCDExec, MCDALLOCCMDI);
  630. CHECK_SIZE_OUT(pMCDExec, MCDHANDLE *);
  631. CHECK_FOR_RC(pMCDExec);
  632. {
  633. MCDALLOCCMDI *pAllocCmd =
  634. (MCDALLOCCMDI *)pMCDExec->pCmd;
  635. return (ULONG_PTR)MCDSrvAllocMem(pMCDExec, pAllocCmd->numBytes,
  636. pAllocCmd->flags,
  637. (MCDHANDLE *)pMCDExec->pvOut);
  638. }
  639. case MCD_FREE:
  640. CHECK_SIZE_IN(pMCDExec, MCDFREECMDI);
  641. {
  642. MCDFREECMDI *pFreeCmd =
  643. (MCDFREECMDI *)pMCDExec->pCmd;
  644. return (ULONG_PTR)DestroyMCDObj(pFreeCmd->hMCDMem, MCDHANDLE_MEM);
  645. }
  646. case MCD_STATE:
  647. CHECK_SIZE_IN(pMCDExec, MCDSTATECMDI);
  648. CHECK_FOR_RC(pMCDExec);
  649. CHECK_FOR_MEM(pMCDExec);
  650. {
  651. MCDSTATECMDI *pStateCmd =
  652. (MCDSTATECMDI *)pMCDExec->pCmd;
  653. UCHAR *pStart = (UCHAR *)(pStateCmd + 1);
  654. LONG totalBytes = pMCDExec->inBufferSize -
  655. sizeof(MCDSTATECMDI);
  656. if (totalBytes < 0) {
  657. MCDBG_PRINT("MCDState: state buffer too small ( < 0).");
  658. return FALSE;
  659. }
  660. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvState) {
  661. MCDBG_PRINT("MCDrvState: missing entry point.");
  662. return FALSE;
  663. }
  664. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvState)(&pMCDExec->MCDSurface,
  665. &pMCDExec->pRcPriv->MCDRc, &pMemObj->MCDMem, pStart,
  666. totalBytes, pStateCmd->numStates);
  667. }
  668. case MCD_VIEWPORT:
  669. CHECK_SIZE_IN(pMCDExec, MCDVIEWPORTCMDI);
  670. CHECK_FOR_RC(pMCDExec);
  671. {
  672. MCDVIEWPORTCMDI *pViewportCmd =
  673. (MCDVIEWPORTCMDI *)pMCDExec->pCmd;
  674. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvViewport) {
  675. MCDBG_PRINT("MCDrvViewport: missing entry point.");
  676. return FALSE;
  677. }
  678. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvViewport)(&pMCDExec->MCDSurface,
  679. &pMCDExec->pRcPriv->MCDRc, &pViewportCmd->MCDViewport);
  680. }
  681. case MCD_QUERYMEMSTATUS:
  682. CHECK_SIZE_IN(pMCDExec, MCDMEMSTATUSCMDI);
  683. {
  684. MCDMEMSTATUSCMDI *pQueryMemCmd =
  685. (MCDMEMSTATUSCMDI *)pMCDExec->pCmd;
  686. return MCDSrvQueryMemStatus(pMCDExec, pQueryMemCmd->hMCDMem);
  687. }
  688. case MCD_READSPAN:
  689. case MCD_WRITESPAN:
  690. CHECK_SIZE_IN(pMCDExec, MCDSPANCMDI);
  691. CHECK_FOR_RC(pMCDExec);
  692. GetScissorClip(pMCDExec->pWndPriv, pMCDExec->pRcPriv);
  693. {
  694. MCDSPANCMDI *pSpanCmd =
  695. (MCDSPANCMDI *)pMCDExec->pCmd;
  696. GET_MEMOBJ_RETVAL(pMemObj, pSpanCmd->hMem, FALSE);
  697. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvSpan) {
  698. MCDBG_PRINT("MCDrvSpan: missing entry point.");
  699. return FALSE;
  700. }
  701. pMinMem = pMemObj->MCDMem.pMemBase;
  702. pMaxMem = pMinMem + pMemObj->MCDMem.memSize;
  703. // At least check that the first pixel is in range. The driver
  704. // must validate the end pixel...
  705. CHECK_MEM_RANGE_RETVAL(pSpanCmd->MCDSpan.pPixels, pMinMem, pMaxMem, FALSE);
  706. if (pMCDExec->pCmd->command == MCD_READSPAN)
  707. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvSpan)(&pMCDExec->MCDSurface,
  708. &pMCDExec->pRcPriv->MCDRc, &pMemObj->MCDMem, &pSpanCmd->MCDSpan, TRUE);
  709. else
  710. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvSpan)(&pMCDExec->MCDSurface,
  711. &pMCDExec->pRcPriv->MCDRc, &pMemObj->MCDMem, &pSpanCmd->MCDSpan, FALSE);
  712. }
  713. case MCD_CLEAR:
  714. CHECK_SIZE_IN(pMCDExec, MCDCLEARCMDI);
  715. CHECK_FOR_RC(pMCDExec);
  716. GetScissorClip(pMCDExec->pWndPriv, pMCDExec->pRcPriv);
  717. {
  718. MCDCLEARCMDI *pClearCmd =
  719. (MCDCLEARCMDI *)pMCDExec->pCmd;
  720. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvClear) {
  721. MCDBG_PRINT("MCDrvClear: missing entry point.");
  722. return FALSE;
  723. }
  724. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvClear)(&pMCDExec->MCDSurface,
  725. &pMCDExec->pRcPriv->MCDRc, pClearCmd->buffers);
  726. }
  727. case MCD_SWAP:
  728. CHECK_SIZE_IN(pMCDExec, MCDSWAPCMDI);
  729. CHECK_FOR_WND(pMCDExec);
  730. GetScissorClip(pMCDExec->pWndPriv, NULL);
  731. {
  732. MCDSWAPCMDI *pSwapCmd =
  733. (MCDSWAPCMDI *)pMCDExec->pCmd;
  734. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvSwap) {
  735. MCDBG_PRINT("MCDrvSwap: missing entry point.");
  736. return FALSE;
  737. }
  738. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvSwap)
  739. (&pMCDExec->MCDSurface,
  740. pSwapCmd->flags);
  741. }
  742. case MCD_SCISSOR:
  743. CHECK_SIZE_IN(pMCDExec, MCDSCISSORCMDI);
  744. CHECK_FOR_RC(pMCDExec);
  745. {
  746. MCDSCISSORCMDI *pMCDScissor = (MCDSCISSORCMDI *)pMCDExec->pCmd;
  747. return (ULONG_PTR)MCDSrvSetScissor(pMCDExec, &pMCDScissor->rect,
  748. pMCDScissor->bEnabled);
  749. }
  750. break;
  751. case MCD_ALLOCBUFFERS:
  752. CHECK_SIZE_IN(pMCDExec, MCDALLOCBUFFERSCMDI);
  753. CHECK_FOR_RC(pMCDExec);
  754. {
  755. MCDALLOCBUFFERSCMDI *pMCDAllocBuffersCmd = (MCDALLOCBUFFERSCMDI *)pMCDExec->pCmd;
  756. if (!pMCDExec->pWndPriv->bRegionValid)
  757. pMCDExec->pWndPriv->MCDWindow.clientRect =
  758. pMCDAllocBuffersCmd->WndRect;
  759. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvAllocBuffers) {
  760. MCDBG_PRINT("MCDrvAllocBuffers: missing entry point.");
  761. return FALSE;
  762. }
  763. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvAllocBuffers)(&pMCDExec->MCDSurface,
  764. &pMCDExec->pRcPriv->MCDRc);
  765. }
  766. break;
  767. case MCD_GETBUFFERS:
  768. CHECK_SIZE_IN(pMCDExec, MCDGETBUFFERSCMDI);
  769. CHECK_SIZE_OUT(pMCDExec, MCDRECTBUFFERS);
  770. CHECK_FOR_RC(pMCDExec);
  771. return CallGetBuffers(pMCDExec, &pMCDExec->pRcPriv->MCDRc,
  772. (MCDRECTBUFFERS *)pMCDExec->pvOut);
  773. case MCD_LOCK:
  774. CHECK_SIZE_IN(pMCDExec, MCDLOCKCMDI);
  775. CHECK_FOR_RC(pMCDExec);
  776. return MCDSrvLock(pMCDExec->pWndPriv);
  777. break;
  778. case MCD_UNLOCK:
  779. CHECK_SIZE_IN(pMCDExec, MCDLOCKCMDI);
  780. CHECK_FOR_RC(pMCDExec);
  781. MCDSrvUnlock(pMCDExec->pWndPriv);
  782. return TRUE;
  783. break;
  784. case MCD_BINDCONTEXT:
  785. CHECK_SIZE_IN(pMCDExec, MCDBINDCONTEXTCMDI);
  786. CHECK_FOR_RC(pMCDExec);
  787. {
  788. ULONG_PTR retVal;
  789. MCDBINDCONTEXTCMDI *pMCDBindContext = (MCDBINDCONTEXTCMDI *)pMCDExec->pCmd;
  790. MCDWINDOW *pWndRes;
  791. if ((!pMCDExec->pWndPriv)) {
  792. pWndRes = MCDSrvNewMCDWindow(&pMCDExec->MCDSurface,
  793. pMCDBindContext->hWnd,
  794. pMCDExec->pGlobal,
  795. pMCDExec->pRcPriv->hDev);
  796. if (!pWndRes)
  797. {
  798. MCDBG_PRINT("MCDBindContext: Creation of window object failed.");
  799. return 0;
  800. }
  801. pMCDExec->pWndPriv = (MCDWINDOWPRIV *)pWndRes;
  802. }
  803. if (!pMCDExec->MCDSurface.pWnd) {
  804. MCDBG_PRINT("MCDrvBindContext: NULL surface.");
  805. return 0;
  806. }
  807. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvBindContext) {
  808. MCDBG_PRINT("MCDrvBindContext: missing entry point.");
  809. return 0;
  810. }
  811. retVal = (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvBindContext)(&pMCDExec->MCDSurface,
  812. &pMCDExec->pRcPriv->MCDRc);
  813. if (retVal)
  814. {
  815. pRcPriv->hWnd = pMCDBindContext->hWnd;
  816. retVal = (ULONG_PTR)pMCDExec->pWndPriv->handle;
  817. }
  818. return retVal;
  819. }
  820. break;
  821. case MCD_SYNC:
  822. CHECK_SIZE_IN(pMCDExec, MCDSYNCCMDI);
  823. CHECK_FOR_RC(pMCDExec);
  824. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvSync) {
  825. MCDBG_PRINT("MCDrvSync: missing entry point.");
  826. return FALSE;
  827. }
  828. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvSync)(&pMCDExec->MCDSurface,
  829. &pMCDExec->pRcPriv->MCDRc);
  830. break;
  831. case MCD_CREATE_TEXTURE:
  832. CHECK_SIZE_IN(pMCDExec, MCDCREATETEXCMDI);
  833. CHECK_FOR_RC(pMCDExec);
  834. {
  835. MCDCREATETEXCMDI *pMCDCreateTex =
  836. (MCDCREATETEXCMDI *)pMCDExec->pCmd;
  837. return (ULONG_PTR)MCDSrvCreateTexture(pMCDExec,
  838. pMCDCreateTex->pTexData,
  839. pMCDCreateTex->pSurface,
  840. pMCDCreateTex->flags);
  841. }
  842. break;
  843. case MCD_DELETE_TEXTURE:
  844. CHECK_SIZE_IN(pMCDExec, MCDDELETETEXCMDI);
  845. CHECK_FOR_RC(pMCDExec);
  846. {
  847. MCDDELETETEXCMDI *pMCDDeleteTex =
  848. (MCDDELETETEXCMDI *)pMCDExec->pCmd;
  849. return (ULONG_PTR)DestroyMCDObj(pMCDDeleteTex->hTex,
  850. MCDHANDLE_TEXTURE);
  851. }
  852. break;
  853. case MCD_UPDATE_SUB_TEXTURE:
  854. CHECK_SIZE_IN(pMCDExec, MCDUPDATESUBTEXCMDI);
  855. CHECK_FOR_RC(pMCDExec);
  856. {
  857. MCDUPDATESUBTEXCMDI *pMCDUpdateSubTex =
  858. (MCDUPDATESUBTEXCMDI *)pMCDExec->pCmd;
  859. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)MCDEngGetPtrFromHandle((MCDHANDLE)pMCDUpdateSubTex->hTex,
  860. MCDHANDLE_TEXTURE);
  861. if (!pTexObj ||
  862. !pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateSubTexture)
  863. return FALSE;
  864. pTexObj->MCDTexture.pMCDTextureData = pMCDUpdateSubTex->pTexData;
  865. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateSubTexture)(&pMCDExec->MCDSurface,
  866. &pMCDExec->pRcPriv->MCDRc,
  867. &pTexObj->MCDTexture,
  868. pMCDUpdateSubTex->lod,
  869. &pMCDUpdateSubTex->rect);
  870. }
  871. break;
  872. case MCD_UPDATE_TEXTURE_PALETTE:
  873. CHECK_SIZE_IN(pMCDExec, MCDUPDATETEXPALETTECMDI);
  874. CHECK_FOR_RC(pMCDExec);
  875. {
  876. MCDUPDATETEXPALETTECMDI *pMCDUpdateTexPalette =
  877. (MCDUPDATETEXPALETTECMDI *)pMCDExec->pCmd;
  878. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)MCDEngGetPtrFromHandle((MCDHANDLE)pMCDUpdateTexPalette->hTex,
  879. MCDHANDLE_TEXTURE);
  880. if (!pTexObj ||
  881. !pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateTexturePalette)
  882. return FALSE;
  883. pTexObj->MCDTexture.pMCDTextureData = pMCDUpdateTexPalette->pTexData;
  884. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateTexturePalette)(&pMCDExec->MCDSurface,
  885. &pMCDExec->pRcPriv->MCDRc,
  886. &pTexObj->MCDTexture,
  887. pMCDUpdateTexPalette->start,
  888. pMCDUpdateTexPalette->numEntries);
  889. }
  890. break;
  891. case MCD_UPDATE_TEXTURE_PRIORITY:
  892. CHECK_SIZE_IN(pMCDExec, MCDUPDATETEXPRIORITYCMDI);
  893. CHECK_FOR_RC(pMCDExec);
  894. {
  895. MCDUPDATETEXPRIORITYCMDI *pMCDUpdateTexPriority =
  896. (MCDUPDATETEXPRIORITYCMDI *)pMCDExec->pCmd;
  897. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)MCDEngGetPtrFromHandle((MCDHANDLE)pMCDUpdateTexPriority->hTex,
  898. MCDHANDLE_TEXTURE);
  899. if (!pTexObj ||
  900. !pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateTexturePriority)
  901. return FALSE;
  902. pTexObj->MCDTexture.pMCDTextureData = pMCDUpdateTexPriority->pTexData;
  903. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateTexturePriority)(&pMCDExec->MCDSurface,
  904. &pMCDExec->pRcPriv->MCDRc,
  905. &pTexObj->MCDTexture);
  906. }
  907. break;
  908. case MCD_UPDATE_TEXTURE_STATE:
  909. CHECK_SIZE_IN(pMCDExec, MCDUPDATETEXSTATECMDI);
  910. CHECK_FOR_RC(pMCDExec);
  911. {
  912. MCDUPDATETEXSTATECMDI *pMCDUpdateTexState =
  913. (MCDUPDATETEXSTATECMDI *)pMCDExec->pCmd;
  914. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)MCDEngGetPtrFromHandle((MCDHANDLE)pMCDUpdateTexState->hTex,
  915. MCDHANDLE_TEXTURE);
  916. if (!pTexObj ||
  917. !pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateTextureState)
  918. return FALSE;
  919. pTexObj->MCDTexture.pMCDTextureData = pMCDUpdateTexState->pTexData;
  920. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvUpdateTextureState)(&pMCDExec->MCDSurface,
  921. &pMCDExec->pRcPriv->MCDRc,
  922. &pTexObj->MCDTexture);
  923. }
  924. break;
  925. case MCD_TEXTURE_STATUS:
  926. CHECK_SIZE_IN(pMCDExec, MCDTEXSTATUSCMDI);
  927. CHECK_FOR_RC(pMCDExec);
  928. {
  929. MCDTEXSTATUSCMDI *pMCDTexStatus =
  930. (MCDTEXSTATUSCMDI *)pMCDExec->pCmd;
  931. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)MCDEngGetPtrFromHandle((MCDHANDLE)pMCDTexStatus->hTex,
  932. MCDHANDLE_TEXTURE);
  933. if (!pTexObj ||
  934. !pMCDExec->pGlobal->mcdDriver.pMCDrvTextureStatus)
  935. return FALSE;
  936. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvTextureStatus)(&pMCDExec->MCDSurface,
  937. &pMCDExec->pRcPriv->MCDRc,
  938. &pTexObj->MCDTexture);
  939. }
  940. break;
  941. case MCD_GET_TEXTURE_KEY:
  942. CHECK_SIZE_IN(pMCDExec, MCDTEXKEYCMDI);
  943. CHECK_FOR_RC(pMCDExec);
  944. {
  945. MCDTEXKEYCMDI *pMCDTexKey =
  946. (MCDTEXKEYCMDI *)pMCDExec->pCmd;
  947. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)MCDEngGetPtrFromHandle((MCDHANDLE)pMCDTexKey->hTex,
  948. MCDHANDLE_TEXTURE);
  949. if (!pTexObj)
  950. return FALSE;
  951. return pTexObj->MCDTexture.textureKey;
  952. }
  953. break;
  954. case MCD_DESCRIBELAYERPLANE:
  955. CHECK_SIZE_IN(pMCDExec, MCDLAYERPLANECMDI);
  956. if (pMCDExec->pvOut) {
  957. CHECK_SIZE_OUT(pMCDExec, MCDLAYERPLANE);
  958. }
  959. {
  960. MCDLAYERPLANECMDI *pMCDLayerPlane =
  961. (MCDLAYERPLANECMDI *)pMCDExec->pCmd;
  962. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvDescribeLayerPlane)
  963. return 0;
  964. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvDescribeLayerPlane)
  965. (&pMCDExec->MCDSurface,
  966. pMCDLayerPlane->iPixelFormat,
  967. pMCDLayerPlane->iLayerPlane,
  968. pMCDExec->cjOut,
  969. pMCDExec->pvOut, 0);
  970. }
  971. break;
  972. case MCD_SETLAYERPALETTE:
  973. CHECK_SIZE_IN(pMCDExec, MCDSETLAYERPALCMDI);
  974. {
  975. MCDSETLAYERPALCMDI *pMCDSetLayerPal =
  976. (MCDSETLAYERPALCMDI *)pMCDExec->pCmd;
  977. // Check to see if palette array is big enough.
  978. CHECK_MEM_RANGE_RETVAL(&pMCDSetLayerPal->acr[pMCDSetLayerPal->cEntries-1],
  979. pMCDExec->pCmd, pMCDExec->pCmdEnd, FALSE);
  980. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvSetLayerPalette) {
  981. MCDBG_PRINT("MCDrvSetLayerPalette: missing entry point.");
  982. return FALSE;
  983. }
  984. return (ULONG_PTR)(*pMCDExec->pGlobal->mcdDriver.pMCDrvSetLayerPalette)
  985. (&pMCDExec->MCDSurface,
  986. pMCDSetLayerPal->iLayerPlane,
  987. pMCDSetLayerPal->bRealize,
  988. pMCDSetLayerPal->cEntries,
  989. &pMCDSetLayerPal->acr[0]);
  990. }
  991. break;
  992. case MCD_DRAW_PIXELS:
  993. CHECK_SIZE_IN(pMCDExec, MCDDRAWPIXELSCMDI);
  994. CHECK_FOR_RC(pMCDExec);
  995. {
  996. MCDDRAWPIXELSCMDI *pMCDPix =
  997. (MCDDRAWPIXELSCMDI *)pMCDExec->pCmd;
  998. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvDrawPixels) {
  999. MCDBG_PRINT("MCDrvDrawPixels: missing entry point.");
  1000. return FALSE;
  1001. }
  1002. return (ULONG_PTR)(pMCDExec->pGlobal->mcdDriver.pMCDrvDrawPixels)(
  1003. &pMCDExec->MCDSurface,
  1004. &pMCDExec->pRcPriv->MCDRc,
  1005. pMCDPix->width,
  1006. pMCDPix->height,
  1007. pMCDPix->format,
  1008. pMCDPix->type,
  1009. pMCDPix->pPixels,
  1010. pMCDPix->packed);
  1011. }
  1012. break;
  1013. case MCD_READ_PIXELS:
  1014. CHECK_SIZE_IN(pMCDExec, MCDREADPIXELSCMDI);
  1015. CHECK_FOR_RC(pMCDExec);
  1016. {
  1017. MCDREADPIXELSCMDI *pMCDPix =
  1018. (MCDREADPIXELSCMDI *)pMCDExec->pCmd;
  1019. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvReadPixels) {
  1020. MCDBG_PRINT("MCDrvReadPixels: missing entry point.");
  1021. return FALSE;
  1022. }
  1023. return (ULONG_PTR)(pMCDExec->pGlobal->mcdDriver.pMCDrvReadPixels)(
  1024. &pMCDExec->MCDSurface,
  1025. &pMCDExec->pRcPriv->MCDRc,
  1026. pMCDPix->x,
  1027. pMCDPix->y,
  1028. pMCDPix->width,
  1029. pMCDPix->height,
  1030. pMCDPix->format,
  1031. pMCDPix->type,
  1032. pMCDPix->pPixels);
  1033. }
  1034. break;
  1035. case MCD_COPY_PIXELS:
  1036. CHECK_SIZE_IN(pMCDExec, MCDCOPYPIXELSCMDI);
  1037. CHECK_FOR_RC(pMCDExec);
  1038. {
  1039. MCDCOPYPIXELSCMDI *pMCDPix =
  1040. (MCDCOPYPIXELSCMDI *)pMCDExec->pCmd;
  1041. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvCopyPixels) {
  1042. MCDBG_PRINT("MCDrvCopyPixels: missing entry point.");
  1043. return FALSE;
  1044. }
  1045. return (ULONG_PTR)(pMCDExec->pGlobal->mcdDriver.pMCDrvCopyPixels)(
  1046. &pMCDExec->MCDSurface,
  1047. &pMCDExec->pRcPriv->MCDRc,
  1048. pMCDPix->x,
  1049. pMCDPix->y,
  1050. pMCDPix->width,
  1051. pMCDPix->height,
  1052. pMCDPix->type);
  1053. }
  1054. break;
  1055. case MCD_PIXEL_MAP:
  1056. CHECK_SIZE_IN(pMCDExec, MCDPIXELMAPCMDI);
  1057. CHECK_FOR_RC(pMCDExec);
  1058. {
  1059. MCDPIXELMAPCMDI *pMCDPix =
  1060. (MCDPIXELMAPCMDI *)pMCDExec->pCmd;
  1061. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvPixelMap) {
  1062. MCDBG_PRINT("MCDrvPixelMap: missing entry point.");
  1063. return FALSE;
  1064. }
  1065. return (ULONG_PTR)(pMCDExec->pGlobal->mcdDriver.pMCDrvPixelMap)(
  1066. &pMCDExec->MCDSurface,
  1067. &pMCDExec->pRcPriv->MCDRc,
  1068. pMCDPix->mapType,
  1069. pMCDPix->mapSize,
  1070. pMCDPix->pMap);
  1071. }
  1072. break;
  1073. case MCD_DESTROY_WINDOW:
  1074. CHECK_SIZE_IN(pMCDExec, MCDDESTROYWINDOWCMDI);
  1075. {
  1076. if (pMCDExec->pWndPriv == NULL)
  1077. {
  1078. MCDBG_PRINT("MCDrvDestroyWindow: NULL window\n");
  1079. return FALSE;
  1080. }
  1081. MCDEngDeleteObject(pMCDExec->pWndPriv->handle);
  1082. return TRUE;
  1083. }
  1084. break;
  1085. case MCD_GET_TEXTURE_FORMATS:
  1086. CHECK_SIZE_IN(pMCDExec, MCDGETTEXTUREFORMATSCMDI);
  1087. {
  1088. MCDGETTEXTUREFORMATSCMDI *pmgtf =
  1089. (MCDGETTEXTUREFORMATSCMDI *)pMCDExec->pCmd;
  1090. if (pMCDExec->pvOut)
  1091. {
  1092. CHECK_SIZE_OUT(pMCDExec,
  1093. pmgtf->nFmts*sizeof(DDSURFACEDESC));
  1094. }
  1095. #if MCD_VER_MAJOR >= 2 || (MCD_VER_MAJOR == 1 && MCD_VER_MINOR >= 0x10)
  1096. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvGetTextureFormats)
  1097. {
  1098. MCDBG_PRINT("MCDrvGetTextureFormats: "
  1099. "missing entry point.");
  1100. return 0;
  1101. }
  1102. return (pMCDExec->pGlobal->mcdDriver.pMCDrvGetTextureFormats)(
  1103. &pMCDExec->MCDSurface,
  1104. pmgtf->nFmts,
  1105. (DDSURFACEDESC *)pMCDExec->pvOut);
  1106. #else
  1107. return 0;
  1108. #endif // 1.1
  1109. }
  1110. break;
  1111. case MCD_SWAP_MULTIPLE:
  1112. CHECK_SIZE_IN(pMCDExec, MCDSWAPMULTIPLECMDI);
  1113. {
  1114. MCDSWAPMULTIPLECMDI *pSwapCmd =
  1115. (MCDSWAPMULTIPLECMDI *)pMCDExec->pCmd;
  1116. MCDWINDOWPRIV *apWndPriv[MCDESC_MAX_EXTRA_WNDOBJ];
  1117. UINT i;
  1118. MCDWINDOWOBJ *pmwo;
  1119. MCDRVSWAPMULTIPLEFUNC pSwapMultFunc;
  1120. ULONG_PTR dwRet;
  1121. pSwapMultFunc = NULL;
  1122. for (i = 0; i < pSwapCmd->cBuffers; i++)
  1123. {
  1124. if (pMCDExec->ppwoMulti[i] != NULL)
  1125. {
  1126. pmwo = (MCDWINDOWOBJ *)
  1127. MCDEngGetPtrFromHandle((MCDHANDLE)
  1128. pSwapCmd->adwMcdWindow[i],
  1129. MCDHANDLE_WINDOW);
  1130. }
  1131. else
  1132. {
  1133. pmwo = NULL;
  1134. }
  1135. if (pmwo == NULL)
  1136. {
  1137. apWndPriv[i] = NULL;
  1138. }
  1139. else
  1140. {
  1141. apWndPriv[i] = &pmwo->MCDWindowPriv;
  1142. GetScissorClip(apWndPriv[i], NULL);
  1143. #if MCD_VER_MAJOR >= 2 || (MCD_VER_MAJOR == 1 && MCD_VER_MINOR >= 0x10)
  1144. if (pSwapMultFunc == NULL)
  1145. {
  1146. pSwapMultFunc = apWndPriv[i]->pGlobal->mcdDriver.
  1147. pMCDrvSwapMultiple;
  1148. }
  1149. else if (pSwapMultFunc !=
  1150. apWndPriv[i]->pGlobal->mcdDriver.
  1151. pMCDrvSwapMultiple)
  1152. {
  1153. MCDBG_PRINT("MCDrvSwapMultiple: "
  1154. "Mismatched SwapMultiple");
  1155. return FALSE;
  1156. }
  1157. #endif // 1.1
  1158. }
  1159. }
  1160. if (pSwapMultFunc != NULL)
  1161. {
  1162. dwRet = pSwapMultFunc(pMCDExec->MCDSurface.pwo->psoOwner,
  1163. pSwapCmd->cBuffers,
  1164. (MCDWINDOW **)apWndPriv,
  1165. (UINT *)pSwapCmd->auiFlags);
  1166. }
  1167. else
  1168. {
  1169. MCDSURFACE *pms;
  1170. dwRet = 0;
  1171. pms = &pMCDExec->MCDSurface;
  1172. for (i = 0; i < pSwapCmd->cBuffers; i++)
  1173. {
  1174. if (apWndPriv[i] == NULL)
  1175. {
  1176. continue;
  1177. }
  1178. if (apWndPriv[i]->pGlobal->mcdDriver.
  1179. pMCDrvSwap == NULL)
  1180. {
  1181. MCDBG_PRINT("MCDrvSwapMultiple: Missing Swap");
  1182. }
  1183. else
  1184. {
  1185. pms->pWnd = (MCDWINDOW *)apWndPriv[i];
  1186. pms->pso = pMCDExec->ppwoMulti[i]->psoOwner;
  1187. pms->pwo = pMCDExec->ppwoMulti[i];
  1188. pms->surfaceFlags = 0;
  1189. if (apWndPriv[i]->pGlobal->mcdDriver.
  1190. pMCDrvSwap(pms, pSwapCmd->auiFlags[i]))
  1191. {
  1192. dwRet |= 1 << i;
  1193. }
  1194. }
  1195. }
  1196. }
  1197. return dwRet;
  1198. }
  1199. break;
  1200. case MCD_PROCESS:
  1201. CHECK_SIZE_IN(pMCDExec, MCDPROCESSCMDI);
  1202. CHECK_FOR_RC(pMCDExec);
  1203. CHECK_FOR_MEM(pMCDExec);
  1204. {
  1205. MCDPROCESSCMDI *pmp = (MCDPROCESSCMDI *)pMCDExec->pCmd;
  1206. // Validate command buffer
  1207. GET_MEMOBJ_RETVAL(pMemObj, pmp->hMCDPrimMem,
  1208. (ULONG_PTR)pmp->pMCDFirstCmd);
  1209. pMinMem = pMemObj->MCDMem.pMemBase;
  1210. // Note: we ignore the memory size in the header since it
  1211. // doesn't really help us...
  1212. pMaxMem = pMinMem + pMemObj->MCDMem.memSize;
  1213. CHECK_MEM_RANGE_RETVAL(pmp->pMCDFirstCmd, pMinMem,
  1214. pMaxMem, (ULONG_PTR)pmp->pMCDFirstCmd);
  1215. // Validate user-mode pointers passed down.
  1216. __try
  1217. {
  1218. EngProbeForRead(pmp->pMCDTransform, sizeof(MCDTRANSFORM),
  1219. sizeof(DWORD));
  1220. // No meaningful check of the material changes can be
  1221. // done. The driver is responsible for probing
  1222. // addresses used.
  1223. }
  1224. __except(EXCEPTION_EXECUTE_HANDLER)
  1225. {
  1226. return (ULONG_PTR)pmp->pMCDFirstCmd;
  1227. }
  1228. GetScissorClip(pMCDExec->pWndPriv, pMCDExec->pRcPriv);
  1229. #if MCD_VER_MAJOR >= 2
  1230. if (!pMCDExec->pGlobal->mcdDriver.pMCDrvProcess)
  1231. {
  1232. if (pMCDExec->pGlobal->mcdDriver.pMCDrvSync)
  1233. {
  1234. (*pMCDExec->pGlobal->mcdDriver.pMCDrvSync)
  1235. (&pMCDExec->MCDSurface,
  1236. &pMCDExec->pRcPriv->MCDRc);
  1237. }
  1238. return (ULONG_PTR)pmp->pMCDFirstCmd;
  1239. }
  1240. return (pMCDExec->pGlobal->mcdDriver.pMCDrvProcess)(
  1241. &pMCDExec->MCDSurface, &pMCDExec->pRcPriv->MCDRc,
  1242. &pMemObj->MCDMem, (UCHAR *)pmp->pMCDFirstCmd, pMaxMem,
  1243. pmp->cmdFlagsAll, pmp->primFlags, pmp->pMCDTransform,
  1244. pmp->pMCDMatChanges);
  1245. #else
  1246. if (pMCDExec->pGlobal->mcdDriver.pMCDrvSync)
  1247. {
  1248. (*pMCDExec->pGlobal->mcdDriver.pMCDrvSync)
  1249. (&pMCDExec->MCDSurface,
  1250. &pMCDExec->pRcPriv->MCDRc);
  1251. }
  1252. return (ULONG_PTR)pmp->pMCDFirstCmd;
  1253. #endif // 2.0
  1254. }
  1255. break;
  1256. default:
  1257. MCDBG_PRINT("MCDSrvProcess: "
  1258. "Null rendering context invalid for command %d.",
  1259. pMCDExec->pCmd->command);
  1260. return FALSE;
  1261. }
  1262. return FALSE; // should never get here...
  1263. }
  1264. //****************************************************************************
  1265. // FreeRCObj()
  1266. //
  1267. // Engine callback for freeing the memory used for rendering-context
  1268. // handles.
  1269. //****************************************************************************
  1270. BOOL CALLBACK FreeRCObj(DRIVEROBJ *pDrvObj)
  1271. {
  1272. MCDRCOBJ *pRcObj = (MCDRCOBJ *)pDrvObj->pvObj;
  1273. MCDRCPRIV *pRcPriv = pRcObj->pRcPriv;
  1274. if ((pRcPriv->bDrvValid) &&
  1275. (pRcPriv->pGlobal->mcdDriver.pMCDrvDeleteContext))
  1276. {
  1277. (*pRcPriv->pGlobal->mcdDriver.pMCDrvDeleteContext)
  1278. (&pRcPriv->MCDRc, pDrvObj->dhpdev);
  1279. }
  1280. MCDSrvLocalFree((UCHAR *)pRcPriv);
  1281. MCDSrvLocalFree((UCHAR *)pRcObj);
  1282. return TRUE;
  1283. }
  1284. //****************************************************************************
  1285. // MCDSrvCreateContext()
  1286. //
  1287. // Create a rendering context (RGBA or color-indexed) for the current
  1288. // hardware mode. This call will also initialize window-tracking for
  1289. // the context (which is associated with the specified window).
  1290. //****************************************************************************
  1291. PRIVATE
  1292. MCDHANDLE MCDSrvCreateContext(MCDSURFACE *pMCDSurface,
  1293. MCDRCINFOPRIV *pMcdRcInfo,
  1294. MCDGLOBALINFO *pGlobal,
  1295. LONG iPixelFormat,
  1296. LONG iLayer,
  1297. HWND hWnd,
  1298. ULONG surfaceFlags,
  1299. ULONG contextFlags)
  1300. {
  1301. MCDWINDOW *pWnd;
  1302. MCDWINDOWPRIV *pWndPriv;
  1303. MCDRCPRIV *pRcPriv;
  1304. MCDHANDLE retVal;
  1305. HWND hwnd;
  1306. MCDRCOBJ *newRcObject;
  1307. MCDRVTRACKWINDOWFUNC pTrackFunc = NULL;
  1308. if (pGlobal->mcdDriver.pMCDrvCreateContext == NULL)
  1309. {
  1310. MCDBG_PRINT("MCDSrvCreateContext: No MCDrvCreateContext.");
  1311. return NULL;
  1312. }
  1313. pRcPriv = (MCDRCPRIV *)MCDSrvLocalAlloc(0,sizeof(MCDRCPRIV));
  1314. if (!pRcPriv) {
  1315. MCDBG_PRINT("MCDSrvCreateContext: Could not allocate new context.");
  1316. return (MCDHANDLE)NULL;
  1317. }
  1318. pRcPriv->pGlobal = pGlobal;
  1319. // Cache the engine handle provided by the driver:
  1320. pRcPriv->hDev = (*pGlobal->mcdDriver.pMCDrvGetHdev)(pMCDSurface);
  1321. if (surfaceFlags & MCDSURFACE_HWND)
  1322. {
  1323. pMCDSurface->surfaceFlags |= MCDSURFACE_HWND;
  1324. }
  1325. if (surfaceFlags & MCDSURFACE_DIRECT)
  1326. {
  1327. pMCDSurface->surfaceFlags |= MCDSURFACE_DIRECT;
  1328. }
  1329. // cache the surface flags away in the private RC:
  1330. pRcPriv->surfaceFlags = pMCDSurface->surfaceFlags;
  1331. // Initialize tracking of this window with a MCDWINDOW
  1332. // (via and WNDOBJ on NT) if we are not already tracking the
  1333. // window:
  1334. pWnd = MCDSrvNewMCDWindow(pMCDSurface, hWnd, pGlobal,
  1335. pRcPriv->hDev);
  1336. if (pWnd == NULL)
  1337. {
  1338. MCDSrvLocalFree((HLOCAL)pRcPriv);
  1339. return (MCDHANDLE)NULL;
  1340. }
  1341. pWndPriv = (MCDWINDOWPRIV *)pWnd;
  1342. pRcPriv->hWnd = hWnd;
  1343. newRcObject = (MCDRCOBJ *)MCDSrvLocalAlloc(0,sizeof(MCDRCOBJ));
  1344. if (!newRcObject) {
  1345. MCDSrvLocalFree((HLOCAL)pRcPriv);
  1346. return (MCDHANDLE)NULL;
  1347. }
  1348. retVal = MCDEngCreateObject(newRcObject, FreeRCObj, pRcPriv->hDev);
  1349. if (retVal) {
  1350. newRcObject->pid = MCDEngGetProcessID();
  1351. newRcObject->type = MCDHANDLE_RC;
  1352. newRcObject->size = sizeof(MCDRCPRIV);
  1353. newRcObject->pRcPriv = pRcPriv;
  1354. newRcObject->handle = (MCDHANDLE)retVal;
  1355. // Add the object to the list in the MCDWINDOW
  1356. newRcObject->next = pWndPriv->objectList;
  1357. pWndPriv->objectList = newRcObject;
  1358. } else {
  1359. MCDBG_PRINT("MCDSrvCreateContext: Could not create new handle.");
  1360. MCDSrvLocalFree((HLOCAL)pRcPriv);
  1361. MCDSrvLocalFree((HLOCAL)newRcObject);
  1362. return (MCDHANDLE)NULL;
  1363. }
  1364. pRcPriv->bValid = TRUE;
  1365. pRcPriv->scissorsEnabled = FALSE;
  1366. pRcPriv->scissorsRect.left = 0;
  1367. pRcPriv->scissorsRect.top = 0;
  1368. pRcPriv->scissorsRect.right = 0;
  1369. pRcPriv->scissorsRect.bottom = 0;
  1370. pRcPriv->MCDRc.createFlags = contextFlags;
  1371. pRcPriv->MCDRc.iPixelFormat = iPixelFormat;
  1372. pRcPriv->MCDRc.iLayerPlane = iLayer;
  1373. if (!(*pGlobal->mcdDriver.pMCDrvCreateContext)(pMCDSurface,
  1374. &pRcPriv->MCDRc,
  1375. &pMcdRcInfo->mri)) {
  1376. DestroyMCDObj((HANDLE)retVal, MCDHANDLE_RC);
  1377. return (MCDHANDLE)NULL;
  1378. }
  1379. // Return window private handle
  1380. pMcdRcInfo->dwMcdWindow = (ULONG_PTR)pWndPriv->handle;
  1381. // Now valid to call driver for deletion...
  1382. pRcPriv->bDrvValid = TRUE;
  1383. return (MCDHANDLE)retVal;
  1384. }
  1385. //****************************************************************************
  1386. // FreeTexObj()
  1387. //
  1388. // Engine callback for freeing the memory used for a texture.
  1389. //****************************************************************************
  1390. BOOL CALLBACK FreeTexObj(DRIVEROBJ *pDrvObj)
  1391. {
  1392. MCDTEXOBJ *pTexObj = (MCDTEXOBJ *)pDrvObj->pvObj;
  1393. // We should never get called if the driver is missing this entry point,
  1394. // but the extra check can't hurt!
  1395. //
  1396. // pGlobal can be NULL for partially constructed objects. It
  1397. // is only NULL prior to calling the driver for creation, so if
  1398. // it's NULL there's no reason to call the driver for cleanup.
  1399. if (pTexObj->pGlobal != NULL &&
  1400. pTexObj->pGlobal->mcdDriver.pMCDrvDeleteTexture != NULL)
  1401. {
  1402. (*pTexObj->pGlobal->mcdDriver.pMCDrvDeleteTexture)
  1403. (&pTexObj->MCDTexture, pDrvObj->dhpdev);
  1404. }
  1405. MCDSrvLocalFree((HLOCAL)pTexObj);
  1406. return TRUE;
  1407. }
  1408. //****************************************************************************
  1409. // MCDSrvCreateTexture()
  1410. //
  1411. // Creates an MCD texture.
  1412. //****************************************************************************
  1413. PRIVATE
  1414. MCDHANDLE MCDSrvCreateTexture(MCDEXEC *pMCDExec, MCDTEXTUREDATA *pTexData,
  1415. VOID *pSurface, ULONG flags)
  1416. {
  1417. MCDRCPRIV *pRcPriv;
  1418. MCDHANDLE hTex;
  1419. MCDTEXOBJ *pTexObj;
  1420. pRcPriv = pMCDExec->pRcPriv;
  1421. if ((!pMCDExec->pGlobal->mcdDriver.pMCDrvDeleteTexture) ||
  1422. (!pMCDExec->pGlobal->mcdDriver.pMCDrvCreateTexture)) {
  1423. return (MCDHANDLE)NULL;
  1424. }
  1425. pTexObj = (MCDTEXOBJ *) MCDSrvLocalAlloc(0,sizeof(MCDTEXOBJ));
  1426. if (!pTexObj) {
  1427. MCDBG_PRINT("MCDCreateTexture: Could not allocate texture object.");
  1428. return (MCDHANDLE)NULL;
  1429. }
  1430. hTex = MCDEngCreateObject(pTexObj, FreeTexObj, pRcPriv->hDev);
  1431. if (!hTex) {
  1432. MCDBG_PRINT("MCDSrvCreateTexture: Could not create texture object.");
  1433. MCDSrvLocalFree((HLOCAL)pTexObj);
  1434. return (MCDHANDLE)NULL;
  1435. }
  1436. // Initialize driver public information for driver call, but not
  1437. // the private information. The private information is not filled out
  1438. // until after the driver call succeeds so that FreeTexObj knows
  1439. // whether to call the driver or not when destroying a texture object.
  1440. pTexObj->MCDTexture.pSurface = pSurface;
  1441. pTexObj->MCDTexture.pMCDTextureData = pTexData;
  1442. pTexObj->MCDTexture.createFlags = flags;
  1443. // Call the driver if everything has gone well...
  1444. if (!(*pMCDExec->pGlobal->mcdDriver.pMCDrvCreateTexture)
  1445. (&pMCDExec->MCDSurface,
  1446. &pRcPriv->MCDRc,
  1447. &pTexObj->MCDTexture)) {
  1448. //MCDBG_PRINT("MCDSrvCreateTexture: Driver could not create texture.");
  1449. MCDEngDeleteObject(hTex);
  1450. return (MCDHANDLE)NULL;
  1451. }
  1452. if (!pTexObj->MCDTexture.textureKey) {
  1453. MCDBG_PRINT("MCDSrvCreateTexture: Driver returned null key.");
  1454. MCDEngDeleteObject(hTex);
  1455. return (MCDHANDLE)NULL;
  1456. }
  1457. pTexObj->pid = MCDEngGetProcessID();
  1458. pTexObj->type = MCDHANDLE_TEXTURE;
  1459. pTexObj->size = sizeof(MCDTEXOBJ);
  1460. pTexObj->pGlobal = pMCDExec->pGlobal;
  1461. return (MCDHANDLE)hTex;
  1462. }
  1463. //****************************************************************************
  1464. // FreeMemObj()
  1465. //
  1466. // Engine callback for freeing memory used by shared-memory handles.
  1467. //****************************************************************************
  1468. BOOL CALLBACK FreeMemObj(DRIVEROBJ *pDrvObj)
  1469. {
  1470. MCDMEMOBJ *pMemObj = (MCDMEMOBJ *)pDrvObj->pvObj;
  1471. // Free the memory using our engine ONLY if it is the same memory
  1472. // we allocated in the first place.
  1473. if (pMemObj->pMemBaseInternal)
  1474. MCDEngFreeSharedMem(pMemObj->pMemBaseInternal);
  1475. // pGlobal can be NULL for partially constructed objects. It
  1476. // is only NULL prior to calling the driver for creation, so if
  1477. // it's NULL there's no reason to call the driver for cleanup.
  1478. if (pMemObj->pGlobal != NULL &&
  1479. pMemObj->pGlobal->mcdDriver.pMCDrvDeleteMem != NULL)
  1480. {
  1481. (*pMemObj->pGlobal->mcdDriver.pMCDrvDeleteMem)
  1482. (&pMemObj->MCDMem, pDrvObj->dhpdev);
  1483. }
  1484. MCDSrvLocalFree((HLOCAL)pMemObj);
  1485. return TRUE;
  1486. }
  1487. //****************************************************************************
  1488. // MCDSrvAllocMem()
  1489. //
  1490. // Creates a handle associated with the specified memory.
  1491. //****************************************************************************
  1492. PRIVATE
  1493. UCHAR * MCDSrvAllocMem(MCDEXEC *pMCDExec, ULONG numBytes,
  1494. ULONG flags, MCDHANDLE *phMem)
  1495. {
  1496. MCDRCPRIV *pRcPriv;
  1497. MCDHANDLE hMem;
  1498. MCDMEMOBJ *pMemObj;
  1499. pRcPriv = pMCDExec->pRcPriv;
  1500. *phMem = (MCDHANDLE)FALSE;
  1501. pMemObj = (MCDMEMOBJ *) MCDSrvLocalAlloc(0,sizeof(MCDMEMOBJ));
  1502. if (!pMemObj) {
  1503. MCDBG_PRINT("MCDSrvAllocMem: Could not allocate memory object.");
  1504. return (MCDHANDLE)NULL;
  1505. }
  1506. hMem = MCDEngCreateObject(pMemObj, FreeMemObj, pRcPriv->hDev);
  1507. if (!hMem) {
  1508. MCDBG_PRINT("MCDSrvAllocMem: Could not create memory object.");
  1509. MCDSrvLocalFree((HLOCAL)pMemObj);
  1510. return (UCHAR *)NULL;
  1511. }
  1512. pMemObj->MCDMem.pMemBase = pMemObj->pMemBaseInternal =
  1513. MCDEngAllocSharedMem(numBytes);
  1514. if (!pMemObj->MCDMem.pMemBase) {
  1515. MCDBG_PRINT("MCDSrvAllocMem: Could not allocate memory.");
  1516. MCDEngDeleteObject(hMem);
  1517. return (UCHAR *)NULL;
  1518. }
  1519. // Call the driver if everything has gone well, and the driver
  1520. // entry points exist...
  1521. if ((pMCDExec->pGlobal->mcdDriver.pMCDrvCreateMem) &&
  1522. (pMCDExec->pGlobal->mcdDriver.pMCDrvDeleteMem)) {
  1523. if (!(*pMCDExec->pGlobal->mcdDriver.pMCDrvCreateMem)
  1524. (&pMCDExec->MCDSurface,
  1525. &pMemObj->MCDMem)) {
  1526. MCDBG_PRINT("MCDSrvAllocMem: "
  1527. "Driver not create memory type %x.", flags);
  1528. MCDEngDeleteObject(hMem);
  1529. return (UCHAR *)NULL;
  1530. }
  1531. }
  1532. // Free the memory allocated with our engine if the driver has substituted
  1533. // its own allocation...
  1534. if (pMemObj->MCDMem.pMemBase != pMemObj->pMemBaseInternal) {
  1535. MCDEngFreeSharedMem(pMemObj->pMemBaseInternal);
  1536. pMemObj->pMemBaseInternal = (UCHAR *)NULL;
  1537. }
  1538. // Set up the private portion of memory object:
  1539. pMemObj->pid = MCDEngGetProcessID();
  1540. pMemObj->type = MCDHANDLE_MEM;
  1541. pMemObj->size = sizeof(MCDMEMOBJ);
  1542. pMemObj->pGlobal = pMCDExec->pGlobal;
  1543. pMemObj->MCDMem.memSize = numBytes;
  1544. pMemObj->MCDMem.createFlags = flags;
  1545. *phMem = hMem;
  1546. return pMemObj->MCDMem.pMemBase;
  1547. }
  1548. PRIVATE
  1549. ULONG MCDSrvQueryMemStatus(MCDEXEC *pMCDExec, MCDHANDLE hMCDMem)
  1550. {
  1551. MCDMEMOBJ *pMemObj;
  1552. pMemObj = (MCDMEMOBJ *)MCDEngGetPtrFromHandle(hMCDMem, MCDHANDLE_MEM);
  1553. if (!pMemObj)
  1554. return MCD_MEM_INVALID;
  1555. if (pMemObj->lockCount)
  1556. return MCD_MEM_BUSY;
  1557. else
  1558. return MCD_MEM_READY;
  1559. }
  1560. PRIVATE
  1561. BOOL MCDSrvSetScissor(MCDEXEC *pMCDExec, RECTL *pRect, BOOL bEnabled)
  1562. {
  1563. MCDRCPRIV *pRcPriv;
  1564. MCDRCOBJ *pRcObj;
  1565. HWND hWnd;
  1566. ULONG retVal = FALSE;
  1567. pRcPriv = pMCDExec->pRcPriv;
  1568. pRcPriv->scissorsEnabled = bEnabled;
  1569. pRcPriv->scissorsRect = *pRect;
  1570. return TRUE;
  1571. }
  1572. //****************************************************************************
  1573. // DestroyMCDObj()
  1574. //
  1575. // Deletes the specified object. This can be memory, textures, or rendering
  1576. // contexts.
  1577. //
  1578. //****************************************************************************
  1579. PRIVATE
  1580. BOOL DestroyMCDObj(MCDHANDLE handle, MCDHANDLETYPE handleType)
  1581. {
  1582. CHAR *pObject;
  1583. pObject = (CHAR *)MCDEngGetPtrFromHandle(handle, handleType);
  1584. if (!pObject)
  1585. return FALSE;
  1586. //!!! Check for PID here...
  1587. return (MCDEngDeleteObject(handle) != 0);
  1588. }
  1589. //****************************************************************************
  1590. // DecoupleMCDWindowObj()
  1591. //
  1592. // Breaks any existing links between an MCDWINDOW and its WNDOBJ
  1593. //****************************************************************************
  1594. PRIVATE
  1595. VOID DecoupleMCDWindow(MCDWINDOWPRIV *pWndPriv)
  1596. {
  1597. // Clean up any outstanding lock
  1598. MCDSrvUnlock(pWndPriv);
  1599. // Delete reference in WNDOBJ. WNDOBJ itself will be cleaned
  1600. // up through normal window cleanup.
  1601. if (pWndPriv->pwo != NULL)
  1602. {
  1603. if (pWndPriv->pGlobal->mcdDriver.pMCDrvTrackWindow)
  1604. {
  1605. (*pWndPriv->pGlobal->mcdDriver.pMCDrvTrackWindow)
  1606. (pWndPriv->pwo, (MCDWINDOW *)pWndPriv, WOC_DELETE);
  1607. }
  1608. WNDOBJ_vSetConsumer(pWndPriv->pwo, NULL);
  1609. pWndPriv->pwo = NULL;
  1610. }
  1611. }
  1612. //****************************************************************************
  1613. // DestroyMCDWindowObj()
  1614. //
  1615. // Destroy the specified MCDWINDOW and any associated handles (such rendering
  1616. // contexts).
  1617. //****************************************************************************
  1618. PRIVATE
  1619. VOID DestroyMCDWindowObj(MCDWINDOWOBJ *pmwo)
  1620. {
  1621. MCDWINDOWPRIV *pWndPriv = &pmwo->MCDWindowPriv;
  1622. MCDRCOBJ *nextObject;
  1623. DecoupleMCDWindow(pWndPriv);
  1624. // Delete all of the rendering contexts associated with the window:
  1625. #if _WIN95_
  1626. while (pWndPriv->objectList)
  1627. {
  1628. nextObject = pWndPriv->objectList->next;
  1629. MCDEngDeleteObject(pWndPriv->objectList->handle);
  1630. pWndPriv->objectList = nextObject;
  1631. }
  1632. #endif
  1633. if (pWndPriv->pAllocatedClipBuffer)
  1634. MCDSrvLocalFree(pWndPriv->pAllocatedClipBuffer);
  1635. // Free the memory
  1636. MCDSrvLocalFree((HLOCAL)pmwo);
  1637. }
  1638. //****************************************************************************
  1639. // GetScissorClip()
  1640. //
  1641. // Generate a new clip list based on the current list of clip rectanges
  1642. // for the window, and the specified scissor rectangle.
  1643. //****************************************************************************
  1644. PRIVATE
  1645. VOID GetScissorClip(MCDWINDOWPRIV *pWndPriv, MCDRCPRIV *pRcPriv)
  1646. {
  1647. MCDWINDOW *pWnd;
  1648. MCDENUMRECTS *pClipUnscissored;
  1649. MCDENUMRECTS *pClipScissored;
  1650. RECTL *pRectUnscissored;
  1651. RECTL *pRectScissored;
  1652. RECTL rectScissor;
  1653. ULONG numUnscissoredRects;
  1654. ULONG numScissoredRects;
  1655. pWnd = (MCDWINDOW *)pWndPriv;
  1656. if (!pRcPriv || !pRcPriv->scissorsEnabled)
  1657. {
  1658. // Scissors aren't enabled, so the unscissored and scissored
  1659. // clip lists are identical:
  1660. pWnd->pClip = pWnd->pClipUnscissored = pWndPriv->pClipUnscissored;
  1661. }
  1662. else
  1663. {
  1664. // The scissored list will go in the second half of our clip
  1665. // buffer:
  1666. pClipUnscissored
  1667. = pWndPriv->pClipUnscissored;
  1668. pClipScissored
  1669. = (MCDENUMRECTS*) ((BYTE*) pClipUnscissored + pWndPriv->sizeClipBuffer / 2);
  1670. pWnd->pClip = pWndPriv->pClipScissored = pClipScissored;
  1671. pWnd->pClipUnscissored = pClipUnscissored;
  1672. // Convert scissor to screen coordinates:
  1673. rectScissor.left = pRcPriv->scissorsRect.left + pWndPriv->MCDWindow.clientRect.left;
  1674. rectScissor.right = pRcPriv->scissorsRect.right + pWndPriv->MCDWindow.clientRect.left;
  1675. rectScissor.top = pRcPriv->scissorsRect.top + pWndPriv->MCDWindow.clientRect.top;
  1676. rectScissor.bottom = pRcPriv->scissorsRect.bottom + pWndPriv->MCDWindow.clientRect.top;
  1677. pRectUnscissored = &pClipUnscissored->arcl[0];
  1678. pRectScissored = &pClipScissored->arcl[0];
  1679. numScissoredRects = 0;
  1680. for (numUnscissoredRects = pClipUnscissored->c;
  1681. numUnscissoredRects != 0;
  1682. numUnscissoredRects--, pRectUnscissored++)
  1683. {
  1684. // Since our clipping rectangles are ordered from top to
  1685. // bottom, we can early-out if the tops of the remaining
  1686. // rectangles are not in the scissor rectangle
  1687. if (rectScissor.bottom <= pRectUnscissored->top)
  1688. break;
  1689. // Continue without updating new clip list is there is
  1690. // no overlap.
  1691. if ((rectScissor.left >= pRectUnscissored->right) ||
  1692. (rectScissor.top >= pRectUnscissored->bottom) ||
  1693. (rectScissor.right <= pRectUnscissored->left))
  1694. continue;
  1695. // If we reach this point, we must intersect the given rectangle
  1696. // with the scissor.
  1697. MCDIntersectRect(pRectScissored, pRectUnscissored, &rectScissor);
  1698. numScissoredRects++;
  1699. pRectScissored++;
  1700. }
  1701. pClipScissored->c = numScissoredRects;
  1702. }
  1703. }
  1704. //****************************************************************************
  1705. // GetClipLists()
  1706. //
  1707. // Updates the clip list for the specified window. Space is also allocated
  1708. // the scissored clip list.
  1709. //
  1710. //****************************************************************************
  1711. PRIVATE
  1712. VOID GetClipLists(WNDOBJ *pwo, MCDWINDOWPRIV *pWndPriv)
  1713. {
  1714. MCDENUMRECTS *pDefault;
  1715. ULONG numClipRects;
  1716. char *pClipBuffer;
  1717. ULONG sizeClipBuffer;
  1718. pDefault = (MCDENUMRECTS*) &pWndPriv->defaultClipBuffer[0];
  1719. #if 1
  1720. if (pwo->coClient.iDComplexity == DC_TRIVIAL)
  1721. {
  1722. if ((pwo->rclClient.left >= pwo->rclClient.right) ||
  1723. (pwo->rclClient.top >= pwo->rclClient.bottom))
  1724. {
  1725. pDefault->c = 0;
  1726. }
  1727. else
  1728. {
  1729. pDefault->c = 1;
  1730. pDefault->arcl[0] = pwo->rclClient;
  1731. }
  1732. }
  1733. else if (pwo->coClient.iDComplexity == DC_RECT)
  1734. #else
  1735. if (pwo->coClient.iDComplexity == DC_RECT)
  1736. #endif
  1737. {
  1738. if (pWndPriv->pAllocatedClipBuffer)
  1739. MCDSrvLocalFree(pWndPriv->pAllocatedClipBuffer);
  1740. pWndPriv->pAllocatedClipBuffer = NULL;
  1741. pWndPriv->pClipUnscissored = pDefault;
  1742. pWndPriv->pClipScissored = pDefault;
  1743. pWndPriv->sizeClipBuffer = SIZE_DEFAULT_CLIP_BUFFER;
  1744. if ((pwo->coClient.rclBounds.left >= pwo->coClient.rclBounds.right) ||
  1745. (pwo->coClient.rclBounds.top >= pwo->coClient.rclBounds.bottom))
  1746. {
  1747. // Full-screen VGA mode is represented by a DC_RECT clip object
  1748. // with an empty bounding rectangle. We'll denote it by
  1749. // setting the rectangle count to zero:
  1750. pDefault->c = 0;
  1751. }
  1752. else
  1753. {
  1754. pDefault->c = 1;
  1755. pDefault->arcl[0] = pwo->coClient.rclBounds;
  1756. }
  1757. }
  1758. else
  1759. {
  1760. WNDOBJ_cEnumStart(pwo, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  1761. // Note that this is divide-by-2 for the buffer size because we
  1762. // need room for two copies of the rectangle list:
  1763. if (WNDOBJ_bEnum(pwo, SIZE_DEFAULT_CLIP_BUFFER / 2, (ULONG*) pDefault))
  1764. {
  1765. // Okay, the list of rectangles won't fit in our default buffer.
  1766. // Unfortunately, there is no way to obtain the total count of clip
  1767. // rectangles other than by enumerating them all, as cEnumStart
  1768. // will occasionally give numbers that are far too large (because
  1769. // GDI itself doesn't feel like counting them all).
  1770. //
  1771. // Note that we can use the full default buffer here for this
  1772. // enumeration loop:
  1773. numClipRects = pDefault->c;
  1774. while (WNDOBJ_bEnum(pwo, SIZE_DEFAULT_CLIP_BUFFER, (ULONG*) pDefault))
  1775. numClipRects += pDefault->c;
  1776. // Don't forget that we are given a valid output buffer even
  1777. // when 'bEnum' returns FALSE:
  1778. numClipRects += pDefault->c;
  1779. pClipBuffer = pWndPriv->pAllocatedClipBuffer;
  1780. sizeClipBuffer = 2 * (numClipRects * sizeof(RECTL) + sizeof(ULONG));
  1781. if ((pClipBuffer == NULL) || (sizeClipBuffer > pWndPriv->sizeClipBuffer))
  1782. {
  1783. // Our allocated buffer is too small; we have to free it and
  1784. // allocate a new one. Take the opportunity to add some
  1785. // growing room to our allocation:
  1786. sizeClipBuffer += 8 * sizeof(RECTL); // Arbitrary growing room
  1787. if (pClipBuffer)
  1788. MCDSrvLocalFree(pClipBuffer);
  1789. pClipBuffer = (char *) MCDSrvLocalAlloc(LMEM_FIXED, sizeClipBuffer);
  1790. if (pClipBuffer == NULL)
  1791. {
  1792. // Oh no: we couldn't allocate enough room for the clip list.
  1793. // So pretend we have no visible area at all:
  1794. pWndPriv->pAllocatedClipBuffer = NULL;
  1795. pWndPriv->pClipUnscissored = pDefault;
  1796. pWndPriv->pClipScissored = pDefault;
  1797. pWndPriv->sizeClipBuffer = SIZE_DEFAULT_CLIP_BUFFER;
  1798. pDefault->c = 0;
  1799. return;
  1800. }
  1801. pWndPriv->pAllocatedClipBuffer = pClipBuffer;
  1802. pWndPriv->pClipUnscissored = (MCDENUMRECTS*) pClipBuffer;
  1803. pWndPriv->pClipScissored = (MCDENUMRECTS*) pClipBuffer;
  1804. pWndPriv->sizeClipBuffer = sizeClipBuffer;
  1805. }
  1806. // Now actually get all the clip rectangles:
  1807. WNDOBJ_cEnumStart(pwo, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  1808. WNDOBJ_bEnum(pwo, sizeClipBuffer, (ULONG*) pClipBuffer);
  1809. }
  1810. else
  1811. {
  1812. // How nice, there are no more clip rectangles, which meant that
  1813. // the entire list fits in our default clip buffer, with room
  1814. // for the scissored version of the list:
  1815. if (pWndPriv->pAllocatedClipBuffer)
  1816. MCDSrvLocalFree(pWndPriv->pAllocatedClipBuffer);
  1817. pWndPriv->pAllocatedClipBuffer = NULL;
  1818. pWndPriv->pClipUnscissored = pDefault;
  1819. pWndPriv->pClipScissored = pDefault;
  1820. pWndPriv->sizeClipBuffer = SIZE_DEFAULT_CLIP_BUFFER;
  1821. }
  1822. }
  1823. }
  1824. //****************************************************************************
  1825. // WndObjChangeProc()
  1826. //
  1827. // This is the callback function for window-change notification. We update
  1828. // our clip list, and also allow the hardware to respond to the client
  1829. // and surface deltas, as well as the client message itself.
  1830. //****************************************************************************
  1831. VOID CALLBACK WndObjChangeProc(WNDOBJ *pwo, FLONG fl)
  1832. {
  1833. MCDGLOBALINFO *pGlobal;
  1834. if (pwo)
  1835. {
  1836. MCDWINDOWPRIV *pWndPriv = (MCDWINDOWPRIV *)pwo->pvConsumer;
  1837. //MCDBG_PRINT("WndObjChangeProc: %s, pWndPriv = 0x%08lx\n",
  1838. // fl == WOC_RGN_CLIENT ? "WOC_RGN_CLIENT " :
  1839. // fl == WOC_RGN_CLIENT_DELTA ? "WOC_RGN_CLIENT_DELTA " :
  1840. // fl == WOC_RGN_SURFACE ? "WOC_RGN_SURFACE " :
  1841. // fl == WOC_RGN_SURFACE_DELTA ? "WOC_RGN_SURFACE_DELTA" :
  1842. // fl == WOC_DELETE ? "WOC_DELETE " :
  1843. // "unknown",
  1844. // pWndPriv);
  1845. //!!!HACK -- surface region tracking doesn't have an MCDWINDOWPRIV (yet...)
  1846. // Client region tracking and deletion requires a valid MCDWINDOWPRIV.
  1847. if (((fl == WOC_RGN_CLIENT) || (fl == WOC_RGN_CLIENT_DELTA) ||
  1848. (fl == WOC_DELETE)))
  1849. {
  1850. if (!pWndPriv)
  1851. {
  1852. return;
  1853. }
  1854. // Invalidate cache because buffers may have moved
  1855. pWndPriv->bBuffersValid = FALSE;
  1856. }
  1857. switch (fl)
  1858. {
  1859. case WOC_RGN_CLIENT: // Capture the clip list
  1860. GetClipLists(pwo, pWndPriv);
  1861. pWndPriv->MCDWindow.clientRect = pwo->rclClient;
  1862. pWndPriv->MCDWindow.clipBoundsRect = pwo->coClient.rclBounds;
  1863. pWndPriv->bRegionValid = TRUE;
  1864. if (pWndPriv->pGlobal->mcdDriver.pMCDrvTrackWindow != NULL)
  1865. {
  1866. (*pWndPriv->pGlobal->mcdDriver.pMCDrvTrackWindow)
  1867. (pwo, (MCDWINDOW *)pWndPriv, fl);
  1868. }
  1869. break;
  1870. case WOC_RGN_CLIENT_DELTA:
  1871. if (pWndPriv->pGlobal->mcdDriver.pMCDrvTrackWindow != NULL)
  1872. {
  1873. (*pWndPriv->pGlobal->mcdDriver.pMCDrvTrackWindow)
  1874. (pwo, (MCDWINDOW *)pWndPriv, fl);
  1875. }
  1876. break;
  1877. case WOC_RGN_SURFACE:
  1878. case WOC_RGN_SURFACE_DELTA:
  1879. //!!!HACK -- use NULL for pWndPriv; we didn't set it, so we can't
  1880. //!!! trust it
  1881. pGlobal = MCDSrvGetGlobalInfo(pwo->psoOwner);
  1882. if (pGlobal != NULL &&
  1883. pGlobal->mcdDriver.pMCDrvTrackWindow != NULL)
  1884. {
  1885. (pGlobal->mcdDriver.pMCDrvTrackWindow)
  1886. (pwo, (MCDWINDOW *)NULL, fl);
  1887. }
  1888. break;
  1889. case WOC_DELETE:
  1890. //MCDBG_PRINT("WndObjChangeProc: WOC_DELETE.");
  1891. // Window is being deleted, so destroy our private window data,
  1892. // and set the consumer field of the WNDOBJ to NULL:
  1893. if (pWndPriv)
  1894. {
  1895. DecoupleMCDWindow(pWndPriv);
  1896. }
  1897. break;
  1898. default:
  1899. break;
  1900. }
  1901. }
  1902. }
  1903. //****************************************************************************
  1904. // FreeMCDWindowObj()
  1905. //
  1906. // Callback to clean up MCDWINDOWs
  1907. //****************************************************************************
  1908. BOOL CALLBACK FreeMCDWindowObj(DRIVEROBJ *pDrvObj)
  1909. {
  1910. MCDWINDOWOBJ *pmwo = (MCDWINDOWOBJ *)pDrvObj->pvObj;
  1911. DestroyMCDWindowObj(pmwo);
  1912. return TRUE;
  1913. }
  1914. //****************************************************************************
  1915. // NewMCDWindowObj()
  1916. //
  1917. // Creates and initializes a new MCDWINDOW and initializes tracking of the
  1918. // associated window through callback notification.
  1919. //****************************************************************************
  1920. PRIVATE
  1921. MCDWINDOWOBJ *NewMCDWindowObj(MCDSURFACE *pMCDSurface,
  1922. MCDGLOBALINFO *pGlobal,
  1923. HDEV hdev)
  1924. {
  1925. MCDWINDOW *pWnd;
  1926. MCDWINDOWPRIV *pWndPriv;
  1927. MCDWINDOWOBJ *pmwo;
  1928. MCDENUMRECTS *pDefault;
  1929. MCDHANDLE handle;
  1930. pmwo = (MCDWINDOWOBJ *)MCDSrvLocalAlloc(0, sizeof(MCDWINDOWOBJ));
  1931. if (!pmwo)
  1932. {
  1933. return NULL;
  1934. }
  1935. // Create a driver object for this window
  1936. handle = MCDEngCreateObject(pmwo, FreeMCDWindowObj, hdev);
  1937. if (handle == 0)
  1938. {
  1939. MCDBG_PRINT("NewMCDWindow: Could not create new handle.");
  1940. MCDSrvLocalFree((UCHAR *)pmwo);
  1941. return NULL;
  1942. }
  1943. pWndPriv = &pmwo->MCDWindowPriv;
  1944. pWnd = &pWndPriv->MCDWindow;
  1945. // Initialize the structure members:
  1946. pmwo->type = MCDHANDLE_WINDOW;
  1947. pWndPriv->objectList = NULL;
  1948. pWndPriv->handle = handle;
  1949. pWndPriv->bBuffersValid = FALSE;
  1950. pWndPriv->pGlobal = pGlobal;
  1951. // Initialize the clipping:
  1952. pDefault = (MCDENUMRECTS*) &pWndPriv->defaultClipBuffer[0];
  1953. pDefault->c = 0;
  1954. pWndPriv->pAllocatedClipBuffer = NULL;
  1955. pWndPriv->pClipUnscissored = pDefault;
  1956. pWndPriv->sizeClipBuffer = SIZE_DEFAULT_CLIP_BUFFER;
  1957. pWndPriv->sizeClipBuffer = SIZE_DEFAULT_CLIP_BUFFER;
  1958. pWnd->pClip = pDefault;
  1959. return pmwo;
  1960. }
  1961. //****************************************************************************
  1962. // MCDSrvNewWndObj()
  1963. //
  1964. // Creates a new WNDOBJ for window tracking.
  1965. //****************************************************************************
  1966. PRIVATE
  1967. WNDOBJ *MCDSrvNewWndObj(MCDSURFACE *pMCDSurface, HWND hWnd, WNDOBJ *pwoIn,
  1968. MCDGLOBALINFO *pGlobal, HDEV hdev)
  1969. {
  1970. MCDWINDOW *pWnd;
  1971. MCDWINDOWPRIV *pWndPriv;
  1972. WNDOBJ *pwo;
  1973. MCDWINDOWOBJ *pmwo;
  1974. pmwo = NewMCDWindowObj(pMCDSurface, pGlobal, hdev);
  1975. if (!pmwo)
  1976. {
  1977. return NULL;
  1978. }
  1979. pWndPriv = &pmwo->MCDWindowPriv;
  1980. pWnd = &pWndPriv->MCDWindow;
  1981. pWndPriv->hWnd = hWnd;
  1982. // Handle the case where a WNDOBJ already exists but hasn't been
  1983. // initialized for MCD usage in addition to the new creation case.
  1984. if (pwoIn == NULL)
  1985. {
  1986. pwo = MCDEngCreateWndObj(pMCDSurface, hWnd, WndObjChangeProc);
  1987. if (!pwo || ((LONG_PTR)pwo == -1))
  1988. {
  1989. MCDBG_PRINT("NewMCDWindowTrack: could not create WNDOBJ.");
  1990. MCDEngDeleteObject(pmwo->MCDWindowPriv.handle);
  1991. return NULL;
  1992. }
  1993. }
  1994. else
  1995. {
  1996. pwo = pwoIn;
  1997. }
  1998. // Set the consumer field in the WNDOBJ:
  1999. WNDOBJ_vSetConsumer(pwo, (PVOID)pWndPriv);
  2000. // Point back to the WNDOBJ
  2001. pWndPriv->pwo = pwo;
  2002. return pwo;
  2003. }
  2004. //****************************************************************************
  2005. // MCDSrvNewMcdWindow()
  2006. //
  2007. // Creates a new MCDWINDOW for window tracking.
  2008. //****************************************************************************
  2009. PRIVATE
  2010. MCDWINDOW *MCDSrvNewMCDWindow(MCDSURFACE *pMCDSurface, HWND hWnd,
  2011. MCDGLOBALINFO *pGlobal, HDEV hdev)
  2012. {
  2013. MCDWINDOW *pWnd;
  2014. MCDWINDOWPRIV *pWndPriv;
  2015. MCDWINDOWOBJ *pmwo;
  2016. // Initialize tracking of this window with a MCDWINDOW
  2017. // (via a WNDOBJ on NT) if we are not already tracking the
  2018. // window:
  2019. if (pMCDSurface->surfaceFlags & MCDSURFACE_HWND)
  2020. {
  2021. WNDOBJ *pwo;
  2022. pwo = MCDEngGetWndObj(pMCDSurface);
  2023. // Sometimes a WNDOBJ has been used and the MCD state destroyed so
  2024. // the consumer is NULL but the WNDOBJ exists. In that case
  2025. // we need to create a new MCDWINDOW for it.
  2026. if (!pwo || !pwo->pvConsumer)
  2027. {
  2028. pwo = MCDSrvNewWndObj(pMCDSurface, hWnd, pwo, pGlobal, hdev);
  2029. if (!pwo)
  2030. {
  2031. MCDBG_PRINT("MCDSrvNewMcdWindow: "
  2032. "Creation of window object failed.");
  2033. return NULL;
  2034. }
  2035. ((MCDWINDOW *)pwo->pvConsumer)->pvUser = NULL;
  2036. }
  2037. pWnd = (MCDWINDOW *)pwo->pvConsumer;
  2038. }
  2039. else
  2040. {
  2041. #if MCD_VER_MAJOR >= 2 || (MCD_VER_MAJOR == 1 && MCD_VER_MINOR >= 0x10)
  2042. MCDENUMRECTS *pDefault;
  2043. PDD_SURFACE_GLOBAL pGbl;
  2044. pmwo = NewMCDWindowObj(pMCDSurface, pGlobal, hdev);
  2045. if (!pmwo)
  2046. {
  2047. MCDBG_PRINT("MCDSrvNewMcdWindow: "
  2048. "Creation of window object failed.");
  2049. return NULL;
  2050. }
  2051. pWnd = &pmwo->MCDWindowPriv.MCDWindow;
  2052. // Real clipping info
  2053. pWndPriv = (MCDWINDOWPRIV *)pWnd;
  2054. pGbl = ((PDD_SURFACE_LOCAL)pMCDSurface->frontId)->lpGbl;
  2055. pWndPriv->MCDWindow.clientRect.left = pGbl->xHint;
  2056. pWndPriv->MCDWindow.clientRect.top = pGbl->yHint;
  2057. pWndPriv->MCDWindow.clientRect.right = pGbl->xHint+pGbl->wWidth;
  2058. pWndPriv->MCDWindow.clientRect.bottom = pGbl->yHint+pGbl->wHeight;
  2059. pWndPriv->MCDWindow.clipBoundsRect = pWndPriv->MCDWindow.clientRect;
  2060. pWndPriv->bRegionValid = TRUE;
  2061. pDefault = (MCDENUMRECTS*) &pWndPriv->defaultClipBuffer[0];
  2062. pDefault->c = 1;
  2063. pDefault->arcl[0] = pWndPriv->MCDWindow.clientRect;
  2064. #else
  2065. return NULL;
  2066. #endif // 1.1
  2067. }
  2068. pMCDSurface->pWnd = pWnd;
  2069. pWndPriv = (MCDWINDOWPRIV *)pWnd;
  2070. pWndPriv->hWnd = hWnd;
  2071. return pWnd;
  2072. }
  2073. ////////////////////////////////////////////////////////////////////////////
  2074. //
  2075. //
  2076. // MCD locking support.
  2077. //
  2078. //
  2079. ////////////////////////////////////////////////////////////////////////////
  2080. //****************************************************************************
  2081. // ULONG MCDSrvLock(MCDWINDOWPRIV *pWndPriv);
  2082. //
  2083. // Lock the MCD driver for the specified window. Fails if lock is already
  2084. // held by another window.
  2085. //****************************************************************************
  2086. ULONG MCDSrvLock(MCDWINDOWPRIV *pWndPriv)
  2087. {
  2088. ULONG ulRet = MCD_LOCK_BUSY;
  2089. MCDLOCKINFO *pLockInfo;
  2090. pLockInfo = &pWndPriv->pGlobal->lockInfo;
  2091. if (!pLockInfo->bLocked || pLockInfo->pWndPrivOwner == pWndPriv)
  2092. {
  2093. pLockInfo->bLocked = TRUE;
  2094. pLockInfo->pWndPrivOwner = pWndPriv;
  2095. ulRet = MCD_LOCK_TAKEN;
  2096. }
  2097. return ulRet;
  2098. }
  2099. //****************************************************************************
  2100. // VOID MCDSrvUnlock(MCDWINDOWPRIV *pWndPriv);
  2101. //
  2102. // Releases the MCD driver lock if held by the specified window.
  2103. //****************************************************************************
  2104. VOID MCDSrvUnlock(MCDWINDOWPRIV *pWndPriv)
  2105. {
  2106. MCDLOCKINFO *pLockInfo;
  2107. //!!!dbug -- could add a lock count, but not really needed right now
  2108. pLockInfo = &pWndPriv->pGlobal->lockInfo;
  2109. if (pLockInfo->pWndPrivOwner == pWndPriv)
  2110. {
  2111. pLockInfo->bLocked = FALSE;
  2112. pLockInfo->pWndPrivOwner = 0;
  2113. }
  2114. }
  2115. //****************************************************************************
  2116. //
  2117. // Per-driver-instance information list handling.
  2118. //
  2119. //****************************************************************************
  2120. #define GLOBAL_INFO_BLOCK 8
  2121. ENGSAFESEMAPHORE ssemGlobalInfo;
  2122. MCDGLOBALINFO *pGlobalInfo;
  2123. int iGlobalInfoAllocated = 0;
  2124. int iGlobalInfoUsed = 0;
  2125. BOOL MCDSrvInitGlobalInfo(void)
  2126. {
  2127. return EngInitializeSafeSemaphore(&ssemGlobalInfo);
  2128. }
  2129. MCDGLOBALINFO *MCDSrvAddGlobalInfo(SURFOBJ *pso)
  2130. {
  2131. MCDGLOBALINFO *pGlobal;
  2132. EngAcquireSemaphore(ssemGlobalInfo.hsem);
  2133. // Ensure space for new entry
  2134. if (iGlobalInfoUsed >= iGlobalInfoAllocated)
  2135. {
  2136. pGlobal = (MCDGLOBALINFO *)
  2137. MCDSrvLocalAlloc(0, (iGlobalInfoAllocated+GLOBAL_INFO_BLOCK)*
  2138. sizeof(MCDGLOBALINFO));
  2139. if (pGlobal != NULL)
  2140. {
  2141. // Copy old data if necessary
  2142. if (iGlobalInfoAllocated > 0)
  2143. {
  2144. memcpy(pGlobal, pGlobalInfo, iGlobalInfoAllocated*
  2145. sizeof(MCDGLOBALINFO));
  2146. MCDSrvLocalFree((UCHAR *)pGlobalInfo);
  2147. }
  2148. // Set new information
  2149. pGlobalInfo = pGlobal;
  2150. iGlobalInfoAllocated += GLOBAL_INFO_BLOCK;
  2151. iGlobalInfoUsed++;
  2152. // pGlobal is guaranteed zero-filled because of MCDSrvLocalAlloc's
  2153. // behavior, so just fill in the pso.
  2154. pGlobal += iGlobalInfoAllocated;
  2155. pGlobal->pso = pso;
  2156. }
  2157. else
  2158. {
  2159. // Falls out and returns NULL
  2160. }
  2161. }
  2162. else
  2163. {
  2164. MCDGLOBALINFO *pGlobal;
  2165. int i;
  2166. pGlobal = pGlobalInfo;
  2167. for (i = 0; i < iGlobalInfoAllocated; i++)
  2168. {
  2169. if (pGlobal->pso == pso)
  2170. {
  2171. // This should never happen.
  2172. MCDBG_PRINT("MCDSrvAddGlobalInfo: duplicate pso");
  2173. pGlobal = NULL;
  2174. break;
  2175. }
  2176. if (pGlobal->pso == NULL)
  2177. {
  2178. iGlobalInfoUsed++;
  2179. // Initialize pso for use.
  2180. memset(pGlobal, 0, sizeof(*pGlobal));
  2181. pGlobal->pso = pso;
  2182. break;
  2183. }
  2184. pGlobal++;
  2185. }
  2186. }
  2187. EngReleaseSemaphore(ssemGlobalInfo.hsem);
  2188. return pGlobal;
  2189. }
  2190. MCDGLOBALINFO *MCDSrvGetGlobalInfo(SURFOBJ *pso)
  2191. {
  2192. MCDGLOBALINFO *pGlobal;
  2193. int i;
  2194. // For backwards compatibility we handle one instance
  2195. // using global data. If the incoming pso matches the
  2196. // pso in the static data then just return it.
  2197. // It is important to check this before entering the semaphore
  2198. // since the semaphore is not created if only legacy drivers
  2199. // have attached.
  2200. if (pso == gStaticGlobalInfo.pso)
  2201. {
  2202. return &gStaticGlobalInfo;
  2203. }
  2204. // Technically we shouldn't have to check this, since MCD processing
  2205. // should not occur unless:
  2206. // 1. It's an old style driver and hits the static case above.
  2207. // 2. It's a new style driver and the semaphore has been created.
  2208. // Unfortunately not all drivers are well-behaved, plus there's a
  2209. // potentialy legacy driver bug where drivers don't check for init
  2210. // failure and try to call MCD anyway.
  2211. if (ssemGlobalInfo.hsem == NULL)
  2212. {
  2213. MCDBG_PRINT("MCDSrvGetGlobalInfo: no hsem");
  2214. return NULL;
  2215. }
  2216. EngAcquireSemaphore(ssemGlobalInfo.hsem);
  2217. pGlobal = pGlobalInfo;
  2218. for (i = 0; i < iGlobalInfoAllocated; i++)
  2219. {
  2220. if (pGlobal->pso == pso)
  2221. {
  2222. break;
  2223. }
  2224. pGlobal++;
  2225. }
  2226. // Technically we shouldn't have to check this, because if
  2227. // we made it into the non-static code path a matching pso should
  2228. // be registered. As with the above check, though, it's better
  2229. // safe than sorry.
  2230. if (i >= iGlobalInfoAllocated)
  2231. {
  2232. MCDBG_PRINT("MCDSrvGetGlobalInfo: no pso match");
  2233. pGlobal = NULL;
  2234. }
  2235. EngReleaseSemaphore(ssemGlobalInfo.hsem);
  2236. return pGlobal;
  2237. }
  2238. void MCDSrvUninitGlobalInfo(void)
  2239. {
  2240. EngDeleteSafeSemaphore(&ssemGlobalInfo);
  2241. }
  2242. void WINAPI MCDEngUninit(SURFOBJ *pso)
  2243. {
  2244. MCDGLOBALINFO *pGlobal;
  2245. int i;
  2246. // This should never happen.
  2247. if (ssemGlobalInfo.hsem == NULL)
  2248. {
  2249. MCDBG_PRINT("MCDEngUninit: no hsem");
  2250. return;
  2251. }
  2252. EngAcquireSemaphore(ssemGlobalInfo.hsem);
  2253. pGlobal = pGlobalInfo;
  2254. for (i = 0; i < iGlobalInfoAllocated; i++)
  2255. {
  2256. if (pGlobal->pso == pso)
  2257. {
  2258. break;
  2259. }
  2260. pGlobal++;
  2261. }
  2262. if (i >= iGlobalInfoAllocated)
  2263. {
  2264. // This should never happen.
  2265. MCDBG_PRINT("MCDEngUninit: No pso match");
  2266. }
  2267. else if (--iGlobalInfoUsed == 0)
  2268. {
  2269. MCDSrvLocalFree((UCHAR *)pGlobalInfo);
  2270. iGlobalInfoAllocated = 0;
  2271. }
  2272. else
  2273. {
  2274. pGlobal->pso = NULL;
  2275. }
  2276. EngReleaseSemaphore(ssemGlobalInfo.hsem);
  2277. MCDSrvUninitGlobalInfo();
  2278. }
  2279. //****************************************************************************
  2280. // BOOL HalInitSystem(ULONG a, ULONG b)
  2281. //
  2282. // This is a dummy function needed to use the standard makefile.def since
  2283. // we're pretending we're an NT HAL.
  2284. //****************************************************************************
  2285. BOOL HalInitSystem(ULONG a, ULONG b)
  2286. {
  2287. return TRUE;
  2288. }
  2289. //******************************Public*Routine******************************
  2290. //
  2291. // BOOL WINAPI DllEntry(HINSTANCE hDLLInst, DWORD fdwReason,
  2292. // LPVOID lpvReserved);
  2293. //
  2294. // DLL entry point invoked for each process and thread that attaches to
  2295. // this DLL.
  2296. //
  2297. //**************************************************************************
  2298. BOOL WINAPI DllEntry(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
  2299. {
  2300. switch (fdwReason)
  2301. {
  2302. case DLL_PROCESS_ATTACH:
  2303. // The DLL is being loaded for the first time by a given process.
  2304. // Perform per-process initialization here. If the initialization
  2305. // is successful, return TRUE; if unsuccessful, return FALSE.
  2306. break;
  2307. case DLL_PROCESS_DETACH:
  2308. // The DLL is being unloaded by a given process. Do any
  2309. // per-process clean up here, such as undoing what was done in
  2310. // DLL_PROCESS_ATTACH. The return value is ignored.
  2311. break;
  2312. case DLL_THREAD_ATTACH:
  2313. // A thread is being created in a process that has already loaded
  2314. // this DLL. Perform any per-thread initialization here. The
  2315. // return value is ignored.
  2316. break;
  2317. case DLL_THREAD_DETACH:
  2318. // A thread is exiting cleanly in a process that has already
  2319. // loaded this DLL. Perform any per-thread clean up here. The
  2320. // return value is ignored.
  2321. break;
  2322. }
  2323. return TRUE;
  2324. }