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.

935 lines
27 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: mcdutil.c
  3. *
  4. * Contains various utility routines for the Millenium MCD driver such as
  5. * rendering-procedure picking functionality and buffer management.
  6. *
  7. * Copyright (c) 1996 Microsoft Corporation
  8. \**************************************************************************/
  9. #include "precomp.h"
  10. #include "mcdhw.h"
  11. #include "mcdutil.h"
  12. #include "mcdmath.h"
  13. #include "stdio.h"
  14. static ULONG xlatRop[16] = {bop_BLACKNESS, // GL_CLEAR 0
  15. bop_MASKPEN, // GL_AND S & D
  16. bop_MASKPENNOT, // GL_AND_REVERSE S & ~D
  17. bop_SRCCOPY, // GL_COPY S
  18. bop_MASKNOTPEN, // GL_AND_INVERTED ~S & D
  19. bop_NOP, // GL_NOOP D
  20. bop_XORPEN, // GL_XOR S ^ D
  21. bop_MERGEPEN, // GL_OR S | D
  22. bop_NOTMERGEPEN, // GL_NOR ~(S | D)
  23. bop_NOTXORPEN, // GL_EQUIV ~(S ^ D)
  24. bop_NOT, // GL_INVERT ~D
  25. bop_MERGEPENNOT, // GL_OR_REVERSE S | ~D
  26. bop_NOTCOPYPEN, // GL_COPY_INVERTED ~S
  27. bop_MERGENOTPEN, // GL_OR_INVERTED ~S | D
  28. bop_NOTMASKPEN, // GL_NAND ~(S & D)
  29. bop_WHITENESS, // GL_SET 1
  30. };
  31. // Function prototypes:
  32. VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip);
  33. #define MCD_ALLOC_TAG 'dDCM'
  34. #if DBG
  35. //#define DEVDBG
  36. ULONG MCDrvAllocMemSize = 0;
  37. UCHAR *MCDDbgAlloc(UINT size)
  38. {
  39. UCHAR *pRet;
  40. if (pRet = (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size + sizeof(ULONG),
  41. MCD_ALLOC_TAG)) {
  42. MCDrvAllocMemSize += size;
  43. *((ULONG *)pRet) = size;
  44. return (pRet + sizeof(ULONG));
  45. } else
  46. return (UCHAR *)NULL;
  47. }
  48. VOID MCDDbgFree(UCHAR *pMem)
  49. {
  50. if (!pMem) {
  51. MCDBG_PRINT("MCDFree: Attempt to free NULL pointer.");
  52. return;
  53. }
  54. pMem -= sizeof(ULONG);
  55. MCDrvAllocMemSize -= *((ULONG *)pMem);
  56. #ifdef DEVDBG
  57. MCDBG_PRINT("MCDFree: %x bytes in use.", MCDrvAllocMemSize);
  58. #endif
  59. EngFreeMem((VOID *)pMem);
  60. }
  61. VOID MCDrvDebugPrint(char *pMessage, ...)
  62. {
  63. va_list ap;
  64. va_start(ap, pMessage);
  65. EngDebugPrint("[MCD DRIVER] ", pMessage, ap);
  66. EngDebugPrint("", "\n", ap);
  67. va_end(ap);
  68. }
  69. #else
  70. UCHAR *MCDAlloc(UINT size)
  71. {
  72. return (UCHAR *)EngAllocMem(FL_ZERO_MEMORY, size, MCD_ALLOC_TAG);
  73. }
  74. VOID MCDFree(UCHAR *pMem)
  75. {
  76. EngFreeMem((VOID *)pMem);
  77. }
  78. #endif /* DBG */
  79. VOID FASTCALL NullRenderPoint(DEVRC *pRc, MCDVERTEX *pv)
  80. {
  81. }
  82. VOID FASTCALL NullRenderLine(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, BOOL bReset)
  83. {
  84. }
  85. VOID FASTCALL NullRenderTri(DEVRC *pRc, MCDVERTEX *pv1, MCDVERTEX *pv2, MCDVERTEX *pv3)
  86. {
  87. }
  88. MCDCOMMAND * FASTCALL FailPrimDraw(DEVRC *pRc, MCDCOMMAND *pCmd)
  89. {
  90. HW_WAIT_DRAWING_DONE(pRc);
  91. return pCmd;
  92. }
  93. BOOL PickPointFuncs(DEVRC *pRc)
  94. {
  95. ULONG enables = pRc->MCDState.enables;
  96. pRc->drawPoint = NULL; // assume failure
  97. if (enables & (MCD_POINT_SMOOTH_ENABLE))
  98. return FALSE;
  99. if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog))
  100. return FALSE;
  101. if (pRc->MCDState.pointSize != __MCDONE)
  102. return FALSE;
  103. // First, get high-level rendering functions:
  104. if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
  105. pRc->renderPoint = __MCDRenderPoint;
  106. } else {
  107. pRc->renderPoint = __MCDRenderGenPoint;
  108. }
  109. if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) {
  110. pRc->renderPointX = pRc->renderPoint;
  111. pRc->renderPoint = __MCDRenderFogPoint;
  112. }
  113. // Handle any lower-level rendering if needed:
  114. pRc->drawPoint = pRc->renderPoint;
  115. return TRUE;
  116. }
  117. BOOL PickLineFuncs(DEVRC *pRc)
  118. {
  119. ULONG enables = pRc->MCDState.enables;
  120. pRc->drawLine = NULL; // assume failure
  121. if (enables & (MCD_LINE_SMOOTH_ENABLE |
  122. MCD_LINE_STIPPLE_ENABLE))
  123. return FALSE;
  124. if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog))
  125. return FALSE;
  126. if (pRc->MCDState.lineWidth != __MCDONE)
  127. return FALSE;
  128. // First, get high-level rendering functions:
  129. if (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK) {
  130. if (pRc->MCDState.shadeModel == GL_SMOOTH)
  131. pRc->renderLine = __MCDRenderSmoothLine;
  132. else
  133. pRc->renderLine = __MCDRenderFlatLine;
  134. } else {
  135. pRc->renderLine = __MCDRenderGenLine;
  136. }
  137. if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) {
  138. pRc->renderLineX = __MCDRenderSmoothLine;
  139. pRc->renderLine = __MCDRenderFlatFogLine;
  140. }
  141. // Handle any lower-level rendering if needed:
  142. pRc->drawLine = pRc->renderLine;
  143. return TRUE;
  144. }
  145. BOOL PickTriangleFuncs(DEVRC *pRc)
  146. {
  147. ULONG enables = pRc->MCDState.enables;
  148. if (enables & MCD_POLYGON_STIPPLE_ENABLE) {
  149. ULONG *pStipple = (ULONG *)pRc->MCDState.polygonStipple;
  150. LONG i;
  151. for (pRc->hwStipple = trans_2, i = 0; i < 16; i += 2) {
  152. if ((pStipple[i] != 0xaaaaaaaa) ||
  153. (pStipple[i+1] != 0x55555555)) {
  154. pRc->hwStipple = 0;
  155. break;
  156. }
  157. }
  158. if (!pRc->hwStipple) {
  159. for (pRc->hwStipple = trans_1, i = 0; i < 16; i += 2) {
  160. if ((pStipple[i] != 0x55555555) ||
  161. (pStipple[i+1] != 0xaaaaaaaa)) {
  162. pRc->hwStipple = 0;
  163. break;
  164. }
  165. }
  166. }
  167. if (!pRc->hwStipple)
  168. return FALSE;
  169. } else
  170. pRc->hwStipple = 0;
  171. if (enables & (MCD_POLYGON_SMOOTH_ENABLE |
  172. MCD_COLOR_LOGIC_OP_ENABLE))
  173. return FALSE;
  174. if ((enables & MCD_FOG_ENABLE) && (!pRc->bCheapFog))
  175. return FALSE;
  176. // First, get high-level rendering functions. If we're not GL_FILL'ing
  177. // both sides of our polygons, use the "generic" function.
  178. if (((pRc->MCDState.polygonModeFront == GL_FILL) &&
  179. (pRc->MCDState.polygonModeBack == GL_FILL)) &&
  180. (pRc->MCDState.drawBuffer != GL_FRONT_AND_BACK)
  181. ) {
  182. if ((pRc->MCDState.shadeModel == GL_SMOOTH) ||
  183. (pRc->bCheapFog))
  184. pRc->renderTri = __MCDRenderSmoothTriangle;
  185. else
  186. pRc->renderTri = __MCDRenderFlatTriangle;
  187. } else {
  188. pRc->renderTri = __MCDRenderGenTriangle;
  189. // In this case, we must handle the various fill modes. We must
  190. // fail triangle drawing if we can't handle the types of primitives
  191. // that may have to be drawn. This logic depends on the line and
  192. // point pick routines
  193. if (((pRc->MCDState.polygonModeFront == GL_POINT) && (!pRc->drawPoint)) ||
  194. ((pRc->MCDState.polygonModeFront == GL_LINE) && (!pRc->drawLine)))
  195. return FALSE;
  196. if (pRc->privateEnables & __MCDENABLE_TWOSIDED) {
  197. if (((pRc->MCDState.polygonModeBack == GL_POINT) && (!pRc->drawPoint)) ||
  198. ((pRc->MCDState.polygonModeBack == GL_LINE) && (!pRc->drawLine)))
  199. return FALSE;
  200. }
  201. }
  202. if ((pRc->bCheapFog) && (pRc->MCDState.shadeModel != GL_SMOOTH)) {
  203. pRc->renderTriX = pRc->renderTri;
  204. pRc->renderTri = __MCDRenderFlatFogTriangle;
  205. }
  206. // Handle lower-level triangle rendering:
  207. pRc->drawTri = __MCDFillTriangle;
  208. pRc->HWDrawTrap = __HWDrawTrap;
  209. pRc->HWSetupDeltas = __HWSetupDeltas;
  210. pRc->calcDeltas = __MCDCalcDeltaRGBZ;
  211. pRc->adjustLeftEdge = __HWAdjustLeftEdgeRGBZ;
  212. pRc->adjustRightEdge = __HWAdjustRightEdge;
  213. return TRUE;
  214. }
  215. VOID __MCDPickRenderingFuncs(DEVRC *pRc, DEVWND *pDevWnd)
  216. {
  217. BOOL bSupportedZFunc = TRUE;
  218. pRc->primFunc[GL_POINTS] = __MCDPrimDrawPoints;
  219. pRc->primFunc[GL_LINES] = __MCDPrimDrawLines;
  220. pRc->primFunc[GL_LINE_LOOP] = __MCDPrimDrawLineLoop;
  221. pRc->primFunc[GL_LINE_STRIP] = __MCDPrimDrawLineStrip;
  222. pRc->primFunc[GL_TRIANGLES] = __MCDPrimDrawTriangles;
  223. pRc->primFunc[GL_TRIANGLE_STRIP] = __MCDPrimDrawTriangleStrip;
  224. pRc->primFunc[GL_TRIANGLE_FAN] = __MCDPrimDrawTriangleFan;
  225. pRc->primFunc[GL_QUADS] = __MCDPrimDrawQuads;
  226. pRc->primFunc[GL_QUAD_STRIP] = __MCDPrimDrawQuadStrip;
  227. pRc->primFunc[GL_POLYGON] = __MCDPrimDrawPolygon;
  228. // Set up the privateEnables flags:
  229. switch (pRc->MCDState.depthTestFunc) {
  230. default:
  231. case GL_NEVER:
  232. bSupportedZFunc = FALSE;
  233. break;
  234. case GL_LESS:
  235. pRc->hwZFunc = zmode_ZLT;
  236. break;
  237. case GL_EQUAL:
  238. pRc->hwZFunc = zmode_ZE;
  239. break;
  240. case GL_LEQUAL:
  241. pRc->hwZFunc = zmode_ZLTE;
  242. break;
  243. case GL_GREATER:
  244. pRc->hwZFunc = zmode_ZGT;
  245. break;
  246. case GL_NOTEQUAL:
  247. pRc->hwZFunc = zmode_ZNE;
  248. break;
  249. case GL_GEQUAL:
  250. pRc->hwZFunc = zmode_ZGTE;
  251. break;
  252. case GL_ALWAYS:
  253. pRc->hwZFunc = zmode_NOZCMP;
  254. break;
  255. }
  256. if (pRc->MCDState.enables & MCD_COLOR_LOGIC_OP_ENABLE) {
  257. pRc->hwRop = xlatRop[pRc->MCDState.logicOpMode & 0xf];
  258. } else
  259. pRc->hwRop = bop_SRCCOPY;
  260. HW_GET_PLANE_MASK(pRc);
  261. pRc->privateEnables = 0;
  262. if ((pRc->MCDState.twoSided) &&
  263. (pRc->MCDState.enables & MCD_LIGHTING_ENABLE))
  264. pRc->privateEnables |= __MCDENABLE_TWOSIDED;
  265. if (pDevWnd->bValidZBuffer &&
  266. (pRc->MCDState.enables & MCD_DEPTH_TEST_ENABLE))
  267. pRc->privateEnables |= __MCDENABLE_Z;
  268. if (pRc->MCDState.shadeModel == GL_SMOOTH)
  269. pRc->privateEnables |= __MCDENABLE_SMOOTH;
  270. // Bail out if we can't support the requested z-buffer function:
  271. if (pRc->privateEnables & __MCDENABLE_Z) {
  272. if (!bSupportedZFunc) {
  273. pRc->allPrimFail = TRUE;
  274. return;
  275. }
  276. if ((pRc->MCDState.depthWritemask) && (pRc->zBufEnabled)) {
  277. pRc->hwTrapFunc = pRc->hwLineFunc = atype_ZI;
  278. } else {
  279. pRc->hwTrapFunc = pRc->hwLineFunc = atype_I;
  280. }
  281. pRc->hwTrapFunc |= opcode_TRAP | pRc->hwRop | pRc->hwZFunc;
  282. pRc->hwLineFunc |= opcode_LINE_OPEN | pRc->hwRop | pRc->hwZFunc;
  283. } else {
  284. pRc->hwTrapFunc = opcode_TRAP | atype_I | bop_SRCCOPY;
  285. pRc->hwLineFunc = opcode_LINE_OPEN | atype_I | bop_SRCCOPY;
  286. }
  287. pRc->HWSetupClipRect = HWSetupClipping;
  288. // Even though we're set up to handle this in the primitive pick
  289. // functions, we'll exit early here since we don't actually handle
  290. // this in the primitive routines themselves:
  291. if (pRc->MCDState.drawBuffer == GL_FRONT_AND_BACK) {
  292. pRc->allPrimFail = TRUE;
  293. return;
  294. }
  295. // If we're culling everything or not updating any of our buffers, just
  296. // return for all primitives:
  297. if (((pRc->MCDState.enables & MCD_CULL_FACE_ENABLE) &&
  298. (pRc->MCDState.cullFaceMode == GL_FRONT_AND_BACK)) ||
  299. ((pRc->MCDState.drawBuffer == GL_NONE) &&
  300. ((!pRc->MCDState.depthWritemask) || (!pDevWnd->bValidZBuffer)))
  301. ) {
  302. pRc->renderPoint = NullRenderPoint;
  303. pRc->renderLine = NullRenderLine;
  304. pRc->renderTri = NullRenderTri;
  305. pRc->allPrimFail = FALSE;
  306. return;
  307. }
  308. // Build lookup table for face direction
  309. switch (pRc->MCDState.frontFace) {
  310. case GL_CW:
  311. pRc->polygonFace[__MCD_CW] = __MCD_BACKFACE;
  312. pRc->polygonFace[__MCD_CCW] = __MCD_FRONTFACE;
  313. break;
  314. case GL_CCW:
  315. pRc->polygonFace[__MCD_CW] = __MCD_FRONTFACE;
  316. pRc->polygonFace[__MCD_CCW] = __MCD_BACKFACE;
  317. break;
  318. }
  319. // Build lookup table for face filling modes:
  320. pRc->polygonMode[__MCD_FRONTFACE] = pRc->MCDState.polygonModeFront;
  321. pRc->polygonMode[__MCD_BACKFACE] = pRc->MCDState.polygonModeBack;
  322. if (pRc->MCDState.enables & MCD_CULL_FACE_ENABLE)
  323. pRc->cullFlag = (pRc->MCDState.cullFaceMode == GL_FRONT ? __MCD_FRONTFACE :
  324. __MCD_BACKFACE);
  325. else
  326. pRc->cullFlag = __MCD_NOFACE;
  327. // Assume that we fail everything:
  328. pRc->allPrimFail = TRUE;
  329. // Determine if we have "cheap" fog:
  330. pRc->bCheapFog = FALSE;
  331. if (pRc->MCDState.enables & MCD_FOG_ENABLE) {
  332. if (!(pRc->MCDState.textureEnabled) &&
  333. (pRc->MCDState.fogHint != GL_NICEST)) {
  334. pRc->bCheapFog = TRUE;
  335. pRc->privateEnables |= __MCDENABLE_SMOOTH;
  336. if ((pRc->MCDState.fogColor.r == pRc->MCDState.fogColor.g) &&
  337. (pRc->MCDState.fogColor.r == pRc->MCDState.fogColor.b))
  338. pRc->privateEnables |= __MCDENABLE_GRAY_FOG;
  339. }
  340. }
  341. if (pRc->MCDState.textureEnabled)
  342. return;
  343. if (pRc->MCDState.enables & (MCD_ALPHA_TEST_ENABLE |
  344. MCD_BLEND_ENABLE |
  345. MCD_STENCIL_TEST_ENABLE))
  346. return;
  347. // Get rendering functions for points:
  348. if (!PickPointFuncs(pRc)) {
  349. pRc->primFunc[GL_POINTS] = FailPrimDraw;
  350. } else
  351. pRc->allPrimFail = FALSE;
  352. // Get rendering functions for lines:
  353. if (!PickLineFuncs(pRc)) {
  354. pRc->primFunc[GL_LINES] = FailPrimDraw;
  355. pRc->primFunc[GL_LINE_LOOP] = FailPrimDraw;
  356. pRc->primFunc[GL_LINE_STRIP] = FailPrimDraw;
  357. } else
  358. pRc->allPrimFail = FALSE;
  359. // Get rendering functions for triangles:
  360. if (!PickTriangleFuncs(pRc)) {
  361. pRc->primFunc[GL_TRIANGLES] = FailPrimDraw;
  362. pRc->primFunc[GL_TRIANGLE_STRIP] = FailPrimDraw;
  363. pRc->primFunc[GL_TRIANGLE_FAN] = FailPrimDraw;
  364. pRc->primFunc[GL_QUADS] = FailPrimDraw;
  365. pRc->primFunc[GL_QUAD_STRIP] = FailPrimDraw;
  366. pRc->primFunc[GL_POLYGON] = FailPrimDraw;
  367. } else
  368. pRc->allPrimFail = FALSE;
  369. }
  370. ////////////////////////////////////////////////////////////////////////
  371. // Hardware-specific utility functions:
  372. ////////////////////////////////////////////////////////////////////////
  373. VOID FASTCALL HWSetupClipping(DEVRC *pRc, RECTL *pClip)
  374. {
  375. PDEV *ppdev = pRc->ppdev;
  376. BYTE *pjBase = ppdev->pjBase;
  377. CHECK_FIFO_FREE(pjBase, pRc->cFifo, 4);
  378. CP_WRITE(pjBase, DWG_CYTOP,
  379. ((pClip->top + pRc->hwBufferYBias) * ppdev->cxMemory) +
  380. ppdev->ulYDstOrg);
  381. CP_WRITE(pjBase, DWG_CXLEFT, pClip->left);
  382. CP_WRITE(pjBase, DWG_CXRIGHT, pClip->right - 1);
  383. CP_WRITE(pjBase, DWG_CYBOT,
  384. ((pClip->bottom + pRc->hwBufferYBias - 1) * ppdev->cxMemory) +
  385. ppdev->ulYDstOrg);
  386. }
  387. //#define DEBUG_OFFSCREEN 1
  388. //#define DEBUG_OFFSSCREEN_PARTIAL 1
  389. #if DEBUG_OFFSCREEN
  390. #undef pohAllocate
  391. #undef pohFree
  392. #define pohAllocate
  393. #define pohFree
  394. #endif
  395. VOID HWUpdateBufferPos(MCDWINDOW *pMCDWnd, SURFOBJ *pso, BOOL bForce)
  396. {
  397. PDEV *ppdev = (PDEV *)pso->dhpdev;
  398. DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
  399. ULONG height;
  400. if (pDevWnd->pohZBuffer &&
  401. ((ppdev->pohZBuffer != pDevWnd->pohZBuffer) ||
  402. (bForce))) {
  403. LONG offset;
  404. LONG offsetAdj;
  405. ULONG y;
  406. // First, re-adjust the z buffer so that its offset from
  407. // the front buffer window rectangle (in z) is a multiple of 512:
  408. if (ppdev->pohZBuffer != pDevWnd->pohZBuffer)
  409. offset = pDevWnd->zBufferBase -
  410. (pMCDWnd->clipBoundsRect.top * pDevWnd->zPitch);
  411. else
  412. offset = pDevWnd->zBufferBase;
  413. if (offset < 0) {
  414. offset = -offset;
  415. for (y = 0, offsetAdj = 0;
  416. (y < pDevWnd->numPadScans) && (offset & 0x1ff);
  417. offset -= pDevWnd->zPitch, offsetAdj += pDevWnd->zPitch)
  418. ;
  419. } else {
  420. for (y = 0, offsetAdj = 0;
  421. (y < pDevWnd->numPadScans) && (offset & 0x1ff);
  422. offset += pDevWnd->zPitch, offsetAdj += pDevWnd->zPitch)
  423. ;
  424. }
  425. ASSERTDD((offset & 0x1ff) == 0, "Z scan not on a 512-byte boundary.");
  426. ASSERTDD(y <= pDevWnd->numPadScans, "Z scan adjustment too large");
  427. pDevWnd->zBufferOffset = pDevWnd->zBufferBase + offsetAdj;
  428. // Now, re-adjust the back buffer so that its offset (in z) from
  429. // the new z buffer offset is also a multiple of 512 bytes. Note
  430. // that zBufferOffset is always a multiple of zPitch:
  431. if (pDevWnd->pohBackBuffer) {
  432. offset = (pDevWnd->backBufferBaseY * pDevWnd->zPitch) -
  433. pDevWnd->zBufferOffset;
  434. for (y = 0; (y < pDevWnd->numPadScans) && (offset & 0x1ff); y++)
  435. offset += pDevWnd->zPitch;
  436. ASSERTDD((offset & 0x1ff) == 0, "Scan not on a 512-byte boundary.");
  437. ASSERTDD(y <= pDevWnd->numPadScans, "Scan adjustment too large");
  438. pDevWnd->backBufferY = y + pDevWnd->backBufferBaseY;
  439. pDevWnd->backBufferOffset = (pDevWnd->backBufferY * ppdev->lDelta);
  440. }
  441. }
  442. height = pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top;
  443. if (height > pDevWnd->allocatedBufferHeight) {
  444. #ifdef DEVDBG
  445. MCDBG_PRINT("HWUpdateBufferPos: buffers are now an invalid size.");
  446. #endif
  447. pDevWnd->bValidBackBuffer = FALSE;
  448. pDevWnd->bValidZBuffer = FALSE;
  449. }
  450. }
  451. BOOL HWAllocResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso,
  452. BOOL zBufferEnabled,
  453. BOOL backBufferEnabled)
  454. {
  455. DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
  456. PDEV *ppdev = (PDEV *)pso->dhpdev;
  457. ULONG w, width, height, fullHeight, zHeight, zFullHeight;
  458. BOOL needFullZBuffer, needFullBackBuffer;
  459. ULONG bufferExtra;
  460. ULONG wPow2;
  461. ULONG zPitch;
  462. BOOL bFullScreen = FALSE;
  463. OH* pohBackBuffer = NULL;
  464. OH* pohZBuffer = NULL;
  465. #if DEBUG_OFFSCREEN
  466. static OH fakeOh[2];
  467. pohBackBuffer = &fakeOh[0];
  468. pohZBuffer = &fakeOh[1];
  469. pohBackBuffer->y = 512;
  470. pohZBuffer->y = 256;
  471. #endif
  472. #ifdef DEVDBG
  473. MCDBG_PRINT("HWAllocResources");
  474. #endif
  475. #if DEBUG_OFFSCREEN
  476. width = ppdev->cxScreen;
  477. height = 256;
  478. #else
  479. width = ppdev->cxScreen;
  480. height = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top,
  481. ppdev->cyScreen);
  482. #endif
  483. // Assume failure:
  484. pDevWnd->allocatedBufferHeight = 0;
  485. pDevWnd->bValidBackBuffer = FALSE;
  486. pDevWnd->bValidZBuffer = FALSE;
  487. pDevWnd->pohBackBuffer = NULL;
  488. pDevWnd->pohZBuffer = NULL;
  489. fullHeight = ppdev->cyScreen;
  490. switch (ppdev->iBitmapFormat) {
  491. case BMF_8BPP:
  492. zPitch = ppdev->lDelta * 2;
  493. break;
  494. case BMF_16BPP:
  495. zPitch = ppdev->lDelta;
  496. break;
  497. case BMF_24BPP:
  498. case BMF_32BPP:
  499. zPitch = ppdev->lDelta / 2;
  500. break;
  501. default:
  502. return FALSE;
  503. }
  504. // We have to be able to keep our buffers 512-byte aligned, so calculate
  505. // extra scan lines needed to aligned scan on a 512-byte boundary:
  506. for (wPow2 = 1, w = zPitch;
  507. (w) && !(w & 1); w >>= 1, wPow2 *= 2)
  508. ;
  509. bufferExtra = 512 / wPow2; // z buffer granularity is 512 bytes...
  510. // Now adjust the number of extra scan lines needed for the pixel format
  511. // we're using, since the z and color stride may be different...
  512. switch (ppdev->iBitmapFormat) {
  513. case BMF_8BPP:
  514. zHeight = ((height + bufferExtra) * 2) + 1;
  515. zFullHeight = ((fullHeight + bufferExtra) * 2) + 1;
  516. break;
  517. case BMF_16BPP:
  518. zHeight = height + bufferExtra;
  519. zFullHeight = fullHeight + bufferExtra;
  520. break;
  521. case BMF_24BPP:
  522. case BMF_32BPP:
  523. zHeight = (height + bufferExtra + 1) / 2;
  524. zFullHeight = (fullHeight + bufferExtra + 1) / 2;
  525. break;
  526. default:
  527. return FALSE;
  528. }
  529. pDevWnd->numPadScans = bufferExtra;
  530. // Add extra scans for alignment:
  531. height += bufferExtra;
  532. fullHeight += bufferExtra;
  533. if ((backBufferEnabled) && (!ppdev->cDoubleBufferRef))
  534. needFullBackBuffer = TRUE;
  535. else
  536. needFullBackBuffer = FALSE;
  537. if ((zBufferEnabled) && (!ppdev->cZBufferRef))
  538. needFullZBuffer = TRUE;
  539. else
  540. needFullZBuffer = FALSE;
  541. // debugging - force parial window allocation
  542. #if DEBUG_OFFSCREEN && DEBUG_OFFSCREEN_PARTIAL
  543. pohBackBuffer = NULL;
  544. pohZBuffer = NULL;
  545. #endif
  546. // Before we begin, boot all the discardable stuff from offscreen
  547. // memory:
  548. bMoveAllDfbsFromOffscreenToDibs(ppdev);
  549. // If we need a back buffer, first try to allocate a fullscreen one:
  550. if (needFullBackBuffer) {
  551. #ifndef DEBUG_OFFSCREEN
  552. pohBackBuffer = pohAllocate(ppdev, NULL, width, fullHeight,
  553. FLOH_MAKE_PERMANENT);
  554. #endif
  555. if (pohBackBuffer) {
  556. ppdev->pohBackBuffer = pohBackBuffer;
  557. ppdev->cDoubleBufferRef = 0;
  558. }
  559. }
  560. // If we need a z buffer, first try to allocate a fullscreen z:
  561. if (needFullZBuffer) {
  562. #ifndef DEBUG_OFFSCREEN
  563. pohZBuffer = pohAllocate(ppdev, NULL, width, zFullHeight,
  564. FLOH_MAKE_PERMANENT);
  565. #endif
  566. if (pohZBuffer) {
  567. ppdev->pohZBuffer = pohZBuffer;
  568. ppdev->cZBufferRef = 0;
  569. } else
  570. needFullBackBuffer = FALSE;
  571. }
  572. // One of our full-screen allocations failed:
  573. if ((needFullZBuffer && !pohZBuffer) ||
  574. (needFullBackBuffer && !pohBackBuffer)) {
  575. // Free any resources allocated so far:
  576. if (pohZBuffer) {
  577. pohFree(ppdev, pohZBuffer);
  578. ppdev->pohZBuffer = NULL;
  579. ppdev->cZBufferRef = 0;
  580. }
  581. if (pohBackBuffer) {
  582. pohFree(ppdev, pohBackBuffer);
  583. ppdev->pohBackBuffer = NULL;
  584. ppdev->cDoubleBufferRef = 0;
  585. }
  586. // Now, try to allocate per-window resources:
  587. if (backBufferEnabled) {
  588. #ifndef DEBUG_OFFSCREEN
  589. pohBackBuffer = pohAllocate(ppdev, NULL, width, height,
  590. FLOH_MAKE_PERMANENT);
  591. #else
  592. pohBackBuffer = &fakeOh[0];
  593. #endif
  594. if (!pohBackBuffer) {
  595. return FALSE;
  596. }
  597. }
  598. if (zBufferEnabled) {
  599. #ifndef DEBUG_OFFSCREEN
  600. pohZBuffer = pohAllocate(ppdev, NULL, width, zHeight,
  601. FLOH_MAKE_PERMANENT);
  602. #else
  603. pohZBuffer = &fakeOh[1];
  604. #endif
  605. if (!pohZBuffer) {
  606. if (pohBackBuffer)
  607. pohFree(ppdev, pohBackBuffer);
  608. return FALSE;
  609. }
  610. }
  611. #ifdef DEVDBG
  612. if (zBufferEnabled)
  613. MCDBG_PRINT("HWAllocResources: Allocated window-sized z buffer");
  614. if (backBufferEnabled)
  615. MCDBG_PRINT("HWAllocResources: Allocated window-sized back buffer");
  616. #endif
  617. } else {
  618. // Our full-screen allocations worked, or the resources existed
  619. // already:
  620. bFullScreen = TRUE;
  621. #ifdef DEVDBG
  622. if (zBufferEnabled && !ppdev->cZBufferRef)
  623. MCDBG_PRINT("HWAllocResources: Allocated full-screen z buffer");
  624. if (backBufferEnabled && !ppdev->cDoubleBufferRef)
  625. MCDBG_PRINT("HWAllocResources: Allocated full-screen back buffer");
  626. #endif
  627. if (zBufferEnabled) {
  628. pohZBuffer = ppdev->pohZBuffer;
  629. ppdev->cZBufferRef++;
  630. }
  631. if (backBufferEnabled) {
  632. pohBackBuffer = ppdev->pohBackBuffer;
  633. ppdev->cDoubleBufferRef++;
  634. }
  635. }
  636. pDevWnd->pohBackBuffer = pohBackBuffer;
  637. pDevWnd->pohZBuffer = pohZBuffer;
  638. pDevWnd->frontBufferPitch = ppdev->lDelta;
  639. // Calculate back buffer variables:
  640. if (backBufferEnabled) {
  641. ULONG y;
  642. ULONG offset;
  643. ASSERTDD(pohBackBuffer->x == 0,
  644. "Back buffer should be 0-aligned");
  645. // Set up base position, etc.
  646. pDevWnd->backBufferY = pDevWnd->backBufferBaseY = pohBackBuffer->y;
  647. pDevWnd->backBufferOffset = pDevWnd->backBufferBase =
  648. pohBackBuffer->y * ppdev->lDelta;
  649. pDevWnd->backBufferPitch = ppdev->lDelta;
  650. pDevWnd->bValidBackBuffer = TRUE;
  651. }
  652. if (zBufferEnabled) {
  653. ULONG y = pohZBuffer->y;
  654. ASSERTDD(pohZBuffer->x == 0,
  655. "Z buffer should be 0-aligned");
  656. pDevWnd->zBufferBaseY = pohZBuffer->y;
  657. // Make sure out z buffer starts on a valid z scan line. The only
  658. // case where this may not happen is 8bpp, which is why we add one
  659. // the the number if z scan lines allocated above.
  660. if (ppdev->iBitmapFormat == BMF_8BPP)
  661. pDevWnd->zBufferBase = (pohZBuffer->y & ~1) * ppdev->lDelta;
  662. else
  663. pDevWnd->zBufferBase = pohZBuffer->y * ppdev->lDelta;
  664. pDevWnd->zPitch = zPitch;
  665. pDevWnd->bValidZBuffer = TRUE;
  666. }
  667. if (bFullScreen)
  668. pDevWnd->allocatedBufferHeight = ppdev->cyMemory;
  669. else
  670. pDevWnd->allocatedBufferHeight = min(pMCDWnd->clientRect.bottom - pMCDWnd->clientRect.top,
  671. ppdev->cyScreen);
  672. // Update position-dependant buffer information:
  673. HWUpdateBufferPos(pMCDWnd, pso, TRUE);
  674. #ifdef DEVDBG
  675. MCDBG_PRINT("HWAllocResources OK");
  676. #endif
  677. return TRUE;
  678. }
  679. VOID HWFreeResources(MCDWINDOW *pMCDWnd, SURFOBJ *pso)
  680. {
  681. DEVWND *pDevWnd = (DEVWND *)pMCDWnd->pvUser;
  682. PDEV *ppdev = (PDEV *)pso->dhpdev;
  683. if (pDevWnd->pohZBuffer) {
  684. if (ppdev->cZBufferRef) {
  685. if (!--ppdev->cZBufferRef) {
  686. #ifdef DEVDBG
  687. MCDBG_PRINT("MCDrvTrackWindow: Free global z buffer");
  688. #endif
  689. pohFree(ppdev, ppdev->pohZBuffer);
  690. ppdev->pohZBuffer = NULL;
  691. }
  692. } else {
  693. #ifdef DEVDBG
  694. MCDBG_PRINT("MCDrvTrackWindow: Free local z buffer");
  695. #endif
  696. pohFree(ppdev, pDevWnd->pohZBuffer);
  697. }
  698. }
  699. if (pDevWnd->pohBackBuffer) {
  700. if (ppdev->cDoubleBufferRef) {
  701. if (!--ppdev->cDoubleBufferRef) {
  702. #ifdef DEVDBG
  703. MCDBG_PRINT("MCDrvTrackWindow: Free global color buffer");
  704. #endif
  705. pohFree(ppdev, ppdev->pohBackBuffer);
  706. ppdev->pohBackBuffer = NULL;
  707. }
  708. } else {
  709. #ifdef DEVDBG
  710. MCDBG_PRINT("MCDrvTrackWindow: Free local color buffer");
  711. #endif
  712. pohFree(ppdev, pDevWnd->pohBackBuffer);
  713. }
  714. }
  715. }
  716. VOID __MCDCalcFogColor(DEVRC *pRc, MCDVERTEX *a, MCDCOLOR *pResult,
  717. MCDCOLOR *pColor)
  718. {
  719. MCDFLOAT oneMinusFog;
  720. MCDCOLOR *pFogColor;
  721. pFogColor = (MCDCOLOR *)&pRc->MCDState.fogColor;
  722. oneMinusFog = (MCDFLOAT)1.0 - a->fog;
  723. if (pRc->privateEnables & __MCDENABLE_GRAY_FOG) {
  724. MCDFLOAT delta = oneMinusFog * pFogColor->r;
  725. pResult->r = a->fog * pColor->r + delta;
  726. pResult->g = a->fog * pColor->g + delta;
  727. pResult->b = a->fog * pColor->b + delta;
  728. } else {
  729. pResult->r = (a->fog * pColor->r) + (oneMinusFog * pFogColor->r);
  730. pResult->g = (a->fog * pColor->g) + (oneMinusFog * pFogColor->g);
  731. pResult->b = (a->fog * pColor->b) + (oneMinusFog * pFogColor->b);
  732. }
  733. }