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.

399 lines
14 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: drawprim.hpp
  6. * Content: DrawPrimitive common defines
  7. *
  8. ***************************************************************************/
  9. #ifndef _DRAWPRIM_H_
  10. #define _DRAWPRIM_H_
  11. #define MAX_DX6_PRIMCOUNT ((1<<16) - 1)
  12. #define MAX_DX6_VERTICES MAX_DX6_PRIMCOUNT
  13. extern HRESULT DoDrawPrimitive(LPD3DFE_PROCESSVERTICES pv);
  14. extern HRESULT DoDrawIndexedPrimitive(LPD3DFE_PROCESSVERTICES pv);
  15. extern HRESULT downloadView(LPDIRECT3DVIEWPORTI);
  16. extern HRESULT CheckDrawPrimitive(LPDIRECT3DDEVICEI lpDevI);
  17. extern HRESULT CheckDrawIndexedPrimitive(LPDIRECT3DDEVICEI lpDevI);
  18. // All vertices from lpDevI->lpVout are copied to the output buffer, expanding
  19. // to D3DTLVERTEX.
  20. // The output buffer is lpAddress if it is not NULL, otherwise it is TLVbuf
  21. //
  22. extern HRESULT MapFVFtoTLVertex(LPDIRECT3DDEVICEI lpDevI, LPVOID lpAddress);
  23. //---------------------------------------------------------------------
  24. #define FVF_TRANSFORMED(dwFVF) ((dwFVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
  25. #define FVF_DRIVERSUPPORTED(lpDevI) (lpDevI->dwDeviceFlags & D3DDEV_FVF)
  26. #define FVF_TEXCOORD_NUMBER(dwFVF) \
  27. (((dwFVF) & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT)
  28. //---------------------------------------------------------------------
  29. // Input:
  30. // type - FVF control word
  31. //
  32. // Returns D3D_OK, if the control word is valid.
  33. // DDERR_INVALIDPARAMS otherwise
  34. //
  35. #undef DPF_MODNAME
  36. #define DPF_MODNAME "ValidateFVF"
  37. __inline HRESULT ValidateFVF(DWORD type)
  38. {
  39. DWORD dwTexCoord = FVF_TEXCOORD_NUMBER(type);
  40. DWORD vertexType = type & D3DFVF_POSITION_MASK;
  41. // Texture type fields should be 0
  42. // Reserved field 0 and 2 should be 0
  43. // Reserved 1 should be set only for LVERTEX
  44. // Only two vertex position types allowed
  45. if (type & 0xFFFF0000 ||
  46. type & (D3DFVF_RESERVED2 | D3DFVF_RESERVED0) ||
  47. (type & D3DFVF_RESERVED1 && !(type & D3DFVF_LVERTEX)) ||
  48. !(vertexType == D3DFVF_XYZRHW || vertexType == D3DFVF_XYZ)
  49. )
  50. goto error;
  51. if (vertexType == D3DFVF_XYZRHW && type & D3DFVF_NORMAL)
  52. goto error;
  53. return D3D_OK;
  54. error:
  55. D3D_ERR("ValidateFVF() returns DDERR_INVALIDPARAMS");
  56. return DDERR_INVALIDPARAMS;
  57. }
  58. //---------------------------------------------------------------------
  59. // Computes vertex size in bytes from the vertex ID
  60. //
  61. __inline DWORD GetVertexSizeFVF(DWORD fvf)
  62. {
  63. DWORD size = 3;
  64. if (FVF_TRANSFORMED(fvf))
  65. size++;
  66. if (fvf & D3DFVF_NORMAL)
  67. size += 3;
  68. if (fvf & D3DFVF_RESERVED1)
  69. size++;
  70. size += FVF_TEXCOORD_NUMBER(fvf) << 1;
  71. if (fvf & D3DFVF_DIFFUSE)
  72. size++;
  73. if (fvf & D3DFVF_SPECULAR)
  74. size++;
  75. return (size << 2);
  76. }
  77. //---------------------------------------------------------------------
  78. __inline BOOL TextureStageEnabled(LPDIRECT3DDEVICEI lpDevI, DWORD dwStage)
  79. {
  80. return (lpDevI->tsstates[dwStage][D3DTSS_COLOROP] != D3DTOP_DISABLE &&
  81. lpDevI->lpD3DMappedTexI[dwStage] != NULL);
  82. }
  83. //---------------------------------------------------------------------
  84. // Computes nTexCoord and dwTextureIndexToCopy in case when a pre-DX6
  85. // driver is used.
  86. __inline void ComputeTCI2CopyLegacy(LPDIRECT3DDEVICEI lpDevI,
  87. DWORD dwNumInpTexCoord,
  88. BOOL bVertexTransformed)
  89. {
  90. if (lpDevI->dwDeviceFlags & D3DDEV_LEGACYTEXTURE)
  91. {
  92. lpDevI->dwTextureIndexToCopy = 0;
  93. if (dwNumInpTexCoord)
  94. lpDevI->nTexCoord = 1;
  95. else
  96. {
  97. lpDevI->nTexCoord = 0;
  98. D3D_WARN(1, "Texture is enabled but vertex has no texture coordinates");
  99. }
  100. }
  101. else
  102. {
  103. if (TextureStageEnabled(lpDevI, 0))
  104. {
  105. if (lpDevI->tsstates[0][D3DTSS_TEXCOORDINDEX] >= dwNumInpTexCoord)
  106. {
  107. lpDevI->nTexCoord = 0;
  108. lpDevI->dwTextureIndexToCopy = 0;
  109. D3D_WARN(1, "Texture index in a texture stage is greater than number of texture coord in vertex");
  110. }
  111. else
  112. {
  113. lpDevI->dwTextureIndexToCopy = lpDevI->tsstates[0][D3DTSS_TEXCOORDINDEX];
  114. if (bVertexTransformed)
  115. {
  116. // In case of clipping we need to clip as many texture
  117. // coordinates as set in the texture stage state.
  118. lpDevI->nTexCoord = min(dwNumInpTexCoord,
  119. lpDevI->dwTextureIndexToCopy+1);
  120. }
  121. else
  122. {
  123. // Number of output texture coordinates is 1 because we will
  124. // build the output buffer in the inner transform & lihgting
  125. // loop.
  126. lpDevI->nTexCoord = 1;
  127. }
  128. }
  129. }
  130. else
  131. {
  132. lpDevI->nTexCoord = 0;
  133. lpDevI->dwTextureIndexToCopy = 0;
  134. }
  135. }
  136. }
  137. //---------------------------------------------------------------------
  138. // Computes output FVF id, based on input FVF id and device settingd
  139. // Also computes nTexCoord field
  140. // Number of texture coordinates is set based on dwVIDIn. ValidateFVF sould
  141. // make sure that it is not greater than supported by the driver
  142. // Last settings for dwVIDOut and dwVIDIn are saved to speed up processing
  143. //
  144. #undef DPF_MODNAME
  145. #define DPF_MODNAME "ComputeOutputFVF"
  146. __inline void ComputeOutputFVF(LPDIRECT3DDEVICEI lpDevI)
  147. {
  148. if (lpDevI->dwVIDIn == lpDevI->dwFVFLastIn)
  149. {
  150. lpDevI->dwVIDOut = lpDevI->dwFVFLastOut;
  151. lpDevI->dwOutputSize = lpDevI->dwFVFLastOutputSize;
  152. lpDevI->nTexCoord = lpDevI->dwFVFLastTexCoord;
  153. return;
  154. }
  155. DWORD dwNumInpTexCoord = FVF_TEXCOORD_NUMBER(lpDevI->dwVIDIn);
  156. // Compute how many texture coordinates to copy
  157. if (lpDevI->dwMaxTextureIndices == 0)
  158. lpDevI->nTexCoord = 0;
  159. else
  160. if (!(lpDevI->dwDeviceFlags & D3DDEV_FVF))
  161. {
  162. ComputeTCI2CopyLegacy(lpDevI, dwNumInpTexCoord, FVF_TRANSFORMED(lpDevI->dwVIDIn));
  163. }
  164. else
  165. {
  166. if (lpDevI->dwDeviceFlags & D3DDEV_LEGACYTEXTURE)
  167. lpDevI->nTexCoord = 1;
  168. else
  169. {
  170. // Find the max used index
  171. if (!(lpDevI->dwFEFlags & D3DFE_TSSINDEX_DIRTY))
  172. lpDevI->nTexCoord = lpDevI->dwMaxUsedTextureIndex;
  173. else
  174. {
  175. lpDevI->dwMaxUsedTextureIndex = 0;
  176. for (DWORD i=0; i < lpDevI->dwMaxTextureBlendStages; i++)
  177. {
  178. if (lpDevI->tsstates[i][D3DTSS_COLOROP] == D3DTOP_DISABLE)
  179. break;
  180. if (lpDevI->lpD3DMappedTexI[i] != NULL)
  181. {
  182. DWORD dwNewMaxTexCoord = lpDevI->tsstates[i][D3DTSS_TEXCOORDINDEX] + 1;
  183. if (lpDevI->dwMaxUsedTextureIndex < dwNewMaxTexCoord)
  184. {
  185. lpDevI->dwMaxUsedTextureIndex = dwNewMaxTexCoord;
  186. }
  187. }
  188. }
  189. lpDevI->nTexCoord = lpDevI->dwMaxUsedTextureIndex;
  190. lpDevI->dwFEFlags &= ~D3DFE_TSSINDEX_DIRTY;
  191. }
  192. }
  193. if (lpDevI->nTexCoord > dwNumInpTexCoord)
  194. {
  195. lpDevI->nTexCoord = dwNumInpTexCoord;
  196. D3D_WARN(1, "Texture index in a texture stage is greater than number of texture coord in vertex");
  197. }
  198. }
  199. if (!(lpDevI->dwDeviceFlags & D3DDEV_FVF))
  200. {
  201. lpDevI->dwVIDOut = D3DFVF_TLVERTEX;
  202. lpDevI->dwOutputSize = sizeof(D3DTLVERTEX);
  203. }
  204. else
  205. {
  206. if (lpDevI->dwDeviceFlags & D3DDEV_DONOTSTRIPELEMENTS)
  207. { // In this case diffuse, specular and at least one texture
  208. // should present
  209. lpDevI->dwVIDOut = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
  210. if (lpDevI->nTexCoord == 0)
  211. lpDevI->dwVIDOut |= 1 << D3DFVF_TEXCOUNT_SHIFT;
  212. else
  213. lpDevI->dwVIDOut |= lpDevI->nTexCoord << D3DFVF_TEXCOUNT_SHIFT;
  214. }
  215. else
  216. {
  217. lpDevI->dwVIDOut = D3DFVF_XYZRHW;
  218. // If normal present we have to compute specular and duffuse
  219. // Otherwise set these bits the same as input.
  220. // Not that normal should not be present for XYZRHW position type
  221. if (lpDevI->dwVIDIn & D3DFVF_NORMAL)
  222. lpDevI->dwVIDOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
  223. else
  224. lpDevI->dwVIDOut |= lpDevI->dwVIDIn &
  225. (D3DFVF_DIFFUSE | D3DFVF_SPECULAR);
  226. // Always set specular flag if fog is enabled
  227. if (lpDevI->rstates[D3DRENDERSTATE_FOGENABLE])
  228. lpDevI->dwVIDOut |= D3DFVF_SPECULAR;
  229. else
  230. // Clear specular flag if specular disabled
  231. if (!lpDevI->rstates[D3DRENDERSTATE_SPECULARENABLE])
  232. lpDevI->dwVIDOut &= ~D3DFVF_SPECULAR;
  233. lpDevI->dwVIDOut |= lpDevI->nTexCoord << D3DFVF_TEXCOUNT_SHIFT;
  234. }
  235. lpDevI->dwOutputSize = GetVertexSizeFVF(lpDevI->dwVIDOut);
  236. }
  237. lpDevI->dwFVFLastIn = lpDevI->dwVIDIn;
  238. lpDevI->dwFVFLastOut = lpDevI->dwVIDOut;
  239. lpDevI->dwFVFLastOutputSize = lpDevI->dwOutputSize;
  240. lpDevI->dwFVFLastTexCoord = lpDevI->nTexCoord;
  241. return;
  242. }
  243. //---------------------------------------------------------------------
  244. #undef DPF_MODNAME
  245. #define DPF_MODNAME "CheckDeviceSettings"
  246. inline HRESULT CheckDeviceSettings(LPDIRECT3DDEVICEI lpDevI)
  247. {
  248. LPDIRECT3DVIEWPORTI lpView = lpDevI->lpCurrentViewport;
  249. #if DBG
  250. if (!(lpDevI->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE) && IS_DX5_COMPATIBLE_DEVICE(lpDevI))
  251. {
  252. D3D_ERR( "Not in scene" );
  253. return D3DERR_SCENE_NOT_IN_SCENE;
  254. }
  255. if (!lpView)
  256. {
  257. D3D_ERR( "Current viewport not set" );
  258. return D3DERR_INVALIDCURRENTVIEWPORT;
  259. }
  260. if (!lpView->v_data_is_set)
  261. {
  262. D3D_ERR("Viewport data is not set yet");
  263. return D3DERR_VIEWPORTDATANOTSET;
  264. }
  265. if (lpDevI->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INBEGIN)
  266. {
  267. D3D_ERR( "Illegal call between Begin/End" );
  268. return D3DERR_INBEGIN;
  269. }
  270. #endif
  271. // Viewport ID could be different from Device->v_id, because during Execute call
  272. // Device->v_id is changed to whatever viewport is used as a parameter.
  273. // So we have to make sure that we use the right viewport.
  274. //
  275. if (lpDevI->v_id != lpView->v_id)
  276. {
  277. return downloadView(lpView);
  278. }
  279. else
  280. return D3D_OK;
  281. }
  282. //---------------------------------------------------------------------
  283. // Computes the number of primtives and also updates the stats accordingly
  284. // Input: lpDevI->primType
  285. // dwNumVertices
  286. // Output: lpDevI->dwNumPrimitives
  287. // lpDevI->D3DStats
  288. // return value = dwNumPrimitives
  289. #undef DPF_MODNAME
  290. #define DPF_MODNAME "GetNumPrim"
  291. inline DWORD GetNumPrim(LPDIRECT3DDEVICEI lpDevI, DWORD dwNumVertices)
  292. {
  293. lpDevI->dwNumPrimitives = 0;
  294. switch (lpDevI->primType)
  295. {
  296. case D3DPT_POINTLIST:
  297. lpDevI->D3DStats.dwPointsDrawn += lpDevI->dwNumPrimitives = dwNumVertices;
  298. break;
  299. case D3DPT_LINELIST:
  300. lpDevI->D3DStats.dwLinesDrawn += lpDevI->dwNumPrimitives = dwNumVertices >> 1;
  301. break;
  302. case D3DPT_LINESTRIP:
  303. if (dwNumVertices < 2)
  304. return 0;
  305. lpDevI->D3DStats.dwLinesDrawn += lpDevI->dwNumPrimitives = dwNumVertices - 1;
  306. break;
  307. case D3DPT_TRIANGLEFAN:
  308. case D3DPT_TRIANGLESTRIP:
  309. if (dwNumVertices < 3)
  310. return 0;
  311. lpDevI->D3DStats.dwTrianglesDrawn += lpDevI->dwNumPrimitives = dwNumVertices - 2;
  312. break;
  313. case D3DPT_TRIANGLELIST:
  314. #ifdef _X86_
  315. {
  316. DWORD tmp;
  317. __asm
  318. {
  319. mov eax, 0x55555555 // fractional part of 1.0/3.0
  320. mul dwNumVertices
  321. add eax, 0x80000000 // Rounding
  322. adc edx, 0
  323. mov tmp, edx
  324. }
  325. lpDevI->D3DStats.dwTrianglesDrawn += lpDevI->dwNumPrimitives = tmp;
  326. }
  327. #else
  328. lpDevI->D3DStats.dwTrianglesDrawn += lpDevI->dwNumPrimitives = dwNumVertices / 3;
  329. #endif
  330. break;
  331. }
  332. return lpDevI->dwNumPrimitives;
  333. }
  334. //---------------------------------------------------------------------
  335. // Sets front-end flags every time fog state is changed
  336. //
  337. inline void SetFogFlags(LPDIRECT3DDEVICEI lpDevI)
  338. {
  339. if (lpDevI->lighting.fog_mode != D3DFOG_NONE &&
  340. lpDevI->rstates[D3DRENDERSTATE_FOGENABLE])
  341. {
  342. lpDevI->dwFEFlags |= D3DFE_FOG_DIRTY | D3DFE_FOGENABLED;
  343. }
  344. else
  345. lpDevI->dwFEFlags &= ~D3DFE_FOGENABLED;
  346. lpDevI->dwFVFLastIn = 0; // Force re-computing of FVF id
  347. }
  348. //---------------------------------------------------------------------
  349. // Validates DrawPrimitive flags
  350. //
  351. inline BOOL IsDPFlagsValid(DWORD dwFlags)
  352. {
  353. BOOL ret = ((dwFlags & ~(D3DDP_DONOTCLIP | D3DDP_DONOTUPDATEEXTENTS |
  354. D3DDP_WAIT | D3DDP_DONOTLIGHT)
  355. ) == 0);
  356. if (!ret)
  357. {
  358. D3D_ERR( "Invalid bit set in DrawPrimitive flags" );
  359. }
  360. return ret;
  361. }
  362. //---------------------------------------------------------------------
  363. // Allocate memory to hold vertex data, assume all vertices are
  364. // of same size
  365. inline HRESULT CheckVertexBatch(LPDIRECT3DDEVICEI lpDevI)
  366. {
  367. if (!lpDevI->lpvVertexBatch)
  368. {
  369. if (D3DMalloc((void**) &lpDevI->lpvVertexBatch,
  370. BEGIN_DATA_BLOCK_MEM_SIZE))
  371. {
  372. D3D_ERR( "Out of memory" );
  373. return DDERR_OUTOFMEMORY;
  374. }
  375. // Allocate memory to hold index data
  376. if (D3DMalloc((void**) &lpDevI->lpIndexBatch,
  377. BEGIN_DATA_BLOCK_SIZE * sizeof(WORD) * 16))
  378. {
  379. D3DFree( lpDevI->lpvVertexBatch );
  380. D3D_ERR( "Out of memory" );
  381. return DDERR_OUTOFMEMORY;
  382. }
  383. }
  384. return D3D_OK;
  385. }
  386. #endif _DRAWPRIM_H_