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.

2250 lines
68 KiB

  1. /*
  2. ** Copyright 1991, 1992, Silicon Graphics, Inc.
  3. ** All Rights Reserved.
  4. **
  5. ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6. ** the contents of this file may not be disclosed to third parties, copied or
  7. ** duplicated in any form, in whole or in part, without the prior written
  8. ** permission of Silicon Graphics, Inc.
  9. **
  10. ** RESTRICTED RIGHTS LEGEND:
  11. ** Use, duplication or disclosure by the Government is subject to restrictions
  12. ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13. ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14. ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15. ** rights reserved under the Copyright Laws of the United States.
  16. */
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. #include <ntcsrdll.h> // CSR declarations and data structures.
  20. // #define DETECT_FPE
  21. #ifdef DETECT_FPE
  22. #include <float.h>
  23. #endif
  24. #include "glsbmsg.h"
  25. #include "glsbmsgh.h"
  26. #include "glsrvspt.h"
  27. #include "devlock.h"
  28. #include "global.h"
  29. #include "glscreen.h"
  30. typedef VOID * (FASTCALL *SERVERPROC)(__GLcontext *, IN VOID *);
  31. #define LASTPROCOFFSET(ProcTable) (sizeof(ProcTable) - sizeof(SERVERPROC))
  32. extern GLSRVSBPROCTABLE glSrvSbProcTable;
  33. #if DBG
  34. char *glSrvSbStringTable[] = {
  35. NULL, /* Make First Entry NULL */
  36. /* gl Entry points */
  37. "glDrawPolyArray ",
  38. "glBitmap ",
  39. "glColor4fv ",
  40. "glEdgeFlag ",
  41. "glIndexf ",
  42. "glNormal3fv ",
  43. "glRasterPos4fv ",
  44. "glTexCoord4fv ",
  45. "glClipPlane ",
  46. "glColorMaterial ",
  47. "glCullFace ",
  48. "glAddSwapHintRectWIN ",
  49. "glFogfv ",
  50. "glFrontFace ",
  51. "glHint ",
  52. "glLightfv ",
  53. "glLightModelfv ",
  54. "glLineStipple ",
  55. "glLineWidth ",
  56. "glMaterialfv ",
  57. "glPointSize ",
  58. "glPolygonMode ",
  59. "glPolygonStipple ",
  60. "glScissor ",
  61. "glShadeModel ",
  62. "glTexParameterfv ",
  63. "glTexParameteriv ",
  64. "glTexImage1D ",
  65. "glTexImage2D ",
  66. "glTexEnvfv ",
  67. "glTexEnviv ",
  68. "glTexGenfv ",
  69. "glFeedbackBuffer ",
  70. "glSelectBuffer ",
  71. "glRenderMode ",
  72. "glInitNames ",
  73. "glLoadName ",
  74. "glPassThrough ",
  75. "glPopName ",
  76. "glPushName ",
  77. "glDrawBuffer ",
  78. "glClear ",
  79. "glClearAccum ",
  80. "glClearIndex ",
  81. "glClearColor ",
  82. "glClearStencil ",
  83. "glClearDepth ",
  84. "glStencilMask ",
  85. "glColorMask ",
  86. "glDepthMask ",
  87. "glIndexMask ",
  88. "glAccum ",
  89. "glDisable ",
  90. "glEnable ",
  91. "glPopAttrib ",
  92. "glPushAttrib ",
  93. "glMap1d ",
  94. "glMap1f ",
  95. "glMap2d ",
  96. "glMap2f ",
  97. "glMapGrid1f ",
  98. "glMapGrid2f ",
  99. "glAlphaFunc ",
  100. "glBlendFunc ",
  101. "glLogicOp ",
  102. "glStencilFunc ",
  103. "glStencilOp ",
  104. "glDepthFunc ",
  105. "glPixelZoom ",
  106. "glPixelTransferf ",
  107. "glPixelTransferi ",
  108. "glPixelStoref ",
  109. "glPixelStorei ",
  110. "glPixelMapfv ",
  111. "glPixelMapuiv ",
  112. "glPixelMapusv ",
  113. "glReadBuffer ",
  114. "glCopyPixels ",
  115. "glReadPixels ",
  116. "glDrawPixels ",
  117. "glGetBooleanv ",
  118. "glGetClipPlane ",
  119. "glGetDoublev ",
  120. "glGetError ",
  121. "glGetFloatv ",
  122. "glGetIntegerv ",
  123. "glGetLightfv ",
  124. "glGetLightiv ",
  125. "glGetMapdv ",
  126. "glGetMapfv ",
  127. "glGetMapiv ",
  128. "glGetMaterialfv ",
  129. "glGetMaterialiv ",
  130. "glGetPixelMapfv ",
  131. "glGetPixelMapuiv ",
  132. "glGetPixelMapusv ",
  133. "glGetPolygonStipple ",
  134. "glGetTexEnvfv ",
  135. "glGetTexEnviv ",
  136. "glGetTexGendv ",
  137. "glGetTexGenfv ",
  138. "glGetTexGeniv ",
  139. "glGetTexImage ",
  140. "glGetTexParameterfv ",
  141. "glGetTexParameteriv ",
  142. "glGetTexLevelParameterfv ",
  143. "glGetTexLevelParameteriv ",
  144. "glIsEnabled ",
  145. "glDepthRange ",
  146. "glFrustum ",
  147. "glLoadIdentity ",
  148. "glLoadMatrixf ",
  149. "glMatrixMode ",
  150. "glMultMatrixf ",
  151. "glOrtho ",
  152. "glPopMatrix ",
  153. "glPushMatrix ",
  154. "glRotatef ",
  155. "glScalef ",
  156. "glTranslatef ",
  157. "glViewport ",
  158. "glAreTexturesResident ",
  159. "glBindTexture ",
  160. "glCopyTexImage1D ",
  161. "glCopyTexImage2D ",
  162. "glCopyTexSubImage1D ",
  163. "glCopyTexSubImage2D ",
  164. "glDeleteTextures ",
  165. "glGenTextures ",
  166. "glIsTexture ",
  167. "glPrioritizeTextures ",
  168. "glTexSubImage1D ",
  169. "glTexSubImage2D ",
  170. "glColorTableEXT ",
  171. "glColorSubTableEXT ",
  172. "glGetColorTableEXT ",
  173. "glGetColorTableParameterivEXT",
  174. "glGetColorTableParameterfvEXT",
  175. "glPolygonOffset ",
  176. #ifdef GL_WIN_multiple_textures
  177. "glCurrentTextureIndexWIN ",
  178. "glBindNthTextureWIN ",
  179. "glNthTexCombineFuncWIN ",
  180. #endif // GL_WIN_multiple_textures
  181. };
  182. #endif
  183. #ifdef DOGLMSGBATCHSTATS
  184. #define STATS_INC_SERVERCALLS() pMsgBatchInfo->BatchStats.ServerCalls++
  185. #define STATS_INC_SERVERTRIPS() (pMsgBatchInfo->BatchStats.ServerTrips++)
  186. #else
  187. #define STATS_INC_SERVERCALLS()
  188. #define STATS_INC_SERVERTRIPS()
  189. #endif
  190. DWORD BATCH_LOCK_TICKMAX = 99;
  191. DWORD TICK_RANGE_LO = 60;
  192. DWORD TICK_RANGE_HI = 100;
  193. DWORD gcmsOpenGLTimer;
  194. // The GDISAVESTATE structure is used to save/restore DC drawing state
  195. // that could affect OpenGL rasterization.
  196. typedef struct _GDISAVESTATE {
  197. int iRop2;
  198. } GDISAVESTATE;
  199. void FASTCALL vSaveGdiState(HDC, GDISAVESTATE *);
  200. void FASTCALL vRestoreGdiState(HDC, GDISAVESTATE *);
  201. #if DBG
  202. extern long glDebugLevel;
  203. #endif
  204. /***************************************************************************\
  205. * CheckCritSectionIn
  206. *
  207. * This function asserts that the current thread owns the specified
  208. * critical section. If it doesn't it display some output on the debugging
  209. * terminal and breaks into the debugger. At some point we'll have RIPs
  210. * and this will be a little less harsh.
  211. *
  212. * The function is used in code where global values that both the RIT and
  213. * application threads access are used to verify they are protected via
  214. * the raw input critical section. There's a macro to use this function
  215. * called CheckCritIn() which will be defined to nothing for a non-debug
  216. * version of the system.
  217. *
  218. * History:
  219. * 11-29-90 DavidPe Created.
  220. \***************************************************************************/
  221. #if DBG
  222. VOID APIENTRY CheckCritSectionIn(
  223. LPCRITICAL_SECTION pcs)
  224. {
  225. //!!!dbug -- implement
  226. #if 0
  227. /*
  228. * If the current thread doesn't own this critical section,
  229. * that's bad.
  230. */
  231. if (NtCurrentTeb()->ClientId.UniqueThread != pcs->OwningThread)
  232. {
  233. RIP("CheckCritSectionIn: Not in critical section!");
  234. }
  235. #endif
  236. }
  237. VOID APIENTRY CheckCritSectionOut(
  238. LPCRITICAL_SECTION pcs)
  239. {
  240. //!!!dbug -- implement
  241. #if 0
  242. /*
  243. * If the current thread owns this critical section, that's bad.
  244. */
  245. if (NtCurrentTeb()->ClientId.UniqueThread == pcs->OwningThread)
  246. {
  247. RIP("CheckCritSectionOut: In critical section!");
  248. }
  249. #endif
  250. }
  251. #endif
  252. /******************************Public*Routine******************************\
  253. * ResizeAlphaBufs
  254. *
  255. * Resize alpha buffers associated with the drawable.
  256. *
  257. * Returns:
  258. * No return value.
  259. \**************************************************************************/
  260. static void ResizeAlphaBufs(__GLcontext *gc, __GLGENbuffers *buffers,
  261. GLint width, GLint height)
  262. {
  263. __GLbuffer *common, *local;
  264. BOOL bSuccess;
  265. // front alpha buffer
  266. common = buffers->alphaFrontBuffer;
  267. // We are using the generic ancillary resize here...
  268. bSuccess = (*buffers->resize)(buffers, common, width, height);
  269. if( !bSuccess ) {
  270. __glSetError(GL_OUT_OF_MEMORY);
  271. return;
  272. }
  273. local = &gc->front->alphaBuf.buf;
  274. UpdateSharedBuffer( local, common );
  275. if ( gc->modes.doubleBufferMode) {
  276. // Handle back alpha buffer
  277. common = buffers->alphaBackBuffer;
  278. bSuccess = (*buffers->resize)(buffers, common, width, height);
  279. if( !bSuccess ) {
  280. __glSetError(GL_OUT_OF_MEMORY);
  281. return;
  282. }
  283. local = &gc->back->alphaBuf.buf;
  284. UpdateSharedBuffer( local, common );
  285. }
  286. }
  287. /******************************Public*Routine******************************\
  288. * ResizeAncillaryBufs
  289. *
  290. * Resize each of the ancillary buffers associated with the drawable.
  291. *
  292. * Returns:
  293. * No return value.
  294. \**************************************************************************/
  295. static void ResizeAncillaryBufs(__GLcontext *gc, __GLGENbuffers *buffers,
  296. GLint width, GLint height)
  297. {
  298. __GLbuffer *common, *local;
  299. GLboolean forcePick = GL_FALSE;
  300. if (buffers->createdAccumBuffer)
  301. {
  302. common = &buffers->accumBuffer;
  303. local = &gc->accumBuffer.buf;
  304. gc->modes.haveAccumBuffer =
  305. (*buffers->resize)(buffers, common, width, height);
  306. UpdateSharedBuffer(local, common);
  307. if (!gc->modes.haveAccumBuffer) // Lost the ancillary buffer
  308. {
  309. forcePick = GL_TRUE;
  310. __glSetError(GL_OUT_OF_MEMORY);
  311. }
  312. }
  313. if (buffers->createdDepthBuffer)
  314. {
  315. common = &buffers->depthBuffer;
  316. local = &gc->depthBuffer.buf;
  317. gc->modes.haveDepthBuffer =
  318. (*buffers->resizeDepth)(buffers, common, width, height);
  319. UpdateSharedBuffer(local, common);
  320. if (!gc->modes.haveDepthBuffer) // Lost the ancillary buffer
  321. {
  322. forcePick = GL_TRUE;
  323. __glSetError(GL_OUT_OF_MEMORY);
  324. }
  325. }
  326. if (buffers->createdStencilBuffer)
  327. {
  328. common = &buffers->stencilBuffer;
  329. local = &gc->stencilBuffer.buf;
  330. gc->modes.haveStencilBuffer =
  331. (*buffers->resize)(buffers, common, width, height);
  332. UpdateSharedBuffer(local, common);
  333. if (!gc->modes.haveStencilBuffer) // Lost the ancillary buffer
  334. {
  335. forcePick = GL_TRUE;
  336. gc->validateMask |= (__GL_VALIDATE_STENCIL_FUNC |
  337. __GL_VALIDATE_STENCIL_OP);
  338. __glSetError(GL_OUT_OF_MEMORY);
  339. }
  340. }
  341. if (forcePick)
  342. {
  343. // Cannot use DELAY_VALIDATE, may be in glBegin/End
  344. __GL_INVALIDATE(gc);
  345. (*gc->procs.validate)(gc);
  346. }
  347. }
  348. /******************************Public*Routine******************************\
  349. * wglResizeBuffers
  350. *
  351. * Resize the back and ancillary buffers.
  352. *
  353. * History:
  354. * 20-Apr-1996 -by- Gilman Wong [gilmanw]
  355. * Wrote it.
  356. \**************************************************************************/
  357. VOID wglResizeBuffers(__GLGENcontext *gengc, GLint width, GLint height)
  358. {
  359. __GLcontext *gc = &gengc->gc;
  360. GLGENwindow *pwnd;
  361. __GLGENbuffers *buffers;
  362. pwnd = gengc->pwndLocked;
  363. ASSERTOPENGL(pwnd, "wglResizeBuffers: bad window\n");
  364. buffers = pwnd->buffers;
  365. ASSERTOPENGL(buffers, "wglResizeBuffers: bad buffers\n");
  366. ASSERT_WINCRIT(pwnd);
  367. // Resize back buffer.
  368. gengc->errorcode = 0;
  369. if ( gengc->pMcdState )
  370. {
  371. // If the shared buffer struct has not lost its MCD info and
  372. // the MCD buffers are still valid, we can use MCD.
  373. if ( !(buffers->flags & GLGENBUF_MCD_LOST) &&
  374. GenMcdResizeBuffers(gengc) )
  375. {
  376. UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
  377. if (gc->modes.doubleBufferMode)
  378. (*gc->back->resize)(buffers, gc->back, width, height);
  379. }
  380. else
  381. {
  382. // If GenMcdConvertContext succeeds, then pMcdState will
  383. // no longer exist. The context is now an "ordinary"
  384. // generic context.
  385. if ( !GenMcdConvertContext(gengc, buffers) )
  386. {
  387. // Not only have we lost the MCD buffers, but we cannot
  388. // convert the context to generic. For now, disable
  389. // drawing (by setting the window bounds to empty). On
  390. // the next batch we will reattempt MCD buffer access
  391. // and context conversion.
  392. buffers->width = 0;
  393. buffers->height = 0;
  394. gc->constants.width = 0;
  395. gc->constants.height = 0;
  396. (*gc->procs.applyViewport)(gc);
  397. return;
  398. }
  399. else
  400. {
  401. goto wglResizeBuffers_GenericBackBuf;
  402. }
  403. }
  404. }
  405. else
  406. {
  407. wglResizeBuffers_GenericBackBuf:
  408. if ( gc->modes.doubleBufferMode )
  409. {
  410. // Have to update the back buffer BEFORE resizing because
  411. // another thread may have changed the shared back buffer
  412. // already, but this thread was unlucky enough to get yet
  413. // ANOTHER window resize.
  414. UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
  415. gengc->errorcode = 0;
  416. (*gc->back->resize)(buffers, gc->back, width, height);
  417. // If resize failed, set width & height to 0
  418. if ( gengc->errorcode )
  419. {
  420. gc->constants.width = 0;
  421. gc->constants.height = 0;
  422. // Memory failure has occured. But if a resize happens
  423. // that returns window size to size before memory error
  424. // occurred (i.e., consistent with original
  425. // buffers->{width|height}) we will not try to resize again.
  426. // Therefore, we need to set buffers->{width|height} to zero
  427. // to ensure that next thread will attempt to resize.
  428. buffers->width = 0;
  429. buffers->height = 0;
  430. }
  431. }
  432. if ( gc->modes.alphaBits )
  433. {
  434. ResizeAlphaBufs( gc, buffers, width, height );
  435. if (gengc->errorcode)
  436. return;
  437. }
  438. }
  439. (*gc->procs.applyViewport)(gc);
  440. // Check if new size caused a memory failure.
  441. // The viewport code will set width & height to zero
  442. // punt on ancillary buffers, will try next time.
  443. if (gengc->errorcode)
  444. return;
  445. // Resize ancillary buffers (depth, stencil, accum).
  446. ResizeAncillaryBufs(gc, buffers, width, height);
  447. }
  448. /******************************Public*Routine******************************\
  449. * wglUpdateBuffers
  450. *
  451. * The __GLGENbuffers structure contains the data specifying the shared
  452. * buffers (back, depth, stencil, accum, etc.).
  453. *
  454. * This function updates the context with the shared buffer information.
  455. *
  456. * Returns:
  457. * TRUE if one of the existence of any of the buffers changes (i.e.,
  458. * gained or lost). FALSE if the state is the same as before.
  459. *
  460. * In other words, if function returns TRUE, the pick procs need to
  461. * be rerun because one or more of the buffers changed.
  462. *
  463. * History:
  464. * 20-Apr-1996 -by- Gilman Wong [gilmanw]
  465. * Wrote it.
  466. \**************************************************************************/
  467. BOOL wglUpdateBuffers(__GLGENcontext *gengc, __GLGENbuffers *buffers)
  468. {
  469. BOOL bRet = FALSE;
  470. __GLcontext *gc = &gengc->gc;
  471. UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
  472. UpdateSharedBuffer(&gc->accumBuffer.buf, &buffers->accumBuffer);
  473. UpdateSharedBuffer(&gc->depthBuffer.buf, &buffers->depthBuffer);
  474. UpdateSharedBuffer(&gc->stencilBuffer.buf, &buffers->stencilBuffer);
  475. if( gc->modes.alphaBits ) {
  476. UpdateSharedBuffer(&gc->frontBuffer.alphaBuf.buf, buffers->alphaFrontBuffer);
  477. if (gc->modes.doubleBufferMode)
  478. UpdateSharedBuffer(&gc->backBuffer.alphaBuf.buf, buffers->alphaBackBuffer);
  479. }
  480. (*gc->procs.applyViewport)(gc);
  481. // Check if any ancillary buffers were lost or regained.
  482. if ( ( gc->modes.haveAccumBuffer && (buffers->accumBuffer.base == NULL)) ||
  483. (!gc->modes.haveAccumBuffer && (buffers->accumBuffer.base != NULL)) )
  484. {
  485. if ( buffers->accumBuffer.base == NULL )
  486. gc->modes.haveAccumBuffer = GL_FALSE;
  487. else
  488. gc->modes.haveAccumBuffer = GL_TRUE;
  489. bRet = TRUE;
  490. }
  491. if ( ( gc->modes.haveDepthBuffer && (buffers->depthBuffer.base == NULL)) ||
  492. (!gc->modes.haveDepthBuffer && (buffers->depthBuffer.base != NULL)) )
  493. {
  494. if ( buffers->depthBuffer.base == NULL )
  495. gc->modes.haveDepthBuffer = GL_FALSE;
  496. else
  497. gc->modes.haveDepthBuffer = GL_TRUE;
  498. bRet = TRUE;
  499. }
  500. if ( ( gc->modes.haveStencilBuffer && (buffers->stencilBuffer.base == NULL)) ||
  501. (!gc->modes.haveStencilBuffer && (buffers->stencilBuffer.base != NULL)) )
  502. {
  503. if ( buffers->stencilBuffer.base == NULL )
  504. gc->modes.haveStencilBuffer = GL_FALSE;
  505. else
  506. gc->modes.haveStencilBuffer = GL_TRUE;
  507. gc->validateMask |= (__GL_VALIDATE_STENCIL_FUNC |
  508. __GL_VALIDATE_STENCIL_OP);
  509. bRet = TRUE;
  510. }
  511. return bRet;
  512. }
  513. /******************************Public*Routine******************************\
  514. * UpdateWindowInfo
  515. *
  516. * Update context data if window changed
  517. * position
  518. * size
  519. * palette
  520. *
  521. * No need to worry about clipping changes.
  522. *
  523. * Returns:
  524. * No return value.
  525. \**************************************************************************/
  526. void UpdateWindowInfo(__GLGENcontext *gengc)
  527. {
  528. GLGENwindow *pwnd;
  529. __GLGENbuffers *buffers;
  530. __GLcontext *gc = (__GLcontext *)gengc;
  531. GLint width, height, visWidth, visHeight;
  532. GLboolean forcePick = GL_FALSE;
  533. pwnd = gengc->pwndLocked;
  534. ASSERTOPENGL(pwnd, "UpdateWindowInfo(): bad window\n");
  535. buffers = pwnd->buffers;
  536. ASSERTOPENGL(buffers, "UpdateWindowInfo(): bad buffers\n");
  537. ASSERT_WINCRIT(pwnd);
  538. // Memory DC case -- need to check bitmap size. The DC is not bound to
  539. // a window, so there is no message or visrgn watcher to inform us of size
  540. // changes.
  541. if ( GLSURF_IS_MEMDC(gengc->dwCurrentFlags) )
  542. {
  543. DIBSECTION ds;
  544. int iRetVal;
  545. if ( iRetVal =
  546. GetObject(GetCurrentObject(gengc->gwidCurrent.hdc, OBJ_BITMAP),
  547. sizeof(ds), &ds) )
  548. {
  549. ASSERTOPENGL(pwnd->rclClient.left == 0 &&
  550. pwnd->rclClient.top == 0,
  551. "UpdateWindowInfo(): bad rclClient for memDc\n");
  552. // Bitmap may have changed. If DIB, force reload of base pointer and
  553. // outer width (buffer pitch).
  554. if ( (iRetVal == sizeof(ds)) && ds.dsBm.bmBits )
  555. {
  556. // For backwards compatibility with Get/SetBitmapBits, GDI does
  557. // not accurately report the bitmap pitch in bmWidthBytes. It
  558. // always computes bmWidthBytes assuming WORD-aligned scanlines
  559. // regardless of the platform.
  560. //
  561. // Therefore, if the platform is WinNT, which uses DWORD-aligned
  562. // scanlines, adjust the bmWidthBytes value.
  563. if ( dwPlatformId == VER_PLATFORM_WIN32_NT )
  564. {
  565. ds.dsBm.bmWidthBytes = (ds.dsBm.bmWidthBytes + 3) & ~3;
  566. }
  567. // If biHeight is positive, then the bitmap is a bottom-up DIB.
  568. // If biHeight is negative, then the bitmap is a top-down DIB.
  569. if ( ds.dsBmih.biHeight > 0 )
  570. {
  571. gengc->gc.frontBuffer.buf.base = (PVOID) (((ULONG_PTR) ds.dsBm.bmBits) +
  572. (ds.dsBm.bmWidthBytes * (ds.dsBm.bmHeight - 1)));
  573. gengc->gc.frontBuffer.buf.outerWidth = -ds.dsBm.bmWidthBytes;
  574. }
  575. else
  576. {
  577. gengc->gc.frontBuffer.buf.base = ds.dsBm.bmBits;
  578. gengc->gc.frontBuffer.buf.outerWidth = ds.dsBm.bmWidthBytes;
  579. }
  580. }
  581. // Bitmap size different from window?
  582. if ( ds.dsBm.bmWidth != pwnd->rclClient.right ||
  583. ds.dsBm.bmHeight != pwnd->rclClient.bottom )
  584. {
  585. // Save new size.
  586. pwnd->rclClient.right = ds.dsBm.bmWidth;
  587. pwnd->rclClient.bottom = ds.dsBm.bmHeight;
  588. pwnd->rclBounds.right = ds.dsBm.bmWidth;
  589. pwnd->rclBounds.bottom = ds.dsBm.bmHeight;
  590. // Increment uniqueness numbers.
  591. // Don't let it hit -1. -1 is special and is used by
  592. // MakeCurrent to signal that an update is required
  593. buffers->WndUniq++;
  594. buffers->WndSizeUniq++;
  595. if (buffers->WndUniq == -1)
  596. buffers->WndUniq = 0;
  597. if (buffers->WndSizeUniq == -1)
  598. buffers->WndSizeUniq = 0;
  599. }
  600. }
  601. else
  602. {
  603. WARNING("UpdateWindowInfo: could not get bitmap info for memDc\n");
  604. }
  605. }
  606. // Compute current window dimensions.
  607. width = pwnd->rclClient.right - pwnd->rclClient.left;
  608. height = pwnd->rclClient.bottom - pwnd->rclClient.top;
  609. // Check MCD buffers.
  610. if ( gengc->pMcdState )
  611. {
  612. BOOL bAllocOK;
  613. // Do we need an initial MCDAllocBuffers (via GenMcdResizeBuffers)?
  614. // The bAllocOK flag will be set to FALSE if the resize fails.
  615. if ( gengc->pMcdState->mcdFlags & MCD_STATE_FORCERESIZE )
  616. {
  617. // Attempt resize. If it fails, convert context (see below).
  618. if (GenMcdResizeBuffers(gengc))
  619. {
  620. UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
  621. if (gc->modes.doubleBufferMode)
  622. (*gc->back->resize)(buffers, gc->back, width, height);
  623. bAllocOK = TRUE;
  624. }
  625. else
  626. bAllocOK = FALSE;
  627. // Clear the flag. If resize succeeded, we don't need to
  628. // force the resize again. If resize failed, the context
  629. // will be converted, so we don't need to force the resize.
  630. gengc->pMcdState->mcdFlags &= ~MCD_STATE_FORCERESIZE;
  631. }
  632. else
  633. bAllocOK = TRUE;
  634. // If the shared buffer struct has lost its MCD info or we could
  635. // not do the initial allocate, convert the context.
  636. if ( (buffers->flags & GLGENBUF_MCD_LOST) || !bAllocOK )
  637. {
  638. // If GenMcdConvertContext succeeds, then pMcdState will
  639. // no longer exist. The context is now an "ordinary"
  640. // generic context.
  641. if ( !GenMcdConvertContext(gengc, buffers) )
  642. {
  643. // Not only have we lost the MCD buffers, but we cannot
  644. // convert the context to generic. For now, disable
  645. // drawing (by setting the window bounds to empty). On
  646. // the next batch we will reattempt MCD buffer access
  647. // and context conversion.
  648. buffers->width = 0;
  649. buffers->height = 0;
  650. gc->constants.width = 0;
  651. gc->constants.height = 0;
  652. (*gc->procs.applyViewport)(gc);
  653. return;
  654. }
  655. }
  656. }
  657. // Check the uniqueness signature. If different, the window client area
  658. // state has changed.
  659. //
  660. // Note that we actually have two uniqueness numbers, WndUniq and WndSizeUniq.
  661. // WndUniq is incremented whenever any client window state (size or position)
  662. // changes. WndSizeUniq is incremented only when the size changes and is
  663. // maintained as an optimization. WndSizeUniq allows us to skip copying
  664. // the shared buffer info and recomputing the viewport if only the position
  665. // has changed.
  666. //
  667. // WndSizeUniq is a subset of WndUniq, so checking only WndUniq suffices at
  668. // this level.
  669. if ( gengc->WndUniq != buffers->WndUniq )
  670. {
  671. // Update origin of front buffer in case it moved
  672. gc->frontBuffer.buf.xOrigin = pwnd->rclClient.left;
  673. gc->frontBuffer.buf.yOrigin = pwnd->rclClient.top;
  674. // If acceleration is wired-in, set the offsets for line drawing.
  675. if ( gengc->pPrivateArea )
  676. {
  677. __fastLineComputeOffsets(gengc);
  678. }
  679. // Check for size changed
  680. // Update viewport and ancillary buffers
  681. visWidth = pwnd->rclBounds.right - pwnd->rclBounds.left;
  682. visHeight = pwnd->rclBounds.bottom - pwnd->rclBounds.top;
  683. // Sanity check the info from window.
  684. ASSERTOPENGL(
  685. width <= __GL_MAX_WINDOW_WIDTH && height <= __GL_MAX_WINDOW_HEIGHT,
  686. "UpdateWindowInfo(): bad window client size\n"
  687. );
  688. ASSERTOPENGL(
  689. visWidth <= __GL_MAX_WINDOW_WIDTH && visHeight <= __GL_MAX_WINDOW_HEIGHT,
  690. "UpdateWindowInfo(): bad visible size\n"
  691. );
  692. (*gc->front->resize)(buffers, gc->front, width, height);
  693. if ( (width != buffers->width) ||
  694. (height != buffers->height) )
  695. {
  696. gc->constants.width = width;
  697. gc->constants.height = height;
  698. // This RC needs to resize back & ancillary buffers
  699. gengc->errorcode = 0;
  700. wglResizeBuffers(gengc, width, height);
  701. // Check if new size caused a memory failure
  702. // viewport code will set width & height to zero
  703. // punt on ancillary buffers, will try next time
  704. if (gengc->errorcode)
  705. return;
  706. buffers->width = width;
  707. buffers->height = height;
  708. }
  709. else if ( (gengc->WndSizeUniq != buffers->WndSizeUniq) ||
  710. (width != gc->constants.width) ||
  711. (height != gc->constants.height) )
  712. {
  713. // The buffer size is consistent with the window, so another thread
  714. // has already resized the buffer, but we need to update the
  715. // gc shared buffers and recompute the viewport.
  716. gc->constants.width = width;
  717. gc->constants.height = height;
  718. forcePick = (GLboolean)wglUpdateBuffers(gengc, buffers);
  719. if ( forcePick )
  720. {
  721. /* Cannot use DELAY_VALIDATE, may be in glBegin/End */
  722. __GL_INVALIDATE(gc);
  723. (*gc->procs.validate)(gc);
  724. }
  725. }
  726. else if ( (visWidth != gengc->visibleWidth) ||
  727. (visHeight != gengc->visibleHeight) )
  728. {
  729. // The buffer size has not changed. However, the visibility of
  730. // the window has changed so the viewport data must be recomputed.
  731. (*gc->procs.applyViewport)(gc);
  732. }
  733. // Make sure we swap the whole window
  734. buffers->fMax = TRUE;
  735. // The context is now up-to-date with the buffer size. Set the
  736. // uniqueness numbers to match.
  737. gengc->WndUniq = buffers->WndUniq;
  738. gengc->WndSizeUniq = buffers->WndSizeUniq;
  739. }
  740. // Update palette info is palette has changed
  741. HandlePaletteChanges(gengc, pwnd);
  742. }
  743. /******************************Public*Routine******************************\
  744. * vSaveGdiState
  745. *
  746. * Saves current GDI drawing state to the GDISAVESTATE structure passed in.
  747. * Sets GDI state needed for OpenGL rendering.
  748. *
  749. * History:
  750. * 19-Jul-1996 -by- Gilman Wong [gilmanw]
  751. * Wrote it.
  752. \**************************************************************************/
  753. void FASTCALL vSaveGdiState(HDC hdc, GDISAVESTATE *pGdiState)
  754. {
  755. // Currently, the only state needed is the line code which may use
  756. // GDI lines. Rop2 must be R2_COPYPEN (draws with the pen color).
  757. pGdiState->iRop2 = SetROP2(hdc, R2_COPYPEN);
  758. }
  759. /******************************Public*Routine******************************\
  760. * vRestoreGdiState
  761. *
  762. * Restores GDI drawing state from the GDISAVESTATE structure passed in.
  763. *
  764. * History:
  765. * 19-Jul-1996 -by- Gilman Wong [gilmanw]
  766. * Wrote it.
  767. \**************************************************************************/
  768. void FASTCALL vRestoreGdiState(HDC hdc, GDISAVESTATE *pGdiState)
  769. {
  770. SetROP2(hdc, pGdiState->iRop2);
  771. }
  772. /******************************Public*Routine******************************\
  773. *
  774. * glsrvSynchronizeWithGdi
  775. *
  776. * Synchronizes access to a locked surface with GDI
  777. * This allows GDI calls to be made safely even on a locked surface
  778. * so that we don't have to release the lock we're holding
  779. *
  780. * Win95 doesn't allow this so it just releases the screen lock
  781. *
  782. * History:
  783. * Wed Aug 28 11:10:27 1996 -by- Drew Bliss [drewb]
  784. * Created
  785. *
  786. \**************************************************************************/
  787. #ifdef WINNT
  788. void APIENTRY glsrvSynchronizeWithGdi(__GLGENcontext *gengc,
  789. GLGENwindow *pwnd,
  790. FSHORT surfBits)
  791. {
  792. // Nothing to do
  793. }
  794. #else
  795. void APIENTRY glsrvSynchronizeWithGdi(__GLGENcontext *gengc,
  796. GLGENwindow *pwnd,
  797. FSHORT surfBits)
  798. {
  799. glsrvReleaseSurfaces(gengc, pwnd, surfBits);
  800. }
  801. #endif
  802. /******************************Public*Routine******************************\
  803. *
  804. * glsrvDecoupleFromGdi
  805. *
  806. * Indicates that it's no longer necessary to have GDI access to a surface
  807. * synchronized with direct memory access
  808. *
  809. * Exists for Win95 where synchronization isn't done so the screen lock
  810. * must be reacquired
  811. *
  812. * History:
  813. * Wed Aug 28 11:12:50 1996 -by- Drew Bliss [drewb]
  814. * Created
  815. *
  816. \**************************************************************************/
  817. #ifdef WINNT
  818. void APIENTRY glsrvDecoupleFromGdi(__GLGENcontext *gengc,
  819. GLGENwindow *pwnd,
  820. FSHORT surfBits)
  821. {
  822. GdiFlush();
  823. // Consider - How can this code be made surface specific? Right now
  824. // surfBits is ignored.
  825. // Wait for any GDI accelerator operations to complete before we
  826. // return to direct access
  827. if (gengc->pgddsFront != NULL)
  828. {
  829. // Is there a better way to do this than looping?
  830. // Does ISBLTDONE cover all the cases we need to wait for?
  831. for (;;)
  832. {
  833. if (gengc->pgddsFront->pdds->lpVtbl->
  834. GetBltStatus(gengc->pgddsFront->pdds,
  835. DDGBS_ISBLTDONE) != DDERR_WASSTILLDRAWING)
  836. {
  837. break;
  838. }
  839. Sleep(20);
  840. }
  841. }
  842. }
  843. #else
  844. void APIENTRY glsrvDecoupleFromGdi(__GLGENcontext *gengc,
  845. GLGENwindow *pwnd,
  846. FSHORT surfBits)
  847. {
  848. // Failure is unhandled
  849. glsrvGrabSurfaces(gengc, pwnd, surfBits);
  850. }
  851. #endif
  852. /******************************Public*Routine******************************\
  853. *
  854. * LockDdSurf
  855. *
  856. * Locks a GLDDSURF, handling surface loss
  857. *
  858. * History:
  859. * Wed Aug 28 15:32:08 1996 -by- Drew Bliss [drewb]
  860. * Created
  861. *
  862. \**************************************************************************/
  863. #define LDDS_LOCKED 0
  864. #define LDDS_LOCKED_NEW 1
  865. #define LDDS_ERROR 2
  866. // #define VERBOSE_LOCKDDSURF
  867. DWORD LockDdSurf(GLDDSURF *pgdds, RECT *prcClient)
  868. {
  869. HRESULT hr;
  870. LPDIRECTDRAWSURFACE pdds;
  871. DWORD dwRet;
  872. pdds = pgdds->pdds;
  873. dwRet = LDDS_LOCKED;
  874. hr = DDSLOCK(pdds, &pgdds->ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, prcClient);
  875. #ifdef VERBOSE_LOCKDDSURF
  876. if (hr != DD_OK)
  877. {
  878. DbgPrint("LockDdSurf: Lock failed with 0x%08lX\n", hr);
  879. }
  880. #endif
  881. // If lock failed because of a resolution change, try to recreate
  882. // the primary surface. We can only do this if the surface is the
  883. // screen surface because for app-provided DDraw surfaces we don't
  884. // know what content needs to be recreated on the lost surface before
  885. // it can be reused.
  886. if ( hr == DDERR_SURFACELOST &&
  887. pgdds == &GLSCREENINFO->gdds )
  888. {
  889. DDSURFACEDESC ddsd;
  890. memset(&ddsd, 0, sizeof(ddsd));
  891. ddsd.dwSize = sizeof(ddsd);
  892. if (pdds->lpVtbl->Restore(pdds) == DD_OK &&
  893. pdds->lpVtbl->GetSurfaceDesc(pdds, &ddsd) == DD_OK)
  894. {
  895. // While OpenGL generic implementation can handle screen dimension
  896. // changes, it cannot yet deal with a color depth change.
  897. if (ddsd.ddpfPixelFormat.dwRGBBitCount ==
  898. pgdds->ddsd.ddpfPixelFormat.dwRGBBitCount)
  899. {
  900. pgdds->ddsd = ddsd;
  901. // Try lock with the new surface.
  902. dwRet = LDDS_LOCKED_NEW;
  903. hr = DDSLOCK(pdds, &pgdds->ddsd,
  904. DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, prcClient);
  905. #ifdef VERBOSE_LOCKDDSURF
  906. if (hr != DD_OK)
  907. {
  908. DbgPrint("LockDdSurf: Relock failed with 0x%08lX\n", hr);
  909. }
  910. #endif
  911. }
  912. else
  913. {
  914. hr = DDERR_GENERIC;
  915. #ifdef VERBOSE_LOCKDDSURF
  916. DbgPrint("LockDdSurf: Bit count changed\n");
  917. #endif
  918. }
  919. }
  920. else
  921. {
  922. hr = DDERR_GENERIC;
  923. #ifdef VERBOSE_LOCKDDSURF
  924. DbgPrint("LockDdSurf: Restore/GetSurfaceDesc failed\n");
  925. #endif
  926. }
  927. }
  928. return hr == DD_OK ? dwRet : LDDS_ERROR;
  929. }
  930. /******************************Public*Routine******************************\
  931. * BeginDirectScreenAccess
  932. *
  933. * Attempts to begin direct screen access for the primary surface.
  934. *
  935. * If the screen resolution changes, the primary surface is invalidated. To
  936. * regain access, the primary surface must be recreated. If successful,
  937. * the pointer to the primary surface passed into this function will be
  938. * modified.
  939. *
  940. * Note: as currently written, generic implementation of OpenGL cannot
  941. * handle color depth changes. So we fail the call if this is detected.
  942. *
  943. * History:
  944. * 21-Mar-1996 -by- Gilman Wong [gilmanw]
  945. * Wrote it.
  946. \**************************************************************************/
  947. BOOL BeginDirectScreenAccess(__GLGENcontext *gengc, GLGENwindow *pwnd,
  948. PIXELFORMATDESCRIPTOR *ppfd)
  949. {
  950. DWORD dwRet;
  951. ASSERTOPENGL((pwnd->ulFlags & GLGENWIN_DIRECTSCREEN) == 0,
  952. "BeginDirectScreenAccess called with access\n");
  953. ASSERT_WINCRIT(pwnd);
  954. // Do not acquire access if gengc format does not match pixelformat.
  955. if (gengc->pgddsFront->dwBitDepth != ppfd->cColorBits)
  956. {
  957. WARNING("BeginDirectScreenAccess: "
  958. "surface not compatible with context\n");
  959. return FALSE;
  960. }
  961. // OK to try lock now.
  962. dwRet = LockDdSurf(gengc->pgddsFront, (RECT*) &pwnd->rclBounds);
  963. if (dwRet == LDDS_LOCKED_NEW)
  964. {
  965. __GLGENbuffers *buffers = (__GLGENbuffers *) NULL;
  966. // If screen changes, the MCD surfaces are lost and must be
  967. // recreated from scratch. This can be triggered by simply
  968. // changing the window uniqueness numbers.
  969. buffers = pwnd->buffers;
  970. if (buffers)
  971. {
  972. buffers->WndUniq++;
  973. buffers->WndSizeUniq++;
  974. // Don't let it hit -1. -1 is special and is used by
  975. // MakeCurrent to signal that an update is required
  976. if (buffers->WndUniq == -1)
  977. buffers->WndUniq = 0;
  978. if (buffers->WndSizeUniq == -1)
  979. buffers->WndSizeUniq = 0;
  980. }
  981. }
  982. // If we really have access to the surface, set the lock flag.
  983. // Otherwise return error.
  984. if (dwRet != LDDS_ERROR)
  985. {
  986. ASSERTOPENGL(gengc->pgddsFront->ddsd.lpSurface != NULL,
  987. "BeginDirectScreenAccess: expected non-NULL pointer\n");
  988. pwnd->pddsDirectScreen = gengc->pgddsFront->pdds;
  989. pwnd->pddsDirectScreen->lpVtbl->AddRef(pwnd->pddsDirectScreen);
  990. pwnd->pvDirectScreenLock = gengc->pgddsFront->ddsd.lpSurface;
  991. // DirectDraw returns a pointer offset to the specified rectangle;
  992. // undo that offset.
  993. gengc->pgddsFront->ddsd.lpSurface = (BYTE*) gengc->pgddsFront->ddsd.lpSurface
  994. - pwnd->rclBounds.left * (gengc->pgddsFront->ddsd.ddpfPixelFormat.dwRGBBitCount >> 3)
  995. - pwnd->rclBounds.top * gengc->pgddsFront->ddsd.lPitch;
  996. pwnd->pvDirectScreen = gengc->pgddsFront->ddsd.lpSurface;
  997. pwnd->ulFlags |= GLGENWIN_DIRECTSCREEN;
  998. return TRUE;
  999. }
  1000. else
  1001. {
  1002. //XXX too noisy in stress when mode changes enabled
  1003. //WARNING("BeginDirectScreenAccess failed\n");
  1004. return FALSE;
  1005. }
  1006. }
  1007. /******************************Public*Routine******************************\
  1008. * EndDirectScreenAccess
  1009. *
  1010. * Release lock acquired via BeginDirectScreenAccess.
  1011. *
  1012. * History:
  1013. * 28-Mar-1996 -by- Gilman Wong [gilmanw]
  1014. * Wrote it.
  1015. \**************************************************************************/
  1016. VOID EndDirectScreenAccess(GLGENwindow *pwnd)
  1017. {
  1018. ASSERTOPENGL(pwnd->ulFlags & GLGENWIN_DIRECTSCREEN,
  1019. "EndDirectScreenAccess: not holding screen lock!\n");
  1020. ASSERT_WINCRIT(pwnd);
  1021. pwnd->ulFlags &= ~GLGENWIN_DIRECTSCREEN;
  1022. if (pwnd->pddsDirectScreen != NULL)
  1023. {
  1024. DDSUNLOCK(pwnd->pddsDirectScreen, pwnd->pvDirectScreenLock);
  1025. pwnd->pddsDirectScreen->lpVtbl->Release(pwnd->pddsDirectScreen);
  1026. pwnd->pddsDirectScreen = NULL;
  1027. }
  1028. }
  1029. /******************************Public*Routine******************************\
  1030. *
  1031. * glsrvGrabSurfaces
  1032. *
  1033. * Acquire all necessary surface locks and handle any changes that occurred
  1034. * since the last acquisition.
  1035. *
  1036. * NOTE: surfBits is currently ignored because taking fine-grained
  1037. * locks can lead to deadlocks because lock need has no guaranteed
  1038. * order. To avoid this, all locks are taken if any locks are needed.
  1039. *
  1040. * History:
  1041. * Tue Apr 02 13:10:26 1996 -by- Drew Bliss [drewb]
  1042. * Split out of glsrvGrabLock
  1043. *
  1044. \**************************************************************************/
  1045. BOOL APIENTRY glsrvGrabSurfaces(__GLGENcontext *gengc, GLGENwindow *pwnd,
  1046. FSHORT surfBits)
  1047. {
  1048. #if DBG
  1049. // If debugging, remember the surface offset in case it changes when we grab
  1050. // the lock.
  1051. static void *pvCurSurf = NULL;
  1052. #endif
  1053. BOOL bDoOver;
  1054. FSHORT takeLocks;
  1055. FSHORT locksTaken = 0;
  1056. int lev = 0;
  1057. ASSERT_WINCRIT(pwnd);
  1058. #ifndef DEADLOCKS_OK
  1059. // See above note.
  1060. surfBits = LAZY_LOCK_FLAGS;
  1061. #endif
  1062. // Mask out MCD bit if no MCD.
  1063. if (gengc->pMcdState == NULL)
  1064. {
  1065. surfBits &= ~LOCKFLAG_MCD;
  1066. }
  1067. // Early out if we don't actually need locks for the requested surfaces.
  1068. takeLocks = gengc->fsGenLocks & surfBits;
  1069. if (takeLocks == 0)
  1070. {
  1071. return TRUE;
  1072. }
  1073. // We can assume this function is not invoked if we already have the lock.
  1074. ASSERTOPENGL((gengc->fsLocks & surfBits) == 0,
  1075. "glsrvGrabSurfaces: locks already held\n");
  1076. // We already check this in glsrvAttention, but there are other
  1077. // functions that call this so check that the window is correct
  1078. // to be safe.
  1079. if (pwnd != gengc->pwndMakeCur)
  1080. {
  1081. // One way an app could cause this is if the current HDC is released
  1082. // without releasing (wglMakeCurrent(0, 0)) the corresponding HGLRC.
  1083. // If GetDC returns this same HDC but for a different window, then
  1084. // pwndGetFromID will return the pwnd associated with the new window.
  1085. // However, the HGLRC is still bound to the original window. In
  1086. // such a situation we must fail the lock.
  1087. WARNING("glsrvGrabSurfaces: mismatched windows\n");
  1088. return FALSE;
  1089. }
  1090. if (takeLocks & LOCKFLAG_FRONT_BUFFER)
  1091. {
  1092. // Grab, test, and release the lock until the visregion is stable.
  1093. // IsClipListChanged is currently hard-coded to return TRUE,
  1094. // so force this loop to terminate after one update. If
  1095. // IsClipListChanged gets implemented correctly this will be
  1096. // unnecessary.
  1097. bDoOver = FALSE;
  1098. do
  1099. {
  1100. UpdateWindowInfo(gengc);
  1101. // Grab the screen lock.
  1102. if (!BeginDirectScreenAccess(gengc, pwnd, &gengc->gsurf.pfd))
  1103. {
  1104. #if 0
  1105. // Too verbose under stress.
  1106. WARNING("glsrvGrabLock(): BeginDirectScreenAccess failed\n");
  1107. #endif
  1108. goto glsrvGrabSurfaces_exit;
  1109. }
  1110. if (bDoOver)
  1111. {
  1112. break;
  1113. }
  1114. // The surface may not have a clipper associated with it.
  1115. if (pwnd->pddClip == NULL)
  1116. {
  1117. break;
  1118. }
  1119. // Did the window change during the time the lock was released?
  1120. // If so, we need recompute the clip list and call UpdateWindowInfo
  1121. // again.
  1122. if ( pwnd->pddClip->lpVtbl->
  1123. IsClipListChanged(pwnd->pddClip, &bDoOver) == DD_OK &&
  1124. bDoOver )
  1125. {
  1126. BOOL bHaveClip;
  1127. bHaveClip = wglGetClipList(pwnd);
  1128. // Release access because we're going to loop around
  1129. // to UpdateWindowInfo again and it makes a lot of
  1130. // GDI calls.
  1131. EndDirectScreenAccess(pwnd);
  1132. if (!bHaveClip)
  1133. {
  1134. WARNING("glsrvGrabSurfaces(): wglGetClipList failed\n");
  1135. goto glsrvGrabSurfaces_exit;
  1136. }
  1137. }
  1138. } while ( bDoOver );
  1139. // UpdateWindowInfo can cause a context conversion so we
  1140. // may have lost MCD state since the start of locking activity.
  1141. // Check again to make sure.
  1142. if (gengc->pMcdState == NULL)
  1143. {
  1144. surfBits &= ~LOCKFLAG_MCD;
  1145. takeLocks &= ~LOCKFLAG_MCD;
  1146. }
  1147. // Now that screen lock is held, set the lock flag.
  1148. locksTaken |= LOCKFLAG_FRONT_BUFFER;
  1149. }
  1150. // Lock Z surface if necessary.
  1151. if (takeLocks & LOCKFLAG_DD_DEPTH)
  1152. {
  1153. if (LockDdSurf(&gengc->gsurf.dd.gddsZ, NULL) == LDDS_ERROR)
  1154. {
  1155. goto glsrvGrabSurfaces_unlock;
  1156. }
  1157. locksTaken |= LOCKFLAG_DD_DEPTH;
  1158. }
  1159. // If there's a DirectDraw texture bound, lock its surface
  1160. // and all mipmaps for use.
  1161. if (takeLocks & LOCKFLAG_DD_TEXTURE)
  1162. {
  1163. GLDDSURF gdds;
  1164. gdds = gengc->gc.texture.ddtex.gdds;
  1165. for (lev = 0; lev < gengc->gc.texture.ddtex.levels; lev++)
  1166. {
  1167. gdds.pdds = gengc->gc.texture.ddtex.pdds[lev];
  1168. if (LockDdSurf(&gdds, NULL) == LDDS_ERROR)
  1169. {
  1170. goto glsrvGrabSurfaces_unlock;
  1171. }
  1172. gengc->gc.texture.ddtex.texobj.texture.map.level[lev].buffer =
  1173. gdds.ddsd.lpSurface;
  1174. }
  1175. locksTaken |= LOCKFLAG_DD_TEXTURE;
  1176. }
  1177. // Take MCD lock last so that buffer information is current.
  1178. if (takeLocks & LOCKFLAG_MCD)
  1179. {
  1180. ASSERTOPENGL(gengc->pMcdState != NULL,
  1181. "MCD lock request but no MCD\n");
  1182. if ((gpMcdTable->pMCDLock)(&gengc->pMcdState->McdContext) !=
  1183. MCD_LOCK_TAKEN)
  1184. {
  1185. WARNING("glsrvGrabSurfaces(): MCDLock failed\n");
  1186. goto glsrvGrabSurfaces_unlock;
  1187. }
  1188. locksTaken |= LOCKFLAG_MCD;
  1189. }
  1190. gengc->fsLocks |= locksTaken;
  1191. ASSERTOPENGL(((gengc->fsLocks ^ gengc->fsGenLocks) & surfBits) == 0,
  1192. "Real locks/generic locks mismatch\n");
  1193. if (takeLocks & LOCKFLAG_MCD)
  1194. {
  1195. // This must be called after fsLocks is updated since
  1196. // GenMcdUpdateBufferInfo checks fsLocks to see what locks
  1197. // are held.
  1198. GenMcdUpdateBufferInfo(gengc);
  1199. }
  1200. // Base and width may have changed since last lock. Refresh
  1201. // the data in the gengc.
  1202. // If the MCD lock was taken then the front buffer pointer was
  1203. // updated.
  1204. if ((takeLocks & (LOCKFLAG_FRONT_BUFFER | LOCKFLAG_MCD)) ==
  1205. LOCKFLAG_FRONT_BUFFER)
  1206. {
  1207. gengc->gc.frontBuffer.buf.base =
  1208. (VOID *)gengc->pgddsFront->ddsd.lpSurface;
  1209. gengc->gc.frontBuffer.buf.outerWidth =
  1210. gengc->pgddsFront->ddsd.lPitch;
  1211. }
  1212. if (takeLocks & LOCKFLAG_DD_DEPTH)
  1213. {
  1214. gengc->gc.depthBuffer.buf.base =
  1215. gengc->gsurf.dd.gddsZ.ddsd.lpSurface;
  1216. if (gengc->gsurf.dd.gddsZ.dwBitDepth == 16)
  1217. {
  1218. gengc->gc.depthBuffer.buf.outerWidth =
  1219. gengc->gsurf.dd.gddsZ.ddsd.lPitch >> 1;
  1220. }
  1221. else
  1222. {
  1223. gengc->gc.depthBuffer.buf.outerWidth =
  1224. gengc->gsurf.dd.gddsZ.ddsd.lPitch >> 2;
  1225. }
  1226. }
  1227. // Record the approximate time the lock was grabbed. That way we
  1228. // can compute the time the lock is held and release it if necessary.
  1229. gcmsOpenGLTimer = GetTickCount();
  1230. gengc->dwLockTick = gcmsOpenGLTimer;
  1231. gengc->dwLastTick = gcmsOpenGLTimer;
  1232. gengc->dwCalls = 0;
  1233. gengc->dwCallsPerTick = 16;
  1234. #if DBG
  1235. #define LEVEL_SCREEN LEVEL_INFO
  1236. if (takeLocks & LOCKFLAG_FRONT_BUFFER)
  1237. {
  1238. // Did the surface offset change? If so, report it if debugging.
  1239. if (pvCurSurf != gengc->pgddsFront->ddsd.lpSurface)
  1240. {
  1241. DBGLEVEL (LEVEL_SCREEN, "=============================\n");
  1242. DBGLEVEL (LEVEL_SCREEN, "Surface offset changed\n\n");
  1243. DBGLEVEL1(LEVEL_SCREEN, "\tdwOffSurface = 0x%lx\n",
  1244. gengc->pgddsFront->ddsd.lpSurface);
  1245. DBGLEVEL (LEVEL_SCREEN, "=============================\n");
  1246. pvCurSurf = gengc->pgddsFront->ddsd.lpSurface;
  1247. }
  1248. }
  1249. #endif
  1250. return TRUE;
  1251. glsrvGrabSurfaces_unlock:
  1252. while (--lev >= 0)
  1253. {
  1254. DDSUNLOCK(gengc->gc.texture.ddtex.pdds[lev],
  1255. gengc->gc.texture.ddtex.
  1256. texobj.texture.map.level[lev].buffer);
  1257. #if DBG
  1258. gengc->gc.texture.ddtex.texobj.texture.map.level[lev].buffer = NULL;
  1259. #endif
  1260. }
  1261. if (locksTaken & LOCKFLAG_DD_DEPTH)
  1262. {
  1263. DDSUNLOCK(gengc->gsurf.dd.gddsZ.pdds,
  1264. gengc->gsurf.dd.gddsZ.ddsd.lpSurface);
  1265. }
  1266. if (locksTaken & LOCKFLAG_FRONT_BUFFER)
  1267. {
  1268. EndDirectScreenAccess(pwnd);
  1269. }
  1270. glsrvGrabSurfaces_exit:
  1271. // Set the error codes. GL_OUT_OF_MEMORY is used not because we
  1272. // actually had a memory failure, but because this implies that
  1273. // the OpenGL state is now indeterminate.
  1274. gengc->errorcode = GLGEN_DEVLOCK_FAILED;
  1275. __glSetError(GL_OUT_OF_MEMORY);
  1276. return FALSE;
  1277. }
  1278. /******************************Public*Routine******************************\
  1279. *
  1280. * glsrvReleaseSurfaces
  1281. *
  1282. * Releases all resources held for screen access
  1283. *
  1284. * History:
  1285. * Tue Apr 02 13:18:52 1996 -by- Drew Bliss [drewb]
  1286. * Split from glsrvReleaseLock
  1287. *
  1288. \**************************************************************************/
  1289. VOID APIENTRY glsrvReleaseSurfaces(__GLGENcontext *gengc,
  1290. GLGENwindow *pwnd,
  1291. FSHORT surfBits)
  1292. {
  1293. FSHORT relLocks;
  1294. ASSERT_WINCRIT(pwnd);
  1295. #ifndef DEADLOCKS_OK
  1296. // See above note.
  1297. surfBits = LAZY_LOCK_FLAGS;
  1298. #endif
  1299. // Mask out MCD bit if no MCD.
  1300. if (gengc->pMcdState == NULL)
  1301. {
  1302. surfBits &= ~LOCKFLAG_MCD;
  1303. }
  1304. // Early exit if locks are not actually held.
  1305. relLocks = gengc->fsGenLocks & surfBits;
  1306. if (relLocks == 0)
  1307. {
  1308. return;
  1309. }
  1310. if (relLocks & LOCKFLAG_MCD)
  1311. {
  1312. ASSERTOPENGL(gengc->pMcdState != NULL,
  1313. "MCD unlock request but no MCD\n");
  1314. (gpMcdTable->pMCDUnlock)(&gengc->pMcdState->McdContext);
  1315. gengc->fsLocks &= ~LOCKFLAG_MCD;
  1316. }
  1317. if (relLocks & LOCKFLAG_DD_TEXTURE)
  1318. {
  1319. int lev;
  1320. lev = gengc->gc.texture.ddtex.levels;
  1321. while (--lev >= 0)
  1322. {
  1323. DDSUNLOCK(gengc->gc.texture.ddtex.pdds[lev],
  1324. gengc->gc.texture.ddtex.
  1325. texobj.texture.map.level[lev].buffer);
  1326. #if DBG
  1327. gengc->gc.texture.ddtex.texobj.texture.
  1328. map.level[lev].buffer = NULL;
  1329. #endif
  1330. }
  1331. gengc->fsLocks &= ~LOCKFLAG_DD_TEXTURE;
  1332. }
  1333. if (relLocks & LOCKFLAG_DD_DEPTH)
  1334. {
  1335. DDSUNLOCK(gengc->gsurf.dd.gddsZ.pdds,
  1336. gengc->gsurf.dd.gddsZ.ddsd.lpSurface);
  1337. gengc->fsLocks &= ~LOCKFLAG_DD_DEPTH;
  1338. #if DBG
  1339. // NULL out our buffer information to ensure that we
  1340. // can't access the surface unless we're really holding the lock
  1341. gengc->gc.depthBuffer.buf.base = NULL;
  1342. gengc->gc.depthBuffer.buf.outerWidth = 0;
  1343. #endif
  1344. }
  1345. if (relLocks & LOCKFLAG_FRONT_BUFFER)
  1346. {
  1347. EndDirectScreenAccess(pwnd);
  1348. gengc->fsLocks &= ~LOCKFLAG_FRONT_BUFFER;
  1349. #if DBG
  1350. // NULL out our front-buffer information to ensure that we
  1351. // can't access the surface unless we're really holding the lock
  1352. gengc->gc.frontBuffer.buf.base = NULL;
  1353. gengc->gc.frontBuffer.buf.outerWidth = 0;
  1354. #endif
  1355. }
  1356. ASSERTOPENGL((gengc->fsLocks & surfBits) == 0,
  1357. "Surface locks still held after ReleaseSurfaces\n");
  1358. }
  1359. /******************************Public*Routine******************************\
  1360. * glsrvGrabLock
  1361. *
  1362. * Grab the display lock and tear down the cursor as needed. Also, initialize
  1363. * the tickers and such that help determine when the thread should give up
  1364. * the lock.
  1365. *
  1366. * Note that for contexts that draw only to the generic back buffer do not
  1367. * need to grab the display lock or tear down the cursor. However, to prevent
  1368. * another thread of a multithreaded app from resizing the drawable while
  1369. * this thread is using it, a per-drawable semaphore will be grabbed.
  1370. *
  1371. * Note: while the return value indicates whether the function succeeded,
  1372. * some APIs that might call this (like the dispatch function for glCallList
  1373. * and glCallLists) may not be able to return failure. So, an error code
  1374. * of GLGEN_DEVLOCK_FAILED is posted to the GLGENcontext if the lock fails.
  1375. *
  1376. * Returns:
  1377. * TRUE if successful, FALSE otherwise.
  1378. *
  1379. * History:
  1380. * 12-Apr-1994 -by- Gilman Wong [gilmanw]
  1381. * Wrote it.
  1382. \**************************************************************************/
  1383. BOOL APIENTRY glsrvGrabLock(__GLGENcontext *gengc)
  1384. {
  1385. BOOL bRet = FALSE;
  1386. BOOL bBackBufferOnly = GENERIC_BACKBUFFER_ONLY((__GLcontext *) gengc);
  1387. GLGENwindow *pwnd;
  1388. ASSERTOPENGL(gengc->pwndLocked == NULL,
  1389. "Unlocked gengc with window pointer\n");
  1390. // Mostly ignore attempts to lock IC's
  1391. if (gengc->gsurf.dwFlags & GLSURF_METAFILE)
  1392. {
  1393. // If we're running with a real window then we need to look it
  1394. // up to detect whether it's died or not
  1395. if (gengc->ipfdCurrent != 0)
  1396. {
  1397. pwnd = pwndGetFromID(&gengc->gwidCurrent);
  1398. if (pwnd == NULL)
  1399. {
  1400. return FALSE;
  1401. }
  1402. if (pwnd != gengc->pwndMakeCur)
  1403. {
  1404. WARNING("glsrvGrabLock: mismatched windows (info DC)\n");
  1405. pwndRelease(pwnd);
  1406. return FALSE;
  1407. }
  1408. }
  1409. else
  1410. {
  1411. pwnd = gengc->pwndMakeCur;
  1412. }
  1413. ENTER_WINCRIT_GC(pwnd, gengc);
  1414. UpdateWindowInfo(gengc);
  1415. return TRUE;
  1416. }
  1417. // Get the window from the DC. This has the side effect of locking it
  1418. // against deletion.
  1419. pwnd = pwndGetFromID(&gengc->gwidCurrent);
  1420. if (pwnd == NULL)
  1421. {
  1422. WARNING("glsrvGrabLock: No pwnd found\n");
  1423. goto glsrvGrabLock_exit;
  1424. }
  1425. if (pwnd != gengc->pwndMakeCur)
  1426. {
  1427. // One way an app could cause this is if the current HDC is released
  1428. // without releasing (wglMakeCurrent(0, 0)) the corresponding HGLRC.
  1429. // If GetDC returns this same HDC but for a different window, then
  1430. // pwndGetFromID will return the pwnd associated with the new window.
  1431. // However, the HGLRC is still bound to the original window. In
  1432. // such a situation we must fail the lock.
  1433. #ifdef BAD_WINDOW_BREAK
  1434. DbgPrint("%p:%p:%p thinks %p:%p but finds %p:%p\n",
  1435. gengc, gengc->gwidCurrent.hdc, gengc->gwidCurrent.hwnd,
  1436. gengc->pwndMakeCur, gengc->pwndMakeCur->gwid.hwnd,
  1437. pwnd, pwnd->gwid.hwnd);
  1438. DebugBreak();
  1439. #else
  1440. WARNING("glsrvGrabLock: mismatched windows\n");
  1441. #endif
  1442. goto glsrvGrabLock_exit;
  1443. }
  1444. //
  1445. // Compute locks necessary for generic rendering code to operate.
  1446. // If a non-generic code path is going to run first these locks
  1447. // won't actually be taken until after the non-generic code
  1448. // has had a chance at rendering.
  1449. //
  1450. // We always need the window lock.
  1451. gengc->fsGenLocks = LOCKFLAG_WINDOW;
  1452. // If MCD is active we need to do MCD locking.
  1453. if (gengc->pMcdState != NULL)
  1454. {
  1455. gengc->fsGenLocks |= LOCKFLAG_MCD;
  1456. }
  1457. // If we're going to be drawing to a direct-access front-buffer
  1458. // then we need the front buffer lock. MCD always requires
  1459. // a front buffer lock on direct access buffers, so if
  1460. // MCD is active the only thing that is checked is direct access.
  1461. if ((gengc->pMcdState != NULL || !bBackBufferOnly) &&
  1462. gengc->pgddsFront != NULL)
  1463. {
  1464. gengc->fsGenLocks |= LOCKFLAG_FRONT_BUFFER;
  1465. }
  1466. // If we have a DDraw depth buffer we need a lock on it.
  1467. if ((gengc->dwCurrentFlags & GLSURF_DIRECTDRAW) &&
  1468. gengc->gsurf.dd.gddsZ.pdds != NULL)
  1469. {
  1470. gengc->fsGenLocks |= LOCKFLAG_DD_DEPTH;
  1471. }
  1472. // If we have a current DDraw texture we need a lock on it.
  1473. if (gengc->gc.texture.ddtex.levels > 0)
  1474. {
  1475. gengc->fsGenLocks |= LOCKFLAG_DD_TEXTURE;
  1476. }
  1477. // All lock types require the GLGENwindow structure lock.
  1478. ENTER_WINCRIT_GC(pwnd, gengc);
  1479. gengc->fsLocks |= LOCKFLAG_WINDOW;
  1480. // If the current window is out-of-process then we haven't
  1481. // been receiving any updates on its status. Manually
  1482. // check its position, size and palette information
  1483. if (pwnd->ulFlags & GLGENWIN_OTHERPROCESS)
  1484. {
  1485. RECT rct;
  1486. POINT pt;
  1487. BOOL bPosChanged, bSizeChanged;
  1488. if (!IsWindow(pwnd->gwid.hwnd))
  1489. {
  1490. // Window was destroyed
  1491. pwndCleanup(pwnd);
  1492. pwnd = NULL;
  1493. goto glsrvGrabLock_exit;
  1494. }
  1495. if (!GetClientRect(pwnd->gwid.hwnd, &rct))
  1496. {
  1497. goto glsrvGrabLock_exit;
  1498. }
  1499. pt.x = rct.left;
  1500. pt.y = rct.top;
  1501. if (!ClientToScreen(pwnd->gwid.hwnd, &pt))
  1502. {
  1503. goto glsrvGrabLock_exit;
  1504. }
  1505. bPosChanged =
  1506. GLDIRECTSCREEN &&
  1507. (pt.x != pwnd->rclClient.left ||
  1508. pt.y != pwnd->rclClient.top);
  1509. bSizeChanged =
  1510. rct.right != (pwnd->rclClient.right-pwnd->rclClient.left) ||
  1511. rct.bottom != (pwnd->rclClient.bottom-pwnd->rclClient.top);
  1512. if (bPosChanged || bSizeChanged)
  1513. {
  1514. __GLGENbuffers *buffers = NULL;
  1515. pwnd->rclClient.left = pt.x;
  1516. pwnd->rclClient.top = pt.y;
  1517. pwnd->rclClient.right = pt.x+rct.right;
  1518. pwnd->rclClient.bottom = pt.y+rct.bottom;
  1519. pwnd->rclBounds = pwnd->rclClient;
  1520. buffers = pwnd->buffers;
  1521. if (buffers != NULL)
  1522. {
  1523. // Don't let it hit -1. -1 is special and is used by
  1524. // MakeCurrent to signal that an update is required
  1525. if (++buffers->WndUniq == -1)
  1526. {
  1527. buffers->WndUniq = 0;
  1528. }
  1529. if (bSizeChanged &&
  1530. ++buffers->WndSizeUniq == -1)
  1531. {
  1532. buffers->WndSizeUniq = 0;
  1533. }
  1534. }
  1535. }
  1536. // The palette watcher should be active since we
  1537. // are going to use its count.
  1538. if (tidPaletteWatcherThread == 0)
  1539. {
  1540. goto glsrvGrabLock_exit;
  1541. }
  1542. pwnd->ulPaletteUniq = ulPaletteWatcherCount;
  1543. }
  1544. // If there's no MCD then generic code is going to be entered
  1545. // immediately so go ahead and grab the appropriate locks.
  1546. // Update drawables.
  1547. if ( gengc->pMcdState == NULL &&
  1548. gengc->fsGenLocks != gengc->fsLocks )
  1549. {
  1550. // UpdateWindowInfo needs to be called to ensure that
  1551. // the gc's buffer state is synchronized with the current window
  1552. // state. Locking the front buffer will do this, but if
  1553. // we aren't locking the front buffer then we need to do
  1554. // it here to make sure it gets done.
  1555. if ((gengc->fsGenLocks & LOCKFLAG_FRONT_BUFFER) == 0)
  1556. {
  1557. UpdateWindowInfo(gengc);
  1558. }
  1559. if (!glsrvGrabSurfaces(gengc, pwnd, gengc->fsGenLocks))
  1560. {
  1561. goto glsrvGrabLock_exit;
  1562. }
  1563. }
  1564. else
  1565. {
  1566. UpdateWindowInfo(gengc);
  1567. // Update MCD buffer state for MCD drivers w/o direct support.
  1568. if (gengc->pMcdState)
  1569. {
  1570. GenMcdUpdateBufferInfo(gengc);
  1571. }
  1572. else
  1573. {
  1574. // UpdateWindowInfo can result in a context conversion.
  1575. // This can be detected if pMcdState is NULL but
  1576. // fsGenLocks is different from fsLocks (which implies that
  1577. // pMcdState was not NULL prior to the call to
  1578. // UpdateWindowInfo).
  1579. //
  1580. // If so, the locks must be grabbed immediately.
  1581. gengc->fsGenLocks &= ~LOCKFLAG_MCD;
  1582. if ( gengc->fsGenLocks != gengc->fsLocks )
  1583. {
  1584. if (!glsrvGrabSurfaces(gengc, pwnd, gengc->fsGenLocks))
  1585. {
  1586. goto glsrvGrabLock_exit;
  1587. }
  1588. }
  1589. }
  1590. }
  1591. bRet = TRUE;
  1592. glsrvGrabLock_exit:
  1593. if (!bRet)
  1594. {
  1595. gengc->fsGenLocks = 0;
  1596. gengc->fsLocks = 0;
  1597. if (pwnd != NULL)
  1598. {
  1599. if (gengc->pwndLocked != NULL)
  1600. {
  1601. LEAVE_WINCRIT_GC(pwnd, gengc);
  1602. }
  1603. pwndRelease(pwnd);
  1604. }
  1605. // Set the error codes. GL_OUT_OF_MEMORY is used not because we
  1606. // actually had a memory failure, but because this implies that
  1607. // the OpenGL state is now indeterminate.
  1608. gengc->errorcode = GLGEN_DEVLOCK_FAILED;
  1609. __glSetError(GL_OUT_OF_MEMORY);
  1610. }
  1611. return bRet;
  1612. }
  1613. /******************************Public*Routine******************************\
  1614. * glsrvReleaseLock
  1615. *
  1616. * Releases display or drawable semaphore as appropriate.
  1617. *
  1618. * Returns:
  1619. * No return value.
  1620. *
  1621. * History:
  1622. * 12-Apr-1994 -by- Gilman Wong [gilmanw]
  1623. * Wrote it.
  1624. \**************************************************************************/
  1625. VOID APIENTRY glsrvReleaseLock(__GLGENcontext *gengc)
  1626. {
  1627. GLGENwindow *pwnd = gengc->pwndLocked;
  1628. GLint lev;
  1629. ASSERTOPENGL(gengc->pwndLocked != NULL, "glsrvReleaseLock: No window\n");
  1630. // Mostly ignore attempts to lock IC's
  1631. if (gengc->gsurf.dwFlags & GLSURF_METAFILE)
  1632. {
  1633. LEAVE_WINCRIT_GC(pwnd, gengc);
  1634. // If we have a real window we need to release it
  1635. if (gengc->ipfdCurrent != 0)
  1636. {
  1637. pwndRelease(pwnd);
  1638. }
  1639. return;
  1640. }
  1641. if ( gengc->fsLocks & LAZY_LOCK_FLAGS )
  1642. {
  1643. glsrvReleaseSurfaces(gengc, pwnd, gengc->fsLocks);
  1644. }
  1645. ASSERTOPENGL(gengc->fsLocks == LOCKFLAG_WINDOW,
  1646. "Wrong locks held\n");
  1647. // Note: pwndUnlock releases the window semaphore.
  1648. pwndUnlock(pwnd, gengc);
  1649. gengc->fsGenLocks = 0;
  1650. gengc->fsLocks = 0;
  1651. }
  1652. /******************************Public*Routine******************************\
  1653. * glsrvAttention
  1654. *
  1655. * Dispatches each of the OpenGL API calls in the shared memory window.
  1656. *
  1657. * So that a single complex or long batch does not starve the rest of the
  1658. * system, the lock is released periodically based on the number of ticks
  1659. * that have elapsed since the lock was acquired.
  1660. *
  1661. * The user Raw Input Thread (RIT) and OpenGL share the gcmsOpenGLTimer
  1662. * value. Because the RIT may be blocked, it does not always service
  1663. * the gcmsOpenGLTimer. To compensate, glsrvAttention (as well as the
  1664. * display list dispatchers for glCallList and glCallLists) update
  1665. * gcmsOpenGLTimer explicitly with NtGetTickCount (a relatively expensive
  1666. * call) every N calls.
  1667. *
  1668. * The value N, or the number of APIs dispatched per call to NtGetTickCount,
  1669. * is variable. glsrvAttention and its display list equivalents attempt
  1670. * to adjust N so that NtGetTickCount is called approximately every
  1671. * TICK_RANGE_LO to TICK_RANGE_HI ticks.
  1672. *
  1673. * Returns:
  1674. * TRUE if entire batch is processed, FALSE otherwise.
  1675. *
  1676. * History:
  1677. * 12-Apr-1994 -by- Gilman Wong [gilmanw]
  1678. * Wrote it.
  1679. \**************************************************************************/
  1680. BOOL APIENTRY glsrvAttention(PVOID pdlo, PVOID pdco, PVOID pdxo, HANDLE hdev)
  1681. {
  1682. BOOL bRet = FALSE;
  1683. ULONG *pOffset;
  1684. SERVERPROC Proc;
  1685. GLMSGBATCHINFO *pMsgBatchInfo = GLTEB_SHAREDMEMORYSECTION();
  1686. __GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
  1687. #ifdef CHAIN_DRAWPOLYARRAY_MSG
  1688. POLYARRAY *paBegin = (POLYARRAY *) NULL;
  1689. POLYARRAY *paEnd, *pa;
  1690. GLMSG_DRAWPOLYARRAY *pMsgDrawPolyArray = NULL;
  1691. #endif
  1692. UINT old_fp;
  1693. GDISAVESTATE GdiState;
  1694. #ifdef DETECT_FPE
  1695. old_fp = _controlfp(0, 0);
  1696. _controlfp(_EM_INEXACT, _MCW_EM);
  1697. #endif
  1698. if ((gengc->gsurf.dwFlags & GLSURF_DIRECTDRAW) == 0)
  1699. {
  1700. vSaveGdiState(gengc->gsurf.hdc, &GdiState);
  1701. }
  1702. DBGENTRY("glsrvAttention\n");
  1703. DBGLEVEL1(LEVEL_INFO, "glsrvAttention: pMsgBatchInfo=0x%lx\n",
  1704. pMsgBatchInfo);
  1705. STATS_INC_SERVERTRIPS();
  1706. // Grab the lock.
  1707. if (!glsrvGrabLock(gengc))
  1708. {
  1709. //!!! mcd/dma too?
  1710. PolyArrayResetBuffer((__GLcontext *) gengc);
  1711. goto glsrvAttention_exit;
  1712. }
  1713. // Dispatch the calls in the batch.
  1714. pOffset = (ULONG *)(((BYTE *)pMsgBatchInfo) + pMsgBatchInfo->FirstOffset);
  1715. // If we don't require any locks we don't need to burden our processing
  1716. // with timer checks.
  1717. if (gengc->fsGenLocks == LOCKFLAG_WINDOW)
  1718. {
  1719. while (*pOffset)
  1720. {
  1721. ASSERTOPENGL(*pOffset <= LASTPROCOFFSET(glSrvSbProcTable),
  1722. "Bad ProcOffset: memory corruption - we are hosed!\n");
  1723. STATS_INC_SERVERCALLS();
  1724. DBGLEVEL1(LEVEL_ENTRY, "%s\n",
  1725. glSrvSbStringTable[*pOffset / sizeof(SERVERPROC *)]);
  1726. #ifdef CHAIN_DRAWPOLYARRAY_MSG
  1727. if (*pOffset == offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray))
  1728. pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *) pOffset;
  1729. #endif
  1730. // Dispatch the call. The return value is the offset of the next
  1731. // message in the batch.
  1732. Proc = (*((SERVERPROC *)( ((BYTE *)(&glSrvSbProcTable)) +
  1733. *pOffset )));
  1734. pOffset = (*Proc)((__GLcontext *) gengc, pOffset);
  1735. #ifdef CHAIN_DRAWPOLYARRAY_MSG
  1736. // If we are processing DrawPolyArray, we need to update the pointers
  1737. // that indicate the beginning and end of the POLYARRAY data for
  1738. // the current range of DrawPolyArray chain.
  1739. if (pMsgDrawPolyArray)
  1740. {
  1741. pa = (POLYARRAY *) pMsgDrawPolyArray->pa;
  1742. pMsgDrawPolyArray = NULL; // get ready for next iteration
  1743. // Skip this primitive if no rendering is needed.
  1744. if (!(pa->flags & POLYARRAY_RENDER_PRIMITIVE))
  1745. {
  1746. PolyArrayRestoreColorPointer(pa);
  1747. }
  1748. else
  1749. {
  1750. // Add to DrawPolyArray chain
  1751. pa->paNext = NULL;
  1752. if (!paBegin)
  1753. paBegin = pa;
  1754. else
  1755. paEnd->paNext = pa;
  1756. paEnd = pa;
  1757. }
  1758. // If the next message is not a DrawPolyArray, then we need to
  1759. // flush the primitive drawing.
  1760. if (*pOffset != offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray)
  1761. && paBegin)
  1762. {
  1763. // Draw all the POLYARRAY primitives between paBegin
  1764. // and paEnd
  1765. glsrvFlushDrawPolyArray((void *) paBegin);
  1766. paBegin = NULL;
  1767. }
  1768. }
  1769. #endif
  1770. }
  1771. }
  1772. else
  1773. {
  1774. while (*pOffset)
  1775. {
  1776. ASSERTOPENGL(*pOffset <= LASTPROCOFFSET(glSrvSbProcTable),
  1777. "Bad ProcOffset: memory corruption - we are hosed!\n");
  1778. STATS_INC_SERVERCALLS();
  1779. DBGLEVEL1(LEVEL_ENTRY, "%s\n",
  1780. glSrvSbStringTable[*pOffset / sizeof(SERVERPROC *)]);
  1781. #ifdef CHAIN_DRAWPOLYARRAY_MSG
  1782. if (*pOffset == offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray))
  1783. pMsgDrawPolyArray = (GLMSG_DRAWPOLYARRAY *) pOffset;
  1784. #endif
  1785. // Dispatch the call. The return value is the offset of the next
  1786. // message in the batch.
  1787. Proc = (*((SERVERPROC *)( ((BYTE *)(&glSrvSbProcTable)) +
  1788. *pOffset )));
  1789. pOffset = (*Proc)((__GLcontext *) gengc, pOffset);
  1790. #ifdef CHAIN_DRAWPOLYARRAY_MSG
  1791. // If we are processing DrawPolyArray, we need to update the pointers
  1792. // that indicate the beginning and end of the POLYARRAY data for
  1793. // the current range of DrawPolyArray chain.
  1794. if (pMsgDrawPolyArray)
  1795. {
  1796. pa = (POLYARRAY *) pMsgDrawPolyArray->pa;
  1797. pMsgDrawPolyArray = NULL; // get ready for next iteration
  1798. // Skip this primitive if no rendering is needed.
  1799. if (!(pa->flags & POLYARRAY_RENDER_PRIMITIVE))
  1800. {
  1801. PolyArrayRestoreColorPointer(pa);
  1802. }
  1803. else
  1804. {
  1805. // Add to DrawPolyArray chain
  1806. pa->paNext = NULL;
  1807. if (!paBegin)
  1808. paBegin = pa;
  1809. else
  1810. paEnd->paNext = pa;
  1811. paEnd = pa;
  1812. }
  1813. // If the next message is not a DrawPolyArray, then we need to
  1814. // flush the primitive drawing.
  1815. if (*pOffset != offsetof(GLSRVSBPROCTABLE, glsrvDrawPolyArray)
  1816. && paBegin)
  1817. {
  1818. // Draw all the POLYARRAY primitives between paBegin
  1819. // and paEnd
  1820. glsrvFlushDrawPolyArray((void *) paBegin);
  1821. paBegin = NULL;
  1822. }
  1823. }
  1824. #endif
  1825. //!!!XXX -- Better to use other loop until lock is grabbed then
  1826. //!!!XXX switch to this loop. But good enough for now to
  1827. //!!!XXX check flag in loop.
  1828. // If display lock held, we may need to periodically unlock to give
  1829. // other apps a chance.
  1830. if (gengc->fsLocks & LOCKFLAG_FRONT_BUFFER)
  1831. {
  1832. // Force a check of the current tick count every N calls.
  1833. gengc->dwCalls++;
  1834. if (gengc->dwCalls >= gengc->dwCallsPerTick)
  1835. {
  1836. gcmsOpenGLTimer = GetTickCount();
  1837. // If the tick delta is out of range, then increase or decrease
  1838. // N as appropriate. Be careful not to let it grow out of
  1839. // bounds or to shrink to zero.
  1840. if ((gcmsOpenGLTimer - gengc->dwLastTick) < TICK_RANGE_LO)
  1841. if (gengc->dwCallsPerTick < 64)
  1842. gengc->dwCallsPerTick *= 2;
  1843. else if ((gcmsOpenGLTimer - gengc->dwLastTick) > TICK_RANGE_HI)
  1844. // The + 1 is to keep it from hitting 0
  1845. gengc->dwCallsPerTick = (gengc->dwCallsPerTick + 1) / 2;
  1846. gengc->dwLastTick = gcmsOpenGLTimer;
  1847. gengc->dwCalls = 0;
  1848. }
  1849. // Check if time slice has expired. If so, relinquish the lock.
  1850. if ((gcmsOpenGLTimer - gengc->dwLockTick) > BATCH_LOCK_TICKMAX)
  1851. {
  1852. #ifdef CHAIN_DRAWPOLYARRAY_MSG
  1853. //!!! Before we release the lock, we may need to flush the
  1854. //!!! DrawPolyArray chain. For now, just flush it although
  1855. //!!! it is probably unnecessary.
  1856. if (paBegin)
  1857. {
  1858. // Draw all the POLYARRAY primitives between paBegin
  1859. // and paEnd
  1860. glsrvFlushDrawPolyArray((void *) paBegin);
  1861. paBegin = NULL;
  1862. }
  1863. #endif
  1864. // Release and regrab lock. This will allow the cursor to
  1865. // redraw as well as reset the cursor timer.
  1866. glsrvReleaseLock(gengc);
  1867. if (!glsrvGrabLock(gengc))
  1868. {
  1869. //!!! mcd/dma too?
  1870. PolyArrayResetBuffer((__GLcontext *) gengc);
  1871. goto glsrvAttention_exit;
  1872. }
  1873. }
  1874. }
  1875. }
  1876. }
  1877. // Release the lock.
  1878. glsrvReleaseLock(gengc);
  1879. // Success.
  1880. bRet = TRUE;
  1881. glsrvAttention_exit:
  1882. if ((gengc->gsurf.dwFlags & GLSURF_DIRECTDRAW) == 0)
  1883. {
  1884. vRestoreGdiState(gengc->gsurf.hdc, &GdiState);
  1885. }
  1886. #ifdef DETECT_FPE
  1887. _controlfp(old_fp, _MCW_EM);
  1888. #endif
  1889. return bRet;
  1890. }