Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1352 lines
46 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mcdutil.c
  3. *
  4. * Contains various utility routines for the Cirrus Logic 546X MCD driver such as
  5. * rendering-procedure picking functionality and buffer management.
  6. *
  7. * (based on mcdutil.c from NT4.0 DDK)
  8. *
  9. * Copyright (c) 1996 Microsoft Corporation
  10. * Copyright (c) 1997 Cirrus Logic, Inc.
  11. \**************************************************************************/
  12. #include "precomp.h"
  13. #include "mcdhw.h"
  14. #include "mcdutil.h"
  15. #include "mcdmath.h"
  16. #include "stdio.h"
  17. #ifdef B4_CIRRUS
  18. static ULONG xlatRop[16] = {bop_BLACKNESS, // GL_CLEAR 0
  19. bop_MASKPEN, // GL_AND S & D
  20. bop_MASKPENNOT, // GL_AND_REVERSE S & ~D
  21. bop_SRCCOPY, // GL_COPY S
  22. bop_MASKNOTPEN, // GL_AND_INVERTED ~S & D
  23. bop_NOP, // GL_NOOP D
  24. bop_XORPEN, // GL_XOR S ^ D
  25. bop_MERGEPEN, // GL_OR S | D
  26. bop_NOTMERGEPEN, // GL_NOR ~(S | D)
  27. bop_NOTXORPEN, // GL_EQUIV ~(S ^ D)
  28. bop_NOT, // GL_INVERT ~D
  29. bop_MERGEPENNOT, // GL_OR_REVERSE S | ~D
  30. bop_NOTCOPYPEN, // GL_COPY_INVERTED ~S
  31. bop_MERGENOTPEN, // GL_OR_INVERTED ~S | D
  32. bop_NOTMASKPEN, // GL_NAND ~(S & D)
  33. bop_WHITENESS, // GL_SET 1
  34. };
  35. #endif // B4_CIRRUS
  36. // Function prototypes:
  37. VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip);
  38. #define MCD_ALLOC_TAG 'dDCM'
  39. #if DBG
  40. ULONG MCDrvAllocMemSize = 0;
  41. UCHAR *MCDDbgAlloc(UINT size)
  42. {
  43. UCHAR *pRet;
  44. if (pRet = (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size + sizeof(ULONG),
  45. MCD_ALLOC_TAG)) {
  46. MCDrvAllocMemSize += size;
  47. *((ULONG *)pRet) = size;
  48. return (pRet + sizeof(ULONG));
  49. } else
  50. return (UCHAR *)NULL;
  51. }
  52. VOID MCDDbgFree(UCHAR *pMem)
  53. {
  54. if (!pMem) {
  55. MCDBG_PRINT("MCDFree: Attempt to free NULL pointer.");
  56. return;
  57. }
  58. pMem -= sizeof(ULONG);
  59. MCDrvAllocMemSize -= *((ULONG *)pMem);
  60. //MCDBG_PRINT("MCDFree: %x bytes in use.", MCDrvAllocMemSize);
  61. EngFreeMem((VOID *)pMem);
  62. }
  63. #else
  64. UCHAR *MCDAlloc(UINT size)
  65. {
  66. return (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size, MCD_ALLOC_TAG);
  67. }
  68. VOID MCDFree(UCHAR *pMem)
  69. {
  70. EngFreeMem((VOID *)pMem);
  71. }
  72. #endif /* DBG */
  73. VOID MCDrvDebugPrint(char *pMessage, ...)
  74. {
  75. va_list ap;
  76. va_start(ap, pMessage);
  77. EngDebugPrint("[MCD DRIVER] ", pMessage, ap);
  78. EngDebugPrint("", "\n", ap);
  79. va_end(ap);
  80. }
  81. VOID FASTCALL NullRenderPoint(DEVRC *pRc, MCDVERTEX *pv)
  82. {
  83. }
  84. VOID FASTCALL NullRenderLine(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL bReset)
  85. {
  86. }
  87. VOID FASTCALL NullRenderTri(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, MCDVERTEX *pv3)
  88. {
  89. }
  90. MCDCOMMAND * FASTCALL FailPrimDraw(DEVRC *pRc, MCDCOMMAND *pCmd)
  91. {
  92. #ifdef B4_CIRRUS
  93. HW_WAIT_DRAWING_DONE(pRc);
  94. #endif // B4_CIRRUS
  95. return pCmd;
  96. }
  97. BOOL PickPointFuncs(DEVRC *pRc)
  98. {
  99. ULONG enables = pRc->MCDState.enables;
  100. pRc->drawPoint = NULL; // assume failure
  101. if (enables & (MCD_POINT_SMOOTH_ENABLE))
  102. return FALSE;
  103. if (pRc->MCDState.pointSize != __MCDONE)
  104. return FALSE;
  105. // First, get high-level rendering functions:
  106. if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
  107. pRc->renderPoint = __MCDRenderPoint;
  108. } else {
  109. pRc->renderPoint = __MCDRenderGenPoint;
  110. }
  111. // handle any lower-level rendering if needed:
  112. pRc->drawPoint = pRc->renderPoint;
  113. return TRUE;
  114. }
  115. BOOL PickLineFuncs(DEVRC *pRc)
  116. {
  117. ULONG enables = pRc->MCDState.enables;
  118. pRc->drawLine = NULL; // assume failure
  119. if (enables & MCD_LINE_SMOOTH_ENABLE)
  120. return FALSE;
  121. if (pRc->MCDState.lineWidth > __MCDONE)
  122. return FALSE;
  123. // First, get high-level rendering functions:
  124. if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
  125. pRc->renderLine = __MCDRenderLine;
  126. } else {
  127. pRc->renderLine = __MCDRenderGenLine;
  128. }
  129. // Handle any lower-level rendering if needed:
  130. pRc->drawLine = pRc->renderLine;
  131. return TRUE;
  132. }
  133. BOOL PickTriangleFuncs(DEVRC *pRc)
  134. {
  135. ULONG enables = pRc->MCDState.enables;
  136. //MCD_NOTE: MGA checked here if should punt on stipple - 546x does that in PickRendering
  137. //MCD_NOTE: before this proc is called
  138. if (enables & (MCD_POLYGON_SMOOTH_ENABLE |
  139. MCD_COLOR_LOGIC_OP_ENABLE))
  140. return FALSE;
  141. // First, get high-level rendering functions. If we're not GL_FILL'ing
  142. // both sides of our polygons, use the "generic" function.
  143. if (((pRc->MCDState.polygonModeFront == GL_FILL) &&
  144. (pRc->MCDState.polygonModeBack == GL_FILL)) &&
  145. (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK)
  146. ) {
  147. if (pRc->MCDState.shadeModel == GL_SMOOTH)
  148. pRc->renderTri = __MCDRenderSmoothTriangle;
  149. else
  150. pRc->renderTri = __MCDRenderFlatTriangle;
  151. } else {
  152. pRc->renderTri = __MCDRenderGenTriangle;
  153. // In this case, we must handle the various fill modes. We must
  154. // fail triangle drawing if we can't handle the types of primitives
  155. // that may have to be drawn. This logic depends on the line and
  156. // point pick routines
  157. // FUTURE: Sort out 2-sided support
  158. if (((pRc->MCDState.polygonModeFront == GL_POINT) && (!pRc->drawPoint)) ||
  159. ((pRc->MCDState.polygonModeFront == GL_LINE) && (!pRc->drawLine)))
  160. return FALSE;
  161. if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
  162. if (((pRc->MCDState.polygonModeBack == GL_POINT) && (!pRc->drawPoint)) ||
  163. ((pRc->MCDState.polygonModeBack == GL_LINE) && (!pRc->drawLine)))
  164. return FALSE;
  165. }
  166. }
  167. // Handle lower-level triangle rendering:
  168. //FUTURE: add ability to configure different parameterization procs?
  169. if (pRc->privateEnables & __MCDENABLE_PERSPECTIVE)
  170. pRc->drawTri = __MCDPerspTxtTriangle;
  171. else
  172. pRc->drawTri = __MCDFillTriangle;
  173. return TRUE;
  174. }
  175. VOID __MCDPickRenderingFuncs(DEVRC *pRc, DEVWND *pDevWnd)
  176. {
  177. BOOL bSupportedZFunc = TRUE;
  178. unsigned int z_mode, z_comp_mode;
  179. unsigned int punt_all_points = FALSE;
  180. unsigned int punt_all_lines = FALSE;
  181. unsigned int punt_all_polys = FALSE;
  182. PDEV *ppdev = pRc->ppdev;
  183. DWORD *pdwNext = ppdev->LL_State.pDL->pdwNext;
  184. int control0_set=FALSE;
  185. ULONG _MCDStateenables = pRc->MCDState.enables; // copy we can modify
  186. int const_alpha_mode=FALSE;
  187. int frame_scale=FALSE;
  188. pRc->primFunc[GL_POINTS] = __MCDPrimDrawPoints;
  189. pRc->primFunc[GL_LINES] = __MCDPrimDrawLines;
  190. pRc->primFunc[GL_LINE_LOOP] = __MCDPrimDrawLineLoop;
  191. pRc->primFunc[GL_LINE_STRIP] = __MCDPrimDrawLineStrip;
  192. pRc->primFunc[GL_TRIANGLES] = __MCDPrimDrawTriangles;
  193. pRc->primFunc[GL_TRIANGLE_STRIP] = __MCDPrimDrawTriangleStrip;
  194. pRc->primFunc[GL_TRIANGLE_FAN] = __MCDPrimDrawTriangleFan;
  195. pRc->primFunc[GL_QUADS] = __MCDPrimDrawQuads;
  196. pRc->primFunc[GL_QUAD_STRIP] = __MCDPrimDrawQuadStrip;
  197. pRc->primFunc[GL_POLYGON] = __MCDPrimDrawPolygon;
  198. // normal mode for all conditions except NEVER and ALWAYS
  199. z_mode = LL_Z_MODE_NORMAL;
  200. switch (pRc->MCDState.depthTestFunc) {
  201. default:
  202. case GL_NEVER:
  203. z_mode = LL_Z_MODE_MASK;
  204. // comp mode is don't care, but set to default anyway
  205. z_comp_mode = LL_Z_WRITE_GREATER_EQUAL;
  206. break;
  207. case GL_LESS:
  208. z_comp_mode = LL_Z_WRITE_LESS;
  209. break;
  210. case GL_EQUAL:
  211. z_comp_mode = LL_Z_WRITE_EQUAL;
  212. break;
  213. case GL_LEQUAL:
  214. z_comp_mode = LL_Z_WRITE_LESS_EQUAL;
  215. break;
  216. case GL_GREATER:
  217. z_comp_mode = LL_Z_WRITE_GREATER;
  218. break;
  219. case GL_NOTEQUAL:
  220. z_comp_mode = LL_Z_WRITE_NOT_EQUAL;
  221. break;
  222. case GL_GEQUAL:
  223. z_comp_mode = LL_Z_WRITE_GREATER_EQUAL;
  224. break;
  225. case GL_ALWAYS:
  226. z_mode = LL_Z_MODE_ALWAYS;
  227. // comp mode is don't care, but set to default anyway
  228. z_comp_mode = LL_Z_WRITE_GREATER_EQUAL;
  229. break;
  230. }
  231. // Set up the privateEnables flags:
  232. pRc->privateEnables = 0;
  233. if ((pRc->MCDState.twoSided) &&
  234. (_MCDStateenables & MCD_LIGHTING_ENABLE))
  235. pRc->privateEnables |= __MCDENABLE_TWOSIDED;
  236. if (pDevWnd->bValidZBuffer &&
  237. (_MCDStateenables & MCD_DEPTH_TEST_ENABLE))
  238. {
  239. pRc->privateEnables |= __MCDENABLE_Z;
  240. if (z_mode == LL_Z_MODE_MASK)
  241. {
  242. // GL_NEVER depth test, so ignore all primitives
  243. pRc->allPrimFail = TRUE;
  244. return;
  245. }
  246. // Z enabled, so if draw to front (which is full screen and requires coords relative
  247. // to screen origin) and z is windowed (which requires coords relative to window origin),
  248. // punt
  249. if (pRc->MCDState.drawBuffer == GL_FRONT)
  250. {
  251. if (pRc->ppdev->pohZBuffer != pDevWnd->pohZBuffer)
  252. {
  253. pRc->allPrimFail = TRUE;
  254. pRc->punt_front_w_windowed_z=TRUE;
  255. return;
  256. }
  257. else
  258. {
  259. // reset global punt due to front buf draw with window-size z buffer
  260. pRc->punt_front_w_windowed_z = FALSE;
  261. }
  262. }
  263. else
  264. {
  265. if (pRc->punt_front_w_windowed_z)
  266. {
  267. // Drawing to backbuffer after drawing to front was punted.
  268. // Need to punt back draws as well since pixel-to-pixel compares
  269. // of punted front and non-punted back will fail conformance test,
  270. // since punted result and non-punted are visually equivalent, but not
  271. // always exactly identical.
  272. // FUTURE2 : how to fix need to punt when full-screen front and windowed Z:
  273. // instead of making z buffer exact size as window, make larger such
  274. // that it starts at a y=16, x=64 boundary - where x/y offsets of
  275. // the 0,0 location of the window are same as the offsets of the window
  276. // from the nearest 16/64 location on the fullscreen buffer.
  277. // See MCD notes, p 267 for details
  278. pRc->allPrimFail = TRUE;
  279. return;
  280. }
  281. }
  282. }
  283. else
  284. {
  285. // reset global punt due to front buf draw with window-size z buffer
  286. pRc->punt_front_w_windowed_z = FALSE;
  287. }
  288. if (pRc->MCDState.shadeModel == GL_SMOOTH)
  289. pRc->privateEnables |= __MCDENABLE_SMOOTH;
  290. // MCD_NOTE: if stipple and dither active at same time, may need to fail all lines/polys
  291. // MCD_NOTE: - for now, we let stipple take precedence (see code in __MCDFillTriangle, etc)
  292. if (_MCDStateenables & MCD_DITHER_ENABLE)
  293. pRc->privateEnables |= __MCDENABLE_DITHER;
  294. pRc->HWSetupClipRect = HWSetupClipping;
  295. // Even though we're set up to handle this in the primitive pick
  296. // functions, we'll exit early here since we don't actually handle
  297. // this in the primitive routines themselves:
  298. if (pRc->MCDState.drawBuffer == GL_FRONT_AND_BACK) {
  299. pRc->allPrimFail = TRUE;
  300. return;
  301. }
  302. // If we're doing any of the following...
  303. // - culling everything
  304. // - not updating any of our buffers
  305. // - zmode says never update
  306. // - alpha test says never pass
  307. //...just return for all primitives:
  308. if (((_MCDStateenables & MCD_CULL_FACE_ENABLE) &&
  309. (pRc->MCDState.cullFaceMode == GL_FRONT_AND_BACK)) ||
  310. ((pRc->MCDState.drawBuffer == GL_NONE) &&
  311. ((!pRc->MCDState.depthWritemask) || (!pDevWnd->bValidZBuffer))) ||
  312. ((pRc->privateEnables & __MCDENABLE_Z) && (z_mode == LL_Z_MODE_MASK)) ||
  313. ((_MCDStateenables & MCD_ALPHA_TEST_ENABLE) && (pRc->MCDState.alphaTestFunc == GL_NEVER))
  314. ) {
  315. pRc->renderPoint = NullRenderPoint;
  316. pRc->renderLine = NullRenderLine;
  317. pRc->renderTri = NullRenderTri;
  318. pRc->allPrimFail = FALSE;
  319. return;
  320. }
  321. // Build lookup table for face direction
  322. switch (pRc->MCDState.frontFace) {
  323. case GL_CW:
  324. pRc->polygonFace[__MCD_CW] = __MCD_BACKFACE;
  325. pRc->polygonFace[__MCD_CCW] = __MCD_FRONTFACE;
  326. break;
  327. case GL_CCW:
  328. pRc->polygonFace[__MCD_CW] = __MCD_FRONTFACE;
  329. pRc->polygonFace[__MCD_CCW] = __MCD_BACKFACE;
  330. break;
  331. }
  332. // Build lookup table for face filling modes:
  333. pRc->polygonMode[__MCD_FRONTFACE] = pRc->MCDState.polygonModeFront;
  334. pRc->polygonMode[__MCD_BACKFACE] = pRc->MCDState.polygonModeBack;
  335. if (_MCDStateenables & MCD_CULL_FACE_ENABLE)
  336. pRc->cullFlag = (pRc->MCDState.cullFaceMode == GL_FRONT ? __MCD_FRONTFACE :
  337. __MCD_BACKFACE);
  338. else
  339. pRc->cullFlag = __MCD_NOFACE;
  340. // Assume that we fail everything:
  341. pRc->allPrimFail = TRUE;
  342. // see comment in mcd.hlp on MCDVERTEX - disable fog if texture mapping or gouraud shading
  343. if (!pRc->MCDState.textureEnabled && (pRc->MCDState.shadeModel == GL_SMOOTH))
  344. {
  345. _MCDStateenables &= ~MCD_FOG_ENABLE;
  346. }
  347. if ((_MCDStateenables & MCD_FOG_ENABLE) &&
  348. ((pRc->MCDState.fogMode != GL_LINEAR) || (pRc->MCDState.fogHint == GL_NICEST)))
  349. {
  350. // 546x only does linear fog, so punt otherwise
  351. // QST2 - if linear fog mode, do we have to punt if foghint GL_NICEST?
  352. MCDFREE_PRINT("__MCDPick...non linear fog - punt");
  353. return;
  354. }
  355. if (_MCDStateenables & (MCD_COLOR_LOGIC_OP_ENABLE |
  356. MCD_INDEX_LOGIC_OP_ENABLE |
  357. MCD_SCISSOR_TEST_ENABLE |
  358. MCD_STENCIL_TEST_ENABLE))
  359. {
  360. MCDFREE_PRINT(".. will punt...logic ops or stencil ");
  361. return;
  362. }
  363. if (_MCDStateenables & (MCD_ALPHA_TEST_ENABLE))
  364. {
  365. if (pRc->MCDState.alphaTestFunc == GL_ALWAYS)
  366. {
  367. // if GL_ALWAYS, it's the same as no alpha test, so turn it off
  368. _MCDStateenables &= ~MCD_ALPHA_TEST_ENABLE;
  369. }
  370. else
  371. {
  372. if ((pRc->MCDState.alphaTestFunc == GL_GREATER) &&
  373. pRc->MCDState.textureEnabled)
  374. {
  375. // only have alpha test support when textured - and even then it's limited
  376. // store ref scaled by 8 bits for compare to 8 bit alpha in BGRA textures
  377. pRc->bAlphaTestRef = (BYTE)(pRc->MCDState.alphaTestRef * (float)255.0);
  378. pRc->privateEnables |= __MCDENABLE_TEXTUREMASKING;
  379. }
  380. else
  381. {
  382. MCDFREE_PRINT("AlphaTest, but not ALWAYS,NEVER, or GREATER (or not textured) - punt");
  383. return;
  384. }
  385. }
  386. }
  387. // if both blend and fog active, punt all since only one set of interpolators on 546x
  388. if ( (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE)) ==
  389. (MCD_BLEND_ENABLE|MCD_FOG_ENABLE))
  390. {
  391. MCDFREE_PRINT(".. will punt...fog and blend ");
  392. return;
  393. }
  394. if (_MCDStateenables & MCD_BLEND_ENABLE)
  395. {
  396. MCDFREE_PRINT("BLENDS: Src=%x Dst=%x",pRc->MCDState.blendSrc,pRc->MCDState.blendDst);
  397. if ((pRc->MCDState.blendSrc == GL_ONE) &&
  398. (pRc->MCDState.blendDst == GL_ZERO))
  399. {
  400. // equivalent to no blending, so shut it off
  401. _MCDStateenables &= ~MCD_BLEND_ENABLE;
  402. }
  403. else if ((pRc->MCDState.blendSrc == GL_ZERO) &&
  404. (pRc->MCDState.blendDst == GL_ONE_MINUS_SRC_COLOR))
  405. {
  406. // one of GLQuake's favorite modes - requires HW's "Frame Scaling" function
  407. frame_scale=TRUE;
  408. }
  409. else if ((pRc->MCDState.blendSrc == GL_ONE) &&
  410. (pRc->MCDState.blendDst == GL_ONE))
  411. {
  412. // one of GLQuake's favorite modes - will use CONST blend (set later in this proc)
  413. const_alpha_mode=TRUE;
  414. // lines and points don't yet support CONST blend - a simple matter of
  415. // programming to make points and lines work like polys in this regard
  416. punt_all_points=TRUE;
  417. punt_all_lines=TRUE;
  418. }
  419. else if ((pRc->MCDState.blendSrc != GL_SRC_ALPHA) ||
  420. (pRc->MCDState.blendDst != GL_ONE_MINUS_SRC_ALPHA))
  421. {
  422. // unsupported mode
  423. MCDFREE_PRINT("unsupported blendSrc/blendDest");
  424. return;
  425. }
  426. }
  427. // FUTURE2: now punting if colorWriteMask not 1,1,1,X - should implement w/ color compare func
  428. if (!(pRc->MCDState.colorWritemask[0] &&
  429. pRc->MCDState.colorWritemask[1] &&
  430. pRc->MCDState.colorWritemask[2]))
  431. {
  432. MCDFREE_PRINT(".. will punt...write mask ");
  433. return;
  434. }
  435. // WARNING ........
  436. // WARNING ........
  437. // WARNING ........
  438. // Code below MAY set state in shadow regs, so be careful about early return early to punt
  439. // FROM THIS POINT ON...
  440. if (pRc->MCDState.textureEnabled)
  441. {
  442. // parameterization code for lines/points not done yet
  443. punt_all_points=TRUE;
  444. punt_all_lines=TRUE;
  445. MCDFREE_PRINT("__MCDPick...textures, envmode=%x ",pRc->MCDTexEnvState.texEnvMode);
  446. // punt if blending and alphatest both enabled - framescale part of blending,
  447. // so this covers punt needed for alphatest and framescaling
  448. if ((_MCDStateenables & (MCD_BLEND_ENABLE|MCD_ALPHA_TEST_ENABLE)) ==
  449. (MCD_BLEND_ENABLE|MCD_ALPHA_TEST_ENABLE))
  450. {
  451. MCDFREE_PRINT("__MCDPick...textures, punt since blend & alphatest");
  452. return;
  453. }
  454. if (pRc->MCDState.perspectiveCorrectionHint!=GL_FASTEST)
  455. pRc->privateEnables |= (__MCDENABLE_TEXTURE|__MCDENABLE_PERSPECTIVE);
  456. else
  457. pRc->privateEnables |= __MCDENABLE_TEXTURE;
  458. // if both 1d and 2d bits same state, 2d is done (or if only 2d bit is on)
  459. if ((_MCDStateenables & (MCD_TEXTURE_1D_ENABLE|MCD_TEXTURE_2D_ENABLE)) == MCD_TEXTURE_1D_ENABLE)
  460. {
  461. pRc->privateEnables |= __MCDENABLE_1D_TEXTURE;
  462. }
  463. if (pRc->MCDTexEnvState.texEnvMode == GL_BLEND)
  464. {
  465. // MCD_NOTE2: the following works only for GL_LUMINANCE, GL_LUMINANCE_ALPHA, and
  466. // GL_INTENSITY textures. GL_RGB and GL_RGBA textures will punt (later).
  467. // if normal blending or fog on and texture blend environment, then must punt since
  468. // this requires 2 sets of alpha equations and hw only has 1
  469. if (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE|MCD_ALPHA_TEST_ENABLE))
  470. {
  471. MCDFREE_PRINT("__MCDPick...textures, GL_BLEND and fog|blend|alphatest");
  472. return;
  473. }
  474. // set alpha mode and dest color regs for GL_BLEND texture environment
  475. if( pRc->Control0.Alpha_Mode != LL_ALPHA_TEXTURE )
  476. {
  477. pRc->Control0.Alpha_Mode = LL_ALPHA_TEXTURE;
  478. control0_set=TRUE;
  479. }
  480. if( pRc->Control0.Alpha_Dest_Color_Sel != LL_ALPHA_DEST_CONST )
  481. {
  482. pRc->Control0.Alpha_Dest_Color_Sel = LL_ALPHA_DEST_CONST;
  483. control0_set=TRUE;
  484. }
  485. // load texture env color into color0 register
  486. pRc->dwColor0 = (FTOL(pRc->MCDTexEnvState.texEnvColor.r * pRc->rScale) & 0xff0000);
  487. pRc->dwColor0 |= (FTOL(pRc->MCDTexEnvState.texEnvColor.g * pRc->gScale) & 0xff0000) >> 8;
  488. pRc->dwColor0 |= (FTOL(pRc->MCDTexEnvState.texEnvColor.b * pRc->bScale) & 0xff0000) >> 16;
  489. *pdwNext++ = write_register( COLOR0_3D, 1 );
  490. *pdwNext++ = pRc->dwColor0;
  491. if (!pRc->Control0.Alpha_Blending_Enable)
  492. {
  493. pRc->Control0.Alpha_Blending_Enable = TRUE;
  494. control0_set=TRUE;
  495. }
  496. }
  497. else if (pRc->MCDTexEnvState.texEnvMode == GL_MODULATE)
  498. {
  499. if (frame_scale)
  500. {
  501. MCDFREE_PRINT("__MCDPick...textures, GL_MODULATE and framescaling");
  502. return;
  503. }
  504. pRc->privateEnables |= __MCDENABLE_LIGHTING;
  505. if( pRc->Control0.Light_Src_Sel != LL_LIGHTING_INTERP_RGB )
  506. {
  507. pRc->Control0.Light_Src_Sel = LL_LIGHTING_INTERP_RGB;
  508. control0_set=TRUE;
  509. }
  510. }
  511. // if texEnvMod not blend or modulate, it's either replace or decal - some settings
  512. // req'd at runtime, but not here
  513. // set so that first primitive will force setup of texture control regs
  514. pRc->pLastTexture = TEXTURE_NOT_LOADED;
  515. }
  516. else
  517. {
  518. // if texture not enabled, make sure texture mask disabled
  519. // this is a bug in 5464 and 5465 hardware
  520. // Texture enable/disable done only by state change (outside of DrvDraw)
  521. // so we don't have to check this per primitive
  522. if (_MCDStateenables & MCD_ALPHA_TEST_ENABLE)
  523. {
  524. pRc->privateEnables &= ~__MCDENABLE_TEXTUREMASKING;
  525. #ifdef STRICT_CONFORMANCE
  526. MCDFREE_PRINT("__MCDPick...alphatest but not textured - punt");
  527. return;
  528. #else
  529. MCDFREE_PRINT("__MCDPick...alphatest but not textured - SHOULD PUNT, BUT WON'T");
  530. #endif
  531. }
  532. if (frame_scale)
  533. {
  534. MCDFREE_PRINT("__MCDPick...framescale but not textured - punt");
  535. return;
  536. }
  537. if (pRc->dwTxControl0 & TEX_MASK_EN)
  538. {
  539. pRc->dwTxControl0 &= ~TEX_MASK_EN;
  540. *pdwNext++ = write_register( TX_CTL0_3D, 1 );
  541. *pdwNext++ = pRc->dwTxControl0;
  542. }
  543. }
  544. if (_MCDStateenables & MCD_LINE_STIPPLE_ENABLE)
  545. {
  546. if ( (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE)) ||
  547. (pRc->MCDState.lineStippleRepeat > 2) )
  548. {
  549. // if stipple active and alpha (via blend or fog), punt all lines
  550. // since 5464 has very limited support for this
  551. // also punt if factor > 2, since pattern is > 32 bits in such cases
  552. // NOTE that even though stipple and blend won't work as desired, dither and blend
  553. // should. DanW says 5464 has bug so this doesn't look too hot but this should
  554. // be fixed in 5465 and following.
  555. punt_all_lines = TRUE;
  556. }
  557. else
  558. {
  559. DWORD linestipple;
  560. if (pRc->MCDState.lineStippleRepeat == 1)
  561. {
  562. // repeat 16bit stipple twice,
  563. linestipple = (pRc->MCDState.lineStipplePattern<<16) | pRc->MCDState.lineStipplePattern;
  564. }
  565. else
  566. {
  567. // double each bit, so 16 bit original becomes 32 bit
  568. int i;
  569. linestipple = 0;
  570. for (i=0; i<16; i++)
  571. {
  572. linestipple |= (((pRc->MCDState.lineStipplePattern>>i) & 1) * 3) << (i*2);
  573. }
  574. }
  575. pRc->line_style.pat[0] = linestipple;
  576. pRc->privateEnables |= __MCDENABLE_LINE_STIPPLE;
  577. }
  578. pRc->ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
  579. }
  580. if (_MCDStateenables & MCD_POLYGON_STIPPLE_ENABLE)
  581. {
  582. if (_MCDStateenables & (MCD_BLEND_ENABLE|MCD_FOG_ENABLE))
  583. {
  584. // if stipple active and alpha (via blend or fog), punt all polygons
  585. // since 5464 has very limited support for this
  586. punt_all_polys = TRUE;
  587. }
  588. else
  589. {
  590. BYTE *pStipple = pRc->MCDState.polygonStipple;
  591. int i,j;
  592. for (i=0; i<64; ) {
  593. // 546x stipple is 16x16, OpenGL's is 32x32, so unless 32x32 pattern
  594. // is really a 16x16 pattern repeated 4 times, we have to punt.
  595. // for 32 bit row of OpenGL pattern, check if byte0=byte2 and byte1=byte3
  596. if (pStipple[i] != pStipple[i+2]) break;
  597. if (pStipple[i+1] != pStipple[i+3]) break;
  598. // now check if 4 bytes of 32bit row match 4bytes 32 bit row 16 rows down
  599. if (pStipple[i] != pStipple[i+(16*4)]) break;
  600. if (pStipple[i+1] != pStipple[i+(16*4)+1]) break;
  601. if (pStipple[i+2] != pStipple[i+(16*4)+2]) break;
  602. if (pStipple[i+3] != pStipple[i+(16*4)+3]) break;
  603. i+=4;
  604. }
  605. // if we broke out before all 32 rows processed, HW can't support the pattern
  606. if (i<64)
  607. {
  608. punt_all_polys=TRUE;
  609. }
  610. else
  611. {
  612. // pattern is OK - convert to format 546x needs
  613. unsigned int *pat = (unsigned int *)pRc->fill_pattern.pat;
  614. // Recall that we already verified that 32x32 pattern is really 4 identical
  615. // 16x16 blocks. So take the upper left block and convert to 546x 16x16 pattern
  616. // NOTE that pattern is loaded such that first byte is lower left
  617. // therefore, we start at top of 16x16 section and work down
  618. i=0;
  619. j=124;
  620. #define MIRROR_2(val) (( ((val)&0x1)<<1) | ((val)>>1))
  621. #define MIRROR_4(val) ((MIRROR_2((val)&0x3)<<2) | MIRROR_2((val)>>2))
  622. #define MIRROR_8(val) ((MIRROR_4((val)&0xf)<<4) | MIRROR_4((val)>>4))
  623. while (i < 8)
  624. {
  625. // row N, in lower half of word
  626. // compute mirror image of row, so 0th bit is LSB instead of MSB
  627. // therefore we put upper byte in lower and vice versa, and mirror those bytes
  628. pat[i] = (MIRROR_8(pStipple[j+1])<<8) | (MIRROR_8(pStipple[j]));
  629. j-=4;
  630. // row N+1, in upper half of word
  631. // compute mirror image of row, so 0th bit is LSB instead of MSB
  632. // therefore we put upper byte in lower and vice versa, and mirror those bytes
  633. pat[i] |= (MIRROR_8(pStipple[j+1])<<24) | (MIRROR_8(pStipple[j])<<16);
  634. j-=4;
  635. i++;
  636. }
  637. }
  638. pRc->privateEnables |= __MCDENABLE_PG_STIPPLE;
  639. }
  640. pRc->ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
  641. }
  642. if ((z_comp_mode != pRc->Control0.Z_Compare_Mode) ||
  643. (z_mode != pRc->Control0.Z_Mode))
  644. {
  645. pRc->Control0.Z_Compare_Mode = z_comp_mode;
  646. pRc->Control0.Z_Mode = z_mode;
  647. control0_set=TRUE;
  648. }
  649. if (_MCDStateenables & MCD_BLEND_ENABLE)
  650. {
  651. // recall alpha mode only meaningful when alpha opcode bit set for primitive being rendered
  652. if (frame_scale)
  653. {
  654. // "frame scale" type of blend - select light source, and don't enable normal blend
  655. if( pRc->Control0.Light_Src_Sel != LL_LIGHTING_TEXTURE )
  656. {
  657. pRc->Control0.Light_Src_Sel = LL_LIGHTING_TEXTURE;
  658. control0_set=TRUE;
  659. }
  660. }
  661. else
  662. {
  663. pRc->privateEnables |= __MCDENABLE_BLEND;
  664. }
  665. if( pRc->Control0.Alpha_Dest_Color_Sel != LL_ALPHA_DEST_FRAME )
  666. {
  667. pRc->Control0.Alpha_Dest_Color_Sel = LL_ALPHA_DEST_FRAME;
  668. control0_set=TRUE;
  669. }
  670. }
  671. else
  672. {
  673. // for fog dest_color is const and alpha values are coord's "fog" value
  674. if (_MCDStateenables & MCD_FOG_ENABLE)
  675. {
  676. // FUTURE: determine when to punt on fog
  677. pRc->privateEnables |= __MCDENABLE_FOG;
  678. if( pRc->Control0.Alpha_Dest_Color_Sel != LL_ALPHA_DEST_CONST )
  679. {
  680. pRc->Control0.Alpha_Dest_Color_Sel = LL_ALPHA_DEST_CONST;
  681. control0_set=TRUE;
  682. }
  683. // load fog color into color0 register
  684. // QST - is fog density applied to fog color, or to fog values(start,end,etc.)?
  685. pRc->dwColor0 = (FTOL(pRc->MCDState.fogColor.r * pRc->rScale) & 0xff0000);
  686. pRc->dwColor0 |= (FTOL(pRc->MCDState.fogColor.g * pRc->gScale) & 0xff0000) >> 8;
  687. pRc->dwColor0 |= (FTOL(pRc->MCDState.fogColor.b * pRc->bScale) & 0xff0000) >> 16;
  688. *pdwNext++ = write_register( COLOR0_3D, 1 );
  689. *pdwNext++ = pRc->dwColor0;
  690. }
  691. }
  692. if (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG))
  693. {
  694. // texture blend may change alpha_mode and alpha_dest_color
  695. // Note that we will punt before this point if texture blend with normal (blend|fog)
  696. // since HW can't do both - if we make it here, we just need normal blend|fog
  697. if (!const_alpha_mode)
  698. {
  699. if( pRc->Control0.Alpha_Mode != LL_ALPHA_INTERP )
  700. {
  701. pRc->Control0.Alpha_Mode = LL_ALPHA_INTERP;
  702. control0_set=TRUE;
  703. }
  704. }
  705. else
  706. {
  707. if( pRc->Control0.Alpha_Mode != LL_ALPHA_CONST )
  708. {
  709. pRc->Control0.Alpha_Mode = LL_ALPHA_CONST;
  710. control0_set=TRUE;
  711. // always SRC=DST=1.0
  712. *pdwNext++ = write_register( DA_MAIN_3D, 2 );
  713. *pdwNext++ = 0xff0000;
  714. *pdwNext++ = 0xff0000;
  715. }
  716. }
  717. }
  718. if ( (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG)) ||
  719. ((pRc->privateEnables & __MCDENABLE_TEXTURE) &&
  720. (pRc->MCDTexEnvState.texEnvMode == GL_BLEND)) )
  721. {
  722. if (!pRc->Control0.Alpha_Blending_Enable)
  723. {
  724. pRc->Control0.Alpha_Blending_Enable = TRUE;
  725. control0_set=TRUE;
  726. }
  727. }
  728. else
  729. {
  730. // alpha blend not used, so turn off if currently on
  731. if (pRc->Control0.Alpha_Blending_Enable)
  732. {
  733. pRc->Control0.Alpha_Blending_Enable = FALSE;
  734. control0_set=TRUE;
  735. }
  736. }
  737. if (frame_scale)
  738. {
  739. if(!pRc->Control0.Frame_Scaling_Enable )
  740. {
  741. pRc->Control0.Frame_Scaling_Enable = TRUE;
  742. control0_set=TRUE;
  743. }
  744. }
  745. else
  746. {
  747. if( pRc->Control0.Frame_Scaling_Enable )
  748. {
  749. pRc->Control0.Frame_Scaling_Enable = FALSE;
  750. control0_set=TRUE;
  751. }
  752. }
  753. // setup for alpha test here...
  754. // setup for alpha test here...
  755. // setup for alpha test here...
  756. // setup for alpha test here...
  757. // setup for alpha test here...
  758. // setup for alpha test here...
  759. // setup polygon opcode
  760. pRc->dwPolyOpcode = POLY | 6 | WARP_MODE;
  761. if (pRc->privateEnables & __MCDENABLE_PG_STIPPLE)
  762. {
  763. pRc->dwPolyOpcode |= pRc->privateEnables &
  764. (__MCDENABLE_SMOOTH | __MCDENABLE_Z |
  765. __MCDENABLE_TEXTURE | __MCDENABLE_PERSPECTIVE |
  766. __MCDENABLE_LIGHTING |
  767. __MCDENABLE_PG_STIPPLE);
  768. }
  769. else
  770. {
  771. // can dither only if no stipple
  772. pRc->dwPolyOpcode |= pRc->privateEnables &
  773. (__MCDENABLE_SMOOTH | __MCDENABLE_Z |
  774. __MCDENABLE_TEXTURE | __MCDENABLE_PERSPECTIVE |
  775. __MCDENABLE_LIGHTING |
  776. __MCDENABLE_DITHER);
  777. }
  778. // setup length and other flags in Opcode
  779. pRc->dwPolyOpcode += 3; // rgb
  780. // assume not flat bottom, will decrease if flat bottom at run time
  781. pRc->dwPolyOpcode += 2;
  782. if (pRc->privateEnables & __MCDENABLE_SMOOTH)
  783. pRc->dwPolyOpcode += 6; // for rgb, main and ortho slopes - so 6 values
  784. if( pRc->privateEnables & __MCDENABLE_Z)
  785. pRc->dwPolyOpcode += 3;
  786. // assume linear, will increase if perspective at run time
  787. if (pRc->privateEnables & __MCDENABLE_TEXTURE)
  788. pRc->dwPolyOpcode += 6;
  789. // MCD_QST2 -> do we need FETCH_COLOR for Fog?
  790. if (pRc->privateEnables & (__MCDENABLE_BLEND|__MCDENABLE_FOG))
  791. {
  792. if (!const_alpha_mode)
  793. {
  794. pRc->dwPolyOpcode += ( FETCH_COLOR | ALPHA + 3 );
  795. }
  796. else
  797. {
  798. pRc->dwPolyOpcode += ( FETCH_COLOR );
  799. }
  800. }
  801. // frame scaling - must fetch frame color
  802. if (frame_scale) pRc->dwPolyOpcode += ( FETCH_COLOR );
  803. // setup line opcode
  804. pRc->dwLineOpcode = LINE | 5;
  805. pRc->dwLineOpcode |= pRc->privateEnables & (__MCDENABLE_SMOOTH|__MCDENABLE_Z);
  806. if (pRc->privateEnables & __MCDENABLE_LINE_STIPPLE)
  807. {
  808. pRc->dwLineOpcode |= LL_STIPPLE;
  809. }
  810. else
  811. {
  812. // can dither only if no stipple
  813. pRc->dwLineOpcode |= (pRc->privateEnables & __MCDENABLE_DITHER) ;
  814. }
  815. // setup point opcode
  816. pRc->dwPointOpcode= POINT | 2;
  817. pRc->dwPointOpcode |= pRc->privateEnables & (__MCDENABLE_Z|__MCDENABLE_DITHER) ;
  818. if (control0_set)
  819. {
  820. *pdwNext++ = write_register( CONTROL0_3D, 1 );
  821. *pdwNext++ = pRc->dwControl0;
  822. }
  823. pRc->allPrimFail = FALSE;
  824. if (punt_all_points || !PickPointFuncs(pRc)) {
  825. pRc->primFunc[GL_POINTS] = FailPrimDraw;
  826. }
  827. if (punt_all_lines || !PickLineFuncs(pRc)) {
  828. pRc->primFunc[GL_LINES] = FailPrimDraw;
  829. pRc->primFunc[GL_LINE_LOOP] = FailPrimDraw;
  830. pRc->primFunc[GL_LINE_STRIP] = FailPrimDraw;
  831. }
  832. if (punt_all_polys || !PickTriangleFuncs(pRc)) {
  833. pRc->primFunc[GL_TRIANGLES] = FailPrimDraw;
  834. pRc->primFunc[GL_TRIANGLE_STRIP] = FailPrimDraw;
  835. pRc->primFunc[GL_TRIANGLE_FAN] = FailPrimDraw;
  836. pRc->primFunc[GL_QUADS] = FailPrimDraw;
  837. pRc->primFunc[GL_QUAD_STRIP] = FailPrimDraw;
  838. pRc->primFunc[GL_POLYGON] = FailPrimDraw;
  839. }
  840. // don't send setup info, keep it queued and primitive rendering procs will send
  841. ppdev->LL_State.pDL->pdwNext=pdwNext;
  842. }
  843. ////////////////////////////////////////////////////////////////////////
  844. // Hardware-specific utility functions:
  845. ////////////////////////////////////////////////////////////////////////
  846. VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip)
  847. {
  848. PDEV *ppdev = pRc->ppdev;
  849. DWORD *pdwNext = ppdev->LL_State.pDL->pdwNext;
  850. SET_HW_CLIP_REGS(pRc,pdwNext)
  851. ppdev->LL_State.pDL->pdwNext = pdwNext;
  852. }
  853. VOID HWUpdateBufferPos(MCDWINDOW *pMCDWnd, SURFOBJ *pso, BOOL bForce)
  854. {
  855. }
  856. BOOL HWAllocResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso,
  857. BOOL zBufferEnabled,
  858. BOOL backBufferEnabled)
  859. {
  860. DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
  861. PDEV *ppdev = (PDEV *)pso->dhpdev;
  862. ULONG w, width, height;
  863. BOOL needFullZBuffer, needFullBackBuffer, tryFullSc;
  864. BOOL bFullScreen = FALSE;
  865. POFMHDL pohBackBuffer = NULL;
  866. POFMHDL pohZBuffer = NULL;
  867. SIZEL rctsize;
  868. ULONG alignflag;
  869. MCDBG_PRINT("HWAllocResources");
  870. width = min(pMCDWnd->clientRect.right - pMCDWnd->clientRect.left,
  871. (LONG)ppdev->cxScreen);
  872. height = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top,
  873. (LONG)ppdev->cyScreen);
  874. // Assume failure:
  875. pDevWnd->allocatedBufferHeight = 0;
  876. pDevWnd->bValidBackBuffer = FALSE;
  877. pDevWnd->bValidZBuffer = FALSE;
  878. pDevWnd->pohBackBuffer = NULL;
  879. pDevWnd->pohZBuffer = NULL;
  880. if ((backBufferEnabled) && (!ppdev->cDoubleBufferRef))
  881. needFullBackBuffer = TRUE;
  882. else
  883. needFullBackBuffer = FALSE;
  884. if ((zBufferEnabled) && (!ppdev->cZBufferRef))
  885. needFullZBuffer = TRUE;
  886. else
  887. needFullZBuffer = FALSE;
  888. tryFullSc = TRUE; // assume we'll try full screen if needed
  889. // If very little memory would be left after full screen back and z buffer allocations,
  890. // any textures would likely be punted - so just allocate per window
  891. if (needFullBackBuffer || needFullZBuffer)
  892. {
  893. // total for fullscreen buffers for front, back, z
  894. LONG bytes_needed = 3 * ppdev->cyScreen * ppdev->lDeltaScreen;
  895. // add space for 128 scan lines of texture memory
  896. bytes_needed += 128 * ppdev->lDeltaScreen;
  897. if (bytes_needed > ppdev->lTotalMem)
  898. {
  899. MCDBG_PRINT("HWAllocResources: FullSc alloc won't leave 128 scans for texture, will try window size alloc");
  900. tryFullSc = FALSE;
  901. }
  902. }
  903. // NOTE: No need to remove all discardable bitmaps at this point,
  904. // AllocOffScnMem will call OFS_DiscardMem as required if more mem reqd
  905. // If we need a back buffer, first try to allocate a fullscreen one:
  906. if (needFullBackBuffer && tryFullSc) {
  907. // Allocate the active video buffer space from the off screen memory
  908. rctsize.cx = ppdev->cxScreen;
  909. rctsize.cy = ppdev->cyScreen;
  910. alignflag = MCD_NO_X_OFFSET; // force block to start at x=0;
  911. alignflag |= MCD_DRAW_BUFFER_ALLOCATE; // force 32 scanline boundary
  912. pohBackBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
  913. if (pohBackBuffer) {
  914. ppdev->pohBackBuffer = pohBackBuffer;
  915. ppdev->cDoubleBufferRef = 0;
  916. } else {
  917. ppdev->pohBackBuffer = NULL;
  918. }
  919. }
  920. // If we need a z buffer, first try to allocate a fullscreen z:
  921. if (needFullZBuffer && tryFullSc) {
  922. // Allocate the active video buffer space from the off screen memory
  923. rctsize.cx = ppdev->cxScreen;
  924. rctsize.cy = ppdev->cyScreen;
  925. alignflag = MCD_NO_X_OFFSET; // force block to start at x=0;
  926. alignflag |= MCD_Z_BUFFER_ALLOCATE; // force 16 bpp allocate for Z on 32 scanline boundary
  927. pohZBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
  928. if (pohZBuffer) {
  929. ppdev->pohZBuffer = pohZBuffer;
  930. ppdev->cZBufferRef = 0;
  931. } else {
  932. ppdev->pohZBuffer = NULL;
  933. //needFullBackBuffer = FALSE;
  934. }
  935. }
  936. // Check if one of our full-screen allocations failed
  937. if ( (needFullZBuffer && !pohZBuffer) || // fullscreen z tried and failed OR
  938. (needFullBackBuffer && !pohBackBuffer) ) // fullscreen back tried and failed
  939. {
  940. // Free any resources allocated so far:
  941. // Note that even if full screen back allocated OK, and room for windowed Z, we
  942. // still want to free the back and have both windowed. This is so that
  943. // offset for both can be relative to window, not relative to screen.
  944. // If windowed back and Z, and drawing done to front (which by definition is full-screen),
  945. // we'll have to punt since can't do screen relative for visual (front) and window relative
  946. // for z. Hardware has capability for unique y offsets per buffer, but only on 32
  947. // scan line boundary. We could adjust buffers, etc. to make this work, but it is believed
  948. // that drawing to front with windowed z is rare. In such a case, the back buffer likely
  949. // won't exist, so fullscreen alloc for Z should usually have plenty of room.
  950. if (pohZBuffer) {
  951. ppdev->pFreeOffScnMem(ppdev, pohZBuffer);
  952. ppdev->pohZBuffer = NULL;
  953. ppdev->cZBufferRef = 0;
  954. }
  955. if (pohBackBuffer) {
  956. ppdev->pFreeOffScnMem(ppdev, pohBackBuffer);
  957. ppdev->pohBackBuffer = NULL;
  958. ppdev->cDoubleBufferRef = 0;
  959. }
  960. // Now, try to allocate per-window resources:
  961. if (backBufferEnabled) {
  962. // MCD_NOTE - should try to use window width here?
  963. rctsize.cx = width;
  964. rctsize.cy = height;
  965. // don't force block to start at x=0, will increase chance of success
  966. alignflag = MCD_DRAW_BUFFER_ALLOCATE; // force 32 scanline boundary
  967. pohBackBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
  968. if (!pohBackBuffer) {
  969. return FALSE;
  970. }
  971. }
  972. if (zBufferEnabled) {
  973. rctsize.cx = width;
  974. rctsize.cy = height;
  975. alignflag = MCD_NO_X_OFFSET; // force block to start at x=0; z buffer can't have x offset
  976. alignflag |= MCD_Z_BUFFER_ALLOCATE; // force 16 bpp allocate for Z
  977. pohZBuffer = ppdev->pAllocOffScnMem(ppdev, &rctsize, alignflag, NULL);
  978. if (!pohZBuffer) {
  979. if (pohBackBuffer)
  980. ppdev->pFreeOffScnMem(ppdev, pohBackBuffer);
  981. return FALSE;
  982. }
  983. }
  984. #if DBG
  985. if (zBufferEnabled)
  986. MCDBG_PRINT("HWAllocResources: Allocated window-sized z buffer");
  987. if (backBufferEnabled)
  988. MCDBG_PRINT("HWAllocResources: Allocated window-sized back buffer");
  989. #endif
  990. }
  991. else
  992. {
  993. // Our full-screen allocations worked, or the resources existed
  994. // already:
  995. bFullScreen = TRUE;
  996. #if DBG
  997. if (zBufferEnabled && !ppdev->cZBufferRef)
  998. MCDBG_PRINT("HWAllocResources: Allocated full-screen z buffer");
  999. if (backBufferEnabled && !ppdev->cDoubleBufferRef)
  1000. MCDBG_PRINT("HWAllocResources: Allocated full-screen back buffer");
  1001. #endif
  1002. if (zBufferEnabled) {
  1003. pohZBuffer = ppdev->pohZBuffer;
  1004. ppdev->cZBufferRef++;
  1005. }
  1006. if (backBufferEnabled) {
  1007. pohBackBuffer = ppdev->pohBackBuffer;
  1008. ppdev->cDoubleBufferRef++;
  1009. }
  1010. }
  1011. pDevWnd->pohBackBuffer = pohBackBuffer;
  1012. pDevWnd->pohZBuffer = pohZBuffer;
  1013. pDevWnd->frontBufferPitch = ppdev->lDeltaScreen;
  1014. // Calculate back buffer variables:
  1015. if (backBufferEnabled) {
  1016. ULONG y;
  1017. ULONG offset;
  1018. // Set up base position, etc.
  1019. pDevWnd->backBufferY = pDevWnd->backBufferBaseY = pohBackBuffer->aligned_y;
  1020. pDevWnd->backBufferOffset = pDevWnd->backBufferBase =
  1021. (pohBackBuffer->aligned_y * ppdev->lDeltaScreen) + pohBackBuffer->aligned_x;
  1022. pDevWnd->backBufferPitch = ppdev->lDeltaScreen;
  1023. pDevWnd->bValidBackBuffer = TRUE;
  1024. }
  1025. if (zBufferEnabled) {
  1026. ASSERTDD(pohZBuffer->aligned_x == 0,
  1027. "Z buffer should be 0-aligned");
  1028. pDevWnd->zBufferBaseY = pohZBuffer->aligned_y;
  1029. pDevWnd->zBufferBase = pohZBuffer->aligned_y * ppdev->lDeltaScreen;
  1030. pDevWnd->zBufferOffset = pDevWnd->zBufferBase;
  1031. // QST: Possible problem - if 8 bit frame and 16 bit Z, frame pitch may be less
  1032. // QST: than needed to accomodate 16 bit z???
  1033. pDevWnd->zPitch = ppdev->lDeltaScreen;
  1034. pDevWnd->bValidZBuffer = TRUE;
  1035. }
  1036. if (bFullScreen)
  1037. {
  1038. pDevWnd->allocatedBufferWidth = ppdev->cxScreen;
  1039. pDevWnd->allocatedBufferHeight = ppdev->cyScreen;
  1040. }
  1041. else
  1042. {
  1043. pDevWnd->allocatedBufferWidth = width;
  1044. pDevWnd->allocatedBufferHeight = height;
  1045. }
  1046. MCDBG_PRINT("HWAllocResources OK");
  1047. return TRUE;
  1048. }
  1049. VOID HWFreeResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso)
  1050. {
  1051. DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
  1052. PDEV *ppdev = (PDEV *)pso->dhpdev;
  1053. if (pDevWnd->pohZBuffer) {
  1054. if (ppdev->cZBufferRef) {
  1055. if (!--ppdev->cZBufferRef) {
  1056. MCDBG_PRINT("MCDrvTrackWindow: Free global z buffer");
  1057. ppdev->pFreeOffScnMem(ppdev, ppdev->pohZBuffer);
  1058. ppdev->pohZBuffer = NULL;
  1059. }
  1060. } else {
  1061. MCDBG_PRINT("MCDrvTrackWindow: Free local z buffer");
  1062. ppdev->pFreeOffScnMem(ppdev, pDevWnd->pohZBuffer);
  1063. }
  1064. }
  1065. if (pDevWnd->pohBackBuffer) {
  1066. if (ppdev->cDoubleBufferRef) {
  1067. if (!--ppdev->cDoubleBufferRef) {
  1068. MCDBG_PRINT("MCDrvTrackWindow: Free global color buffer");
  1069. ppdev->pFreeOffScnMem(ppdev, ppdev->pohBackBuffer);
  1070. ppdev->pohBackBuffer = NULL;
  1071. }
  1072. } else {
  1073. MCDBG_PRINT("MCDrvTrackWindow: Free local color buffer");
  1074. ppdev->pFreeOffScnMem(ppdev, pDevWnd->pohBackBuffer);
  1075. }
  1076. }
  1077. }
  1078. VOID ContextSwitch(DEVRC *pRc)
  1079. {
  1080. DWORD *pdwNext = pRc->ppdev->LL_State.pDL->pdwNext;
  1081. // set control reg0
  1082. *pdwNext++ = write_register( CONTROL0_3D, 1 );
  1083. *pdwNext++ = pRc->dwControl0;
  1084. // set tx control 0, and texture xy base
  1085. *pdwNext++ = write_register( TX_CTL0_3D, 2 );
  1086. *pdwNext++ = pRc->dwTxControl0;
  1087. *pdwNext++ = pRc->dwTxXYBase;
  1088. // set color0
  1089. *pdwNext++ = write_register( COLOR0_3D, 1 );
  1090. *pdwNext++ = pRc->dwColor0;
  1091. // set to trigger next op that touches window to set base0 and base1 regs
  1092. pRc->pLastDevWnd = NULL;
  1093. pRc->pLastTexture = TEXTURE_NOT_LOADED;
  1094. pRc->ppdev->LL_State.pattern_ram_state = PATTERN_RAM_INVALID;
  1095. pRc->ppdev->pLastDevRC = (ULONG)pRc;
  1096. pRc->ppdev->LL_State.pDL->pdwNext = pdwNext;
  1097. }