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.

2049 lines
78 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: cbhal.cpp
  6. * Content: DrawPrimitive implementation for command buffer HALs
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. #include "drawprim.hpp"
  12. #include "clipfunc.h"
  13. #include "d3dfei.h"
  14. #include "pvvid.h"
  15. #if DBG
  16. // #define VALIDATE_DP2CMD
  17. #endif
  18. extern "C" HRESULT WINAPI
  19. DDInternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID* lpBits );
  20. extern "C" FLATPTR GetAliasedVidMem( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl,
  21. LPDDRAWI_DDRAWSURFACE_LCL surf_lcl,
  22. FLATPTR fpVidMem );
  23. #ifndef WIN95
  24. extern BOOL bVBSwapEnabled, bVBSwapWorkaround;
  25. #endif // WIN95
  26. // Command buffer size tuned to 16K to minimize flushes in Unreal
  27. const DWORD CDirect3DDeviceIDP2::dwD3DDefaultCommandBatchSize = 16384; // * 1 = 16K bytes
  28. inline void CDirect3DDeviceIDP2::ClearBatch(bool bWithinPrimitive)
  29. {
  30. // Reset command buffer
  31. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)lpvDP2Commands;
  32. dwDP2CommandLength = 0;
  33. dp2data.dwCommandOffset = 0;
  34. dp2data.dwCommandLength = 0;
  35. bDP2CurrCmdOP = 0;
  36. // Reset vertex buffer
  37. if (!bWithinPrimitive)
  38. {
  39. dp2data.dwVertexOffset = 0;
  40. this->dwDP2VertexCount = 0;
  41. dwVertexBase = 0;
  42. TLVbuf_Base() = 0;
  43. if (dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES)
  44. {
  45. // We are flushing a user mem primitive.
  46. // We need to clear dp2data.lpUMVertices
  47. // since we are done with it. We replace
  48. // it with TLVbuf.
  49. DDASSERT(lpDP2CurrBatchVBI == NULL);
  50. dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)TLVbuf_GetDDS())->lpLcl;
  51. lpDP2CurrBatchVBI = TLVbuf_GetVBI();
  52. lpDP2CurrBatchVBI->AddRef();
  53. dp2data.dwFlags &= ~D3DHALDP2_USERMEMVERTICES;
  54. }
  55. }
  56. }
  57. #undef DPF_MODNAME
  58. #define DPF_MODNAME "CDirect3DDeviceIDP2::CheckSurfaces()"
  59. HRESULT CDirect3DDeviceIDP2::CheckSurfaces()
  60. {
  61. HRESULT hr;
  62. if(this->lpDirect3DI->lpTextureManager->CheckIfLost())
  63. {
  64. D3D_ERR("Managed Textures lost");
  65. return DDERR_SURFACELOST;
  66. }
  67. if ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl->lpGbl->dwUsageCount ||
  68. (this->lpDDSZBuffer && ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl->lpGbl->dwUsageCount) )
  69. {
  70. D3D_ERR("Render target or Z buffer locked");
  71. return DDERR_SURFACEBUSY;
  72. }
  73. if ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSTarget)->lpLcl->dwFlags & DDRAWISURF_INVALID )\
  74. {
  75. D3D_ERR("Render target buffer lost");
  76. return DDERR_SURFACELOST;
  77. }
  78. if ( this->lpDDSZBuffer && ( ((LPDDRAWI_DDRAWSURFACE_INT) this->lpDDSZBuffer)->lpLcl->dwFlags & DDRAWISURF_INVALID ) )
  79. {
  80. D3D_ERR("Z buffer lost");
  81. return DDERR_SURFACELOST;
  82. }
  83. if (!(this->dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES) && (this->dp2data.lpDDVertex) && (this->dp2data.lpDDVertex->dwFlags & DDRAWISURF_INVALID))
  84. {
  85. D3D_ERR("Vertex buffer lost");
  86. return DDERR_SURFACELOST;
  87. }
  88. if (this->TLVbuf_GetDDS())
  89. {
  90. LPDDRAWI_DDRAWSURFACE_LCL lpLcl = ((LPDDRAWI_DDRAWSURFACE_INT)(this->TLVbuf_GetDDS()))->lpLcl;
  91. if (lpLcl->dwFlags & DDRAWISURF_INVALID)
  92. {
  93. D3D_ERR("Internal vertex buffer lost");
  94. return DDERR_SURFACELOST;
  95. }
  96. }
  97. if (this->dp2data.lpDDCommands->dwFlags & DDRAWISURF_INVALID)
  98. {
  99. D3D_ERR("Command buffer lost");
  100. return DDERR_SURFACELOST;
  101. }
  102. return D3D_OK;
  103. }
  104. #undef DPF_MODNAME
  105. #define DPF_MODNAME "CDirect3DDeviceIDP2::FlushStates(void)"
  106. HRESULT CDirect3DDeviceIDP2::FlushStates(bool bWithinPrimitive)
  107. {
  108. HRESULT dwRet=D3D_OK;
  109. if (dwFlags & D3DPV_WITHINPRIMITIVE)
  110. bWithinPrimitive = true;
  111. if (dwDP2CommandLength) // Do we have some instructions to flush ?
  112. {
  113. CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (ST only).
  114. ++m_qwBatch;
  115. // So that currently bound textures get rebatched
  116. for (DWORD dwStage = 0; dwStage < this->dwMaxTextureBlendStages; dwStage++)
  117. {
  118. LPDIRECT3DTEXTUREI lpTexI = this->lpD3DMappedTexI[dwStage];
  119. if (NULL != lpTexI)
  120. {
  121. if(lpTexI->lpDDS != NULL)
  122. {
  123. BatchTexture(((LPDDRAWI_DDRAWSURFACE_INT)(lpTexI->lpDDS))->lpLcl);
  124. }
  125. }
  126. }
  127. // Check if render target and / or z buffer is lost
  128. if ((dwRet = CheckSurfaces()) != D3D_OK)
  129. { // If lost, we'll just chuck all this work into the bit bucket
  130. ClearBatch(bWithinPrimitive);
  131. if (dwRet == DDERR_SURFACELOST)
  132. {
  133. this->dwFEFlags |= D3DFE_LOSTSURFACES;
  134. dwRet = D3D_OK;
  135. }
  136. }
  137. else
  138. {
  139. // Save since it will get overwritten by ddrval after DDI call
  140. DWORD dwVertexSize = dp2data.dwVertexSize;
  141. dp2data.dwVertexLength = this->dwDP2VertexCount;
  142. dp2data.dwCommandLength = dwDP2CommandLength;
  143. //we clear this to break re-entering as SW rasterizer needs to lock DDRAWSURFACE
  144. dwDP2CommandLength = 0;
  145. // Try and set these 2 values only once during initialization
  146. dp2data.dwhContext = this->dwhContext;
  147. dp2data.lpdwRStates = this->rstates;
  148. DDASSERT(dp2data.dwVertexSize != 0);
  149. D3D_INFO(6, "dwVertexType passed to the driver = 0x%08x", dp2data.dwVertexType);
  150. // If we need the same TLVbuf next time do not swap buffers.
  151. // Save and restore this bit
  152. bool bSwapVB = (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER) != 0;
  153. if (bWithinPrimitive)
  154. {
  155. dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
  156. }
  157. // At the end of the DP2 call we expect the VB to be unlocked if
  158. // 1. We cannot allow the driver to swap the VB
  159. // 2. We are using a VB (not USERMEMVERTICES)
  160. // 3. It is not TLVbuf
  161. // In this case we might as well tell the driver that it is unlocked.
  162. // More importantly, we need to let DDraw know that the VB is unlocked.
  163. if (!(dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER))
  164. {
  165. if ((lpDP2CurrBatchVBI) && (lpDP2CurrBatchVBI != TLVbuf_GetVBI()))
  166. {
  167. lpDP2CurrBatchVBI->UnlockI();
  168. }
  169. }
  170. #ifndef WIN95
  171. else if (bVBSwapWorkaround && lpDP2CurrBatchVBI != 0 && lpDP2CurrBatchVBI == TLVbuf_GetVBI())
  172. {
  173. lpDP2CurrBatchVBI->UnlockWorkAround();
  174. }
  175. if (!bVBSwapEnabled) // Note: bVBSwapEnabled not the same as bSwapVB above.
  176. // bVBSwapEnabled is a global to indicate whether VB
  177. // VB swapping should be turned off due to broken
  178. // Win2K kernel implementation
  179. {
  180. dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
  181. }
  182. if (!dp2data.lpDDCommands->hDDSurface)
  183. CompleteCreateSysmemSurface(dp2data.lpDDCommands);
  184. if (!(dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES )
  185. && !dp2data.lpDDVertex->hDDSurface)
  186. CompleteCreateSysmemSurface(dp2data.lpDDVertex);
  187. #else
  188. // Take Win 16 Lock here
  189. LOCK_HAL( dwRet, this );
  190. #endif //WIN95
  191. // Spin waiting on the driver if wait requested
  192. do {
  193. // Need to set this since the driver may have overwrote it by
  194. // setting ddrval = DDERR_WASSTILLDRAWING
  195. dp2data.dwVertexSize = dwVertexSize;
  196. CALL_HAL3ONLY_NOLOCK(dwRet, this, DrawPrimitives2, &dp2data);
  197. if (dwRet != DDHAL_DRIVER_HANDLED)
  198. {
  199. D3D_ERR ( "Driver not handled in DrawPrimitives2" );
  200. // Need sensible return value in this case,
  201. // currently we return whatever the driver stuck in here.
  202. }
  203. } while (dp2data.ddrval == DDERR_WASSTILLDRAWING);
  204. if (dp2data.ddrval == D3DERR_COMMAND_UNPARSED)
  205. { // This should never occur since the driver must understand
  206. // all the instruction we batch.
  207. D3D_ERR("Driver could not parse this batch!");
  208. dwRet = DDERR_GENERIC; // Some thing better here ?
  209. }
  210. else
  211. {
  212. dwRet= dp2data.ddrval;
  213. // update command buffer pointer
  214. if ((dwRet == D3D_OK) && (dp2data.dwFlags & D3DHALDP2_SWAPCOMMANDBUFFER))
  215. {
  216. #ifdef WIN95
  217. // Get Aliased vid mem pointer if it is a vid mem surf.
  218. if (dp2data.dwFlags & D3DHALDP2_VIDMEMCOMMANDBUF)
  219. {
  220. D3D_INFO(7, "Got back new vid mem command buffer");
  221. FLATPTR paliasbits = GetAliasedVidMem( dp2data.lpDDCommands->lpSurfMore->lpDD_lcl,
  222. dp2data.lpDDCommands, (FLATPTR) dp2data.lpDDCommands->lpGbl->fpVidMem );
  223. if (paliasbits == NULL)
  224. {
  225. DPF_ERR("Could not get Aliased pointer for vid mem command buffer");
  226. // Since we can't use this pointer, set it's size to 0
  227. // That way next time around we will try and allocate a new one
  228. dp2data.lpDDCommands->lpGbl->dwLinearSize = 0;
  229. }
  230. lpvDP2Commands = (LPVOID)paliasbits;
  231. }
  232. else
  233. #endif
  234. {
  235. D3D_INFO(7, "Got back new sys mem command buffer");
  236. lpvDP2Commands = (LPVOID)dp2data.lpDDCommands->lpGbl->fpVidMem;
  237. }
  238. dwDP2CommandBufSize = dp2data.lpDDCommands->lpGbl->dwLinearSize;
  239. }
  240. // update vertex buffer pointer
  241. if ((dwRet == D3D_OK) && (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER) && dp2data.lpDDVertex)
  242. {
  243. FLATPTR paliasbits;
  244. #ifdef WIN95
  245. if (dp2data.dwFlags & D3DHALDP2_VIDMEMVERTEXBUF)
  246. {
  247. paliasbits = GetAliasedVidMem( dp2data.lpDDVertex->lpSurfMore->lpDD_lcl,
  248. dp2data.lpDDVertex, (FLATPTR) dp2data.lpDDVertex->lpGbl->fpVidMem );
  249. if (paliasbits == NULL)
  250. {
  251. DPF_ERR("Could not get Aliased pointer for vid mem vertex buffer");
  252. // Since we can't use this pointer, set it's size to 0
  253. // That way next time around we will try and allocate a new one
  254. dp2data.lpDDVertex->lpGbl->dwLinearSize = 0;
  255. }
  256. }
  257. else
  258. #endif
  259. {
  260. paliasbits = dp2data.lpDDVertex->lpGbl->fpVidMem;
  261. }
  262. if (lpDP2CurrBatchVBI == TLVbuf_GetVBI())
  263. {
  264. #if DBG
  265. if(this->alignedBuf != (VOID*)paliasbits)
  266. {
  267. D3D_INFO(2, "Driver swapped TLVBuf pointer in FlushStates");
  268. }
  269. #endif //DBG
  270. this->alignedBuf = (LPVOID)paliasbits;
  271. this->TLVbuf_size = dp2data.lpDDVertex->lpGbl->dwLinearSize;
  272. }
  273. else
  274. {
  275. #if DBG
  276. if(this->lpDP2CurrBatchVBI->position.lpvData != (VOID*)paliasbits)
  277. {
  278. D3D_INFO(2, "Driver swapped VB pointer in FlushStates");
  279. }
  280. #endif //DBG
  281. this->lpDP2CurrBatchVBI->position.lpvData = (LPVOID)paliasbits;
  282. }
  283. }
  284. }
  285. #ifdef WIN95
  286. // Release Win16 Lock here
  287. UNLOCK_HAL( this );
  288. #else
  289. if (!bWithinPrimitive && bSwapVB && bVBSwapWorkaround && lpDP2CurrBatchVBI != 0 && lpDP2CurrBatchVBI == TLVbuf_GetVBI())
  290. {
  291. HRESULT hr = lpDP2CurrBatchVBI->LockWorkAround(this);
  292. if (FAILED(hr))
  293. {
  294. TLVbuf_base = 0;
  295. TLVbuf_size = 0;
  296. D3D_ERR("Driver failed Lock in FlushStates");
  297. if (SUCCEEDED(dwRet))
  298. {
  299. dwRet = hr;
  300. }
  301. }
  302. }
  303. #endif
  304. // Restore flag if necessary
  305. if (bSwapVB)
  306. dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
  307. // Restore to value before the DDI call
  308. dp2data.dwVertexSize = dwVertexSize;
  309. ClearBatch(bWithinPrimitive);
  310. }
  311. }
  312. // There are situations when the command stream has no data, but there is data in
  313. // the vertex pool. This could happen, for instance if every triangle got rejected
  314. // while clipping. In this case we still need to "Flush out" the vertex data.
  315. else if (dp2data.dwCommandLength == 0)
  316. {
  317. ClearBatch(bWithinPrimitive);
  318. }
  319. return dwRet;
  320. }
  321. #undef DPF_MODNAME
  322. #define DPF_MODNAME "CDirect3DDeviceIDP2::FlushStates(DWORD)"
  323. HRESULT CDirect3DDeviceIDP2::FlushStatesReq(DWORD dwReqSize)
  324. {
  325. DWORD sav = (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER);
  326. dp2data.dwReqVertexBufSize = dwReqSize;
  327. dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQVERTEXBUFSIZE;
  328. HRESULT ret = FlushStates();
  329. dp2data.dwFlags &= ~(D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQVERTEXBUFSIZE);
  330. dp2data.dwFlags |= sav;
  331. return ret;
  332. }
  333. #undef DPF_MODNAME
  334. #define DPF_MODNAME "CDirect3DDeviceIDP2::GrowCommandBuffer"
  335. // Check and grow command buffer
  336. HRESULT CDirect3DDeviceIDP2::GrowCommandBuffer(LPDIRECT3DI lpD3DI, DWORD dwSize)
  337. {
  338. HRESULT ret;
  339. if (dwSize > dwDP2CommandBufSize)
  340. {
  341. if (lpDDSCB1)
  342. {
  343. lpDDSCB1->Release();
  344. lpDDSCB1 = NULL;
  345. }
  346. // Create command buffer through DirectDraw
  347. DDSURFACEDESC2 ddsd;
  348. memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
  349. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  350. ddsd.dwFlags = DDSD_WIDTH | DDSD_CAPS;
  351. ddsd.dwWidth = dwSize;
  352. ddsd.ddsCaps.dwCaps = DDSCAPS_EXECUTEBUFFER;
  353. if (IS_HW_DEVICE(this))
  354. ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  355. else
  356. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  357. ddsd.ddsCaps.dwCaps2 = DDSCAPS2_COMMANDBUFFER;
  358. // Try explicit video memory first
  359. D3D_INFO(7, "Trying to create a vid mem command buffer");
  360. ret = lpD3DI->lpDD7->CreateSurface(&ddsd, &lpDDSCB1, NULL);
  361. if (ret != DD_OK)
  362. {
  363. // If that failed, try explicit system memory
  364. ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
  365. ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  366. D3D_INFO(7, "Trying to create a sys mem command buffer");
  367. ret = lpD3DI->lpDD7->CreateSurface(&ddsd, &lpDDSCB1, NULL);
  368. if (ret != DD_OK)
  369. {
  370. D3D_ERR("failed to allocate Command Buffer 1");
  371. dwDP2CommandBufSize = 0;
  372. return ret;
  373. }
  374. }
  375. // Lock command buffer
  376. ret = lpDDSCB1->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL);
  377. if (ret != DD_OK)
  378. {
  379. D3D_ERR("Could not lock command buffer.");
  380. lpDDSCB1->Release();
  381. lpDDSCB1 = NULL;
  382. dwDP2CommandBufSize = 0;
  383. return ret;
  384. }
  385. // update command buffer pointer
  386. lpvDP2Commands = ddsd.lpSurface;
  387. dp2data.lpDDCommands = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSCB1)->lpLcl;
  388. dwDP2CommandBufSize = dwSize;
  389. }
  390. return D3D_OK;
  391. }
  392. #undef DPF_MODNAME
  393. #define DPF_MODNAME "CDirect3DDeviceIDP2::Init"
  394. HRESULT CDirect3DDeviceIDP2::Init(REFCLSID riid, LPDIRECT3DI lpD3DI, LPDIRECTDRAWSURFACE lpDDS,
  395. IUnknown* pUnkOuter, LPUNKNOWN* lplpD3DDevice)
  396. {
  397. dwDP2CommandBufSize = 0;
  398. dwDP2Flags =0;
  399. lpDDSCB1 = NULL;
  400. lpvDP2Commands = NULL;
  401. TLVbuf_size = 0;
  402. allocatedBuf = 0;
  403. alignedBuf = 0;
  404. TLVbuf_base = 0;
  405. dwTLVbufChanges = 0;
  406. pNullVB = NULL;
  407. // We do this early in case of DP2 since GrowCommandBuffer depends on this check
  408. if (IsEqualIID(riid, IID_IDirect3DHALDevice) || IsEqualIID(riid, IID_IDirect3DTnLHalDevice))
  409. {
  410. this->dwFEFlags |= D3DFE_REALHAL;
  411. }
  412. HRESULT ret = GrowCommandBuffer(lpD3DI, dwD3DDefaultCommandBatchSize);
  413. if (ret != D3D_OK)
  414. return ret;
  415. // Fill the dp2data structure with initial values
  416. dp2data.dwFlags = D3DHALDP2_SWAPCOMMANDBUFFER;
  417. dp2data.dwVertexType = D3DFVF_TLVERTEX; // Initial assumption
  418. dp2data.dwVertexSize = sizeof(D3DTLVERTEX); // Initial assumption
  419. ClearBatch(false);
  420. // Initialize the DDI independent part of the device
  421. ret = DIRECT3DDEVICEI::Init(riid, lpD3DI, lpDDS, pUnkOuter, lplpD3DDevice);
  422. if (ret != D3D_OK)
  423. {
  424. return ret;
  425. }
  426. // Since we plan to call TLV_Grow for the first time with "true"
  427. this->dwDeviceFlags |= D3DDEV_TLVBUFWRITEONLY;
  428. if (TLVbuf_Grow((__INIT_VERTEX_NUMBER*2)*sizeof(D3DTLVERTEX), true) != DD_OK)
  429. {
  430. D3D_ERR( "Out of memory in DeviceCreate (TLVbuf)" );
  431. return DDERR_OUTOFMEMORY;
  432. }
  433. D3DVERTEXBUFFERDESC vbdesc;
  434. vbdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
  435. vbdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
  436. vbdesc.dwFVF = D3DFVF_TLVERTEX;
  437. vbdesc.dwNumVertices = 1;
  438. ret = this->lpDirect3DI->CreateVertexBufferI(&vbdesc, &this->pNullVB, 0);
  439. if (ret != DD_OK)
  440. {
  441. return ret;
  442. }
  443. #ifdef VTABLE_HACK
  444. if (!IS_MT_DEVICE(this))
  445. {
  446. // Make SetRS point to execute mode
  447. VtblSetRenderStateExecute();
  448. VtblSetTextureStageStateExecute();
  449. VtblSetTextureExecute();
  450. VtblApplyStateBlockExecute();
  451. }
  452. #endif
  453. return ret;
  454. }
  455. #undef DPF_MODNAME
  456. #define DPF_MODNAME "CDirect3DDeviceIDP2::~CDirect3DDeviceIDP2"
  457. CDirect3DDeviceIDP2::~CDirect3DDeviceIDP2()
  458. {
  459. CleanupTextures();
  460. if (pNullVB)
  461. pNullVB->Release();
  462. if (allocatedBuf)
  463. allocatedBuf->Release();
  464. if (lpDDSCB1)
  465. lpDDSCB1->Release();
  466. if (lpDP2CurrBatchVBI)
  467. {
  468. lpDP2CurrBatchVBI->lpDevIBatched = NULL;
  469. lpDP2CurrBatchVBI->Release();
  470. }
  471. }
  472. #undef DPF_MODNAME
  473. #define DPF_MODNAME "CDirect3DDeviceIDP2::SetRenderStateI"
  474. HRESULT CDirect3DDeviceIDP2::SetRenderStateI(D3DRENDERSTATETYPE dwStateType,
  475. DWORD value)
  476. {
  477. HRESULT ret = D3D_OK;
  478. if (bDP2CurrCmdOP == D3DDP2OP_RENDERSTATE)
  479. { // Last instruction is a renderstate, append this one to it
  480. if (dwDP2CommandLength + sizeof(D3DHAL_DP2RENDERSTATE) <= dwDP2CommandBufSize)
  481. {
  482. LPD3DHAL_DP2RENDERSTATE lpRState = (LPD3DHAL_DP2RENDERSTATE)((LPBYTE)lpvDP2Commands +
  483. dwDP2CommandLength + dp2data.dwCommandOffset);
  484. lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
  485. lpRState->RenderState = dwStateType;
  486. lpRState->dwState = value;
  487. dwDP2CommandLength += sizeof(D3DHAL_DP2RENDERSTATE);
  488. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  489. return ret;
  490. }
  491. }
  492. // Check for space
  493. if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  494. sizeof(D3DHAL_DP2RENDERSTATE) > dwDP2CommandBufSize)
  495. {
  496. ret = FlushStates();
  497. // Since we ran out of space, we were not able to put (dwStateType, value)
  498. // into the batch so rstates will reflect only the last batched
  499. // renderstate (since the driver updates rstates from the batch).
  500. // To fix this, we simply put the current (dwStateType, value) into rstates.
  501. this->rstates[dwStateType]=value;
  502. if (ret != D3D_OK)
  503. {
  504. D3D_ERR("Error trying to render batched commands in SetRenderStateI");
  505. return ret;
  506. }
  507. }
  508. // Add new renderstate instruction
  509. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  510. dwDP2CommandLength + dp2data.dwCommandOffset);
  511. lpDP2CurrCommand->bCommand = D3DDP2OP_RENDERSTATE;
  512. bDP2CurrCmdOP = D3DDP2OP_RENDERSTATE;
  513. lpDP2CurrCommand->bReserved = 0;
  514. lpDP2CurrCommand->wStateCount = 1;
  515. wDP2CurrCmdCnt = 1;
  516. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  517. // Add renderstate data
  518. LPD3DHAL_DP2RENDERSTATE lpRState = (LPD3DHAL_DP2RENDERSTATE)(lpDP2CurrCommand + 1);
  519. lpRState->RenderState = dwStateType;
  520. lpRState->dwState = value;
  521. dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2RENDERSTATE);
  522. return ret;
  523. }
  524. // Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION
  525. const iprim2cmdop[] = {
  526. 0, // Invalid
  527. 0, // Points are invalid too
  528. D3DDP2OP_INDEXEDLINELIST2,
  529. D3DDP2OP_INDEXEDLINESTRIP,
  530. D3DDP2OP_INDEXEDTRIANGLELIST2,
  531. D3DDP2OP_INDEXEDTRIANGLESTRIP,
  532. D3DDP2OP_INDEXEDTRIANGLEFAN
  533. };
  534. #undef DPF_MODNAME
  535. #define DPF_MODNAME "CDirect3DDeviceIDP2::DrawIndexPrim"
  536. //---------------------------------------------------------------------
  537. //
  538. // The vertices are already in the vertex buffer.
  539. //
  540. HRESULT CDirect3DDeviceIDP2::DrawIndexPrim()
  541. {
  542. HRESULT ret = D3D_OK;
  543. DWORD dwByteCount; // Command length plus indices
  544. DWORD dwIndicesByteCount; // Indices only
  545. if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
  546. {
  547. ret = UpdateTextures();
  548. if(ret != D3D_OK)
  549. {
  550. D3D_ERR("UpdateTextures failed. Device probably doesn't support current texture (check return code).");
  551. return ret;
  552. }
  553. this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
  554. }
  555. dwIndicesByteCount = sizeof(WORD) * this->dwNumIndices;
  556. dwByteCount = dwIndicesByteCount + sizeof(D3DHAL_DP2COMMAND) +
  557. sizeof(D3DHAL_DP2STARTVERTEX);
  558. if (dwDP2CommandLength + dwByteCount > dwDP2CommandBufSize)
  559. {
  560. // Request the driver to grow the command buffer upon flush
  561. dp2data.dwReqCommandBufSize = dwByteCount;
  562. dp2data.dwFlags |= D3DHALDP2_REQCOMMANDBUFSIZE;
  563. ret = FlushStates(true);
  564. dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE;
  565. if (ret != D3D_OK)
  566. return ret;
  567. // Check if the driver did give us what we need or do it ourselves
  568. ret = GrowCommandBuffer(this->lpDirect3DI, dwByteCount);
  569. if (ret != D3D_OK)
  570. {
  571. D3D_ERR("Could not grow Command Buffer");
  572. return ret;
  573. }
  574. }
  575. // Insert indexed primitive instruction
  576. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  577. dwDP2CommandLength + dp2data.dwCommandOffset);
  578. lpDP2CurrCommand->bReserved = 0;
  579. lpDP2CurrCommand->wPrimitiveCount = (WORD)this->dwNumPrimitives;
  580. LPBYTE pIndices = (BYTE*)(lpDP2CurrCommand + 1); // Place for indices
  581. lpDP2CurrCommand->bCommand = (BYTE)iprim2cmdop[this->primType];
  582. ((LPD3DHAL_DP2STARTVERTEX)(lpDP2CurrCommand+1))->wVStart =
  583. (WORD)this->dwVertexBase;
  584. pIndices += sizeof(D3DHAL_DP2STARTVERTEX);
  585. #if DBG
  586. if (lpDP2CurrCommand->bCommand == 0)
  587. {
  588. D3D_ERR("Illegal primitive type");
  589. return DDERR_GENERIC;
  590. }
  591. #endif
  592. bDP2CurrCmdOP = lpDP2CurrCommand->bCommand;
  593. memcpy(pIndices, this->lpwIndices, dwIndicesByteCount);
  594. wDP2CurrCmdCnt = lpDP2CurrCommand->wPrimitiveCount;
  595. dwDP2CommandLength += dwByteCount;
  596. return ret;
  597. }
  598. // Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION
  599. const prim2cmdop[] = {
  600. 0, // Invalid
  601. D3DDP2OP_POINTS,
  602. D3DDP2OP_LINELIST,
  603. D3DDP2OP_LINESTRIP,
  604. D3DDP2OP_TRIANGLELIST,
  605. D3DDP2OP_TRIANGLESTRIP,
  606. D3DDP2OP_TRIANGLEFAN
  607. };
  608. // Map D3DPRIMITIVETYPE to bytes needed in command stream
  609. const prim2cmdsz[] = {
  610. 0, // Invalid
  611. sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2POINTS),
  612. sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2LINELIST),
  613. sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2LINESTRIP),
  614. sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLELIST),
  615. sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLESTRIP),
  616. sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLEFAN)
  617. };
  618. #undef DPF_MODNAME
  619. #define DPF_MODNAME "CDirect3DDeviceIDP2::DrawClippedPrim"
  620. //---------------------------------------------------------------------
  621. // This primitive is generated by the clipper.
  622. // The vertices of this primitive are pointed to by the
  623. // lpvOut member, which need to be copied into the
  624. // command stream immediately after the command itself.
  625. HRESULT CDirect3DDeviceIDP2::DrawClippedPrim()
  626. {
  627. HRESULT ret = D3D_OK;
  628. if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
  629. {
  630. ret = UpdateTextures();
  631. if(ret != D3D_OK)
  632. {
  633. D3D_ERR("UpdateTextures failed. Device probably doesn't support current texture (check return code).");
  634. return ret;
  635. }
  636. this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
  637. }
  638. DWORD dwExtra = 0;
  639. LPVOID lpvVerticesImm; // Place for vertices
  640. DWORD dwVertexPoolSize = this->dwNumVertices * this->dwOutputSize;
  641. if (this->primType == D3DPT_TRIANGLEFAN)
  642. {
  643. if (rstates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME &&
  644. this->dwFlags & D3DPV_NONCLIPPED)
  645. {
  646. // For unclipped (but pretended to be clipped) tri fans in
  647. // wireframe mode we generate 3-vertex tri fans to enable drawing of
  648. // interior edges
  649. BYTE vertices[__MAX_VERTEX_SIZE*3];
  650. BYTE *pV1 = vertices + this->dwOutputSize;
  651. BYTE *pV2 = pV1 + this->dwOutputSize;
  652. BYTE *pInput = (BYTE*)this->lpvOut;
  653. memcpy(vertices, pInput, this->dwOutputSize);
  654. pInput += this->dwOutputSize;
  655. const DWORD nTriangles = this->dwNumVertices - 2;
  656. this->dwNumVertices = 3;
  657. this->dwNumPrimitives = 1;
  658. this->lpvOut = vertices;
  659. this->dwFlags &= ~D3DPV_NONCLIPPED; // Remove this flag for recursive call
  660. for (DWORD i = nTriangles; i; i--)
  661. {
  662. memcpy(pV1, pInput, this->dwOutputSize);
  663. memcpy(pV2, pInput+this->dwOutputSize, this->dwOutputSize);
  664. pInput += this->dwOutputSize;
  665. // To enable all edge flag we set the fill mode to SOLID.
  666. // This will prevent checking the clip flags in the clipper state.
  667. rstates[D3DRENDERSTATE_FILLMODE] = D3DFILL_SOLID;
  668. ret = DrawClippedPrim();
  669. rstates[D3DRENDERSTATE_FILLMODE] = D3DFILL_WIREFRAME;
  670. if (ret != D3D_OK)
  671. return ret;
  672. }
  673. return D3D_OK;
  674. }
  675. dwExtra = sizeof(D3DHAL_DP2TRIANGLEFAN_IMM);
  676. }
  677. DWORD dwPad = (sizeof(D3DHAL_DP2COMMAND) + dwDP2CommandLength + dwExtra) & 3;
  678. DWORD dwByteCount = sizeof(D3DHAL_DP2COMMAND) + dwPad + dwExtra + dwVertexPoolSize;
  679. // Check for space in the command buffer for commands & vertices
  680. if (dwDP2CommandLength + dwByteCount > dwDP2CommandBufSize)
  681. {
  682. // Flush the current batch but hold on to the vertices
  683. ret = FlushStates(true);
  684. if (ret != D3D_OK)
  685. return ret;
  686. if (dwByteCount > dwDP2CommandBufSize)
  687. {
  688. ret = GrowCommandBuffer(this->lpDirect3DI, dwByteCount);
  689. if (ret != D3D_OK)
  690. {
  691. D3D_ERR("Could not grow Command Buffer");
  692. return ret;
  693. }
  694. }
  695. dwPad = (sizeof(D3DHAL_DP2COMMAND) + dwExtra) & 3;
  696. dwByteCount = sizeof(D3DHAL_DP2COMMAND) + dwExtra + dwPad + dwVertexPoolSize;
  697. }
  698. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  699. dwDP2CommandLength + dp2data.dwCommandOffset);
  700. lpDP2CurrCommand->wPrimitiveCount = (WORD)this->dwNumPrimitives;
  701. lpDP2CurrCommand->bReserved = 0;
  702. if (this->primType == D3DPT_TRIANGLEFAN)
  703. {
  704. // Insert inline instruction and vertices
  705. bDP2CurrCmdOP = D3DDP2OP_TRIANGLEFAN_IMM;
  706. lpDP2CurrCommand->bCommand = bDP2CurrCmdOP;
  707. LPD3DHAL_DP2TRIANGLEFAN_IMM lpTriFanImm = (LPD3DHAL_DP2TRIANGLEFAN_IMM)(lpDP2CurrCommand + 1);
  708. if (rstates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME)
  709. {
  710. lpTriFanImm->dwEdgeFlags = 0;
  711. ClipVertex **clip = this->ClipperState.current_vbuf;
  712. // Look at the exterior edges and mark the visible ones
  713. for(DWORD i = 0; i < this->dwNumVertices; ++i)
  714. {
  715. if (clip[i]->clip & CLIPPED_ENABLE)
  716. lpTriFanImm->dwEdgeFlags |= (1 << i);
  717. }
  718. }
  719. else
  720. {
  721. // Mark all exterior edges visible
  722. lpTriFanImm->dwEdgeFlags = 0xFFFFFFFF;
  723. }
  724. lpvVerticesImm = (LPBYTE)(lpTriFanImm + 1) + dwPad;
  725. }
  726. else
  727. {
  728. // Insert inline instruction and vertices
  729. bDP2CurrCmdOP = D3DDP2OP_LINELIST_IMM;
  730. lpDP2CurrCommand->bCommand = bDP2CurrCmdOP;
  731. lpvVerticesImm = (LPBYTE)(lpDP2CurrCommand + 1) + dwPad;
  732. }
  733. memcpy(lpvVerticesImm, this->lpvOut, dwVertexPoolSize);
  734. dwDP2CommandLength += dwByteCount;
  735. return ret;
  736. }
  737. //---------------------------------------------------------------------
  738. HRESULT CDirect3DDeviceIDP2::DrawPrim()
  739. {
  740. HRESULT ret = D3D_OK;
  741. if(this->dwFEFlags & D3DFE_NEED_TEXTURE_UPDATE)
  742. {
  743. ret = UpdateTextures();
  744. if(ret != D3D_OK)
  745. {
  746. D3D_ERR("UpdateTextures failed. Device probably doesn't support current texture (check return code).");
  747. return ret;
  748. }
  749. this->dwFEFlags &= ~D3DFE_NEED_TEXTURE_UPDATE;
  750. }
  751. // Check for space in the command buffer for new command.
  752. // The vertices are already in the vertex buffer.
  753. if (dwDP2CommandLength + prim2cmdsz[this->primType] > dwDP2CommandBufSize)
  754. {
  755. ret = FlushStates(true);
  756. if (ret != D3D_OK)
  757. return ret;
  758. }
  759. // Insert non indexed primitive instruction
  760. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  761. dwDP2CommandLength + dp2data.dwCommandOffset);
  762. bDP2CurrCmdOP = (BYTE)prim2cmdop[this->primType];
  763. lpDP2CurrCommand->bCommand = bDP2CurrCmdOP;
  764. lpDP2CurrCommand->bReserved = 0;
  765. if (bDP2CurrCmdOP == D3DDP2OP_POINTS)
  766. {
  767. wDP2CurrCmdCnt = 1;
  768. LPD3DHAL_DP2POINTS lpPoints = (LPD3DHAL_DP2POINTS)(lpDP2CurrCommand + 1);
  769. lpPoints->wCount = (WORD)this->dwNumVertices;
  770. lpPoints->wVStart = (WORD)this->dwVertexBase;
  771. }
  772. else
  773. {
  774. // Linestrip, trianglestrip, trianglefan, linelist and trianglelist are identical
  775. wDP2CurrCmdCnt = (WORD)this->dwNumPrimitives;
  776. LPD3DHAL_DP2LINESTRIP lpStrip = (LPD3DHAL_DP2LINESTRIP)(lpDP2CurrCommand + 1);
  777. lpStrip->wVStart = (WORD)this->dwVertexBase;
  778. }
  779. lpDP2CurrCommand->wPrimitiveCount = wDP2CurrCmdCnt;
  780. dwDP2CommandLength += prim2cmdsz[this->primType];
  781. #ifdef VALIDATE_DP2CMD
  782. ValidateCommand(lpDP2CurrCommand);
  783. #endif
  784. return ret;
  785. }
  786. #undef DPF_MODNAME
  787. #define DPF_MODNAME "CDirect3DDeviceIDP2::SetTSSI"
  788. HRESULT CDirect3DDeviceIDP2::SetTSSI(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue)
  789. {
  790. HRESULT ret = D3D_OK;
  791. // Filter unsupported states
  792. if (dwState >= m_tssMax)
  793. return D3D_OK;
  794. if (bDP2CurrCmdOP == D3DDP2OP_TEXTURESTAGESTATE)
  795. { // Last instruction is a texture stage state, append this one to it
  796. if (dwDP2CommandLength + sizeof(D3DHAL_DP2TEXTURESTAGESTATE) <= dwDP2CommandBufSize)
  797. {
  798. LPD3DHAL_DP2TEXTURESTAGESTATE lpRState = (LPD3DHAL_DP2TEXTURESTAGESTATE)((LPBYTE)lpvDP2Commands +
  799. dwDP2CommandLength + dp2data.dwCommandOffset);
  800. lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
  801. lpRState->wStage = (WORD)dwStage;
  802. lpRState->TSState = (WORD)dwState;
  803. lpRState->dwValue = dwValue;
  804. dwDP2CommandLength += sizeof(D3DHAL_DP2TEXTURESTAGESTATE);
  805. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  806. return ret;
  807. }
  808. }
  809. // Check for space
  810. if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  811. sizeof(D3DHAL_DP2TEXTURESTAGESTATE) > dwDP2CommandBufSize)
  812. {
  813. ret = FlushStates();
  814. if (ret != D3D_OK)
  815. {
  816. D3D_ERR("Error trying to render batched commands in SetTSSI");
  817. return ret;
  818. }
  819. }
  820. // Add new renderstate instruction
  821. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  822. dwDP2CommandLength + dp2data.dwCommandOffset);
  823. lpDP2CurrCommand->bCommand = D3DDP2OP_TEXTURESTAGESTATE;
  824. bDP2CurrCmdOP = D3DDP2OP_TEXTURESTAGESTATE;
  825. lpDP2CurrCommand->bReserved = 0;
  826. lpDP2CurrCommand->wStateCount = 1;
  827. wDP2CurrCmdCnt = 1;
  828. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  829. // Add renderstate data
  830. LPD3DHAL_DP2TEXTURESTAGESTATE lpRState = (LPD3DHAL_DP2TEXTURESTAGESTATE)(lpDP2CurrCommand + 1);
  831. lpRState->wStage = (WORD)dwStage;
  832. lpRState->TSState = (WORD)dwState;
  833. lpRState->dwValue = dwValue;
  834. dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXTURESTAGESTATE);
  835. return ret;
  836. }
  837. #undef DPF_MODNAME
  838. #define DPF_MODNAME "CDirect3DDeviceIDP2::ValidateDevice"
  839. HRESULT D3DAPI
  840. CDirect3DDeviceIDP2::ValidateDevice(LPDWORD lpdwNumPasses)
  841. {
  842. try
  843. {
  844. // Holds D3D lock until exit.
  845. CLockD3DMT ldmLock(this, DPF_MODNAME, REMIND(""));
  846. HRESULT ret;
  847. D3DHAL_VALIDATETEXTURESTAGESTATEDATA vbod;
  848. if (!VALID_DIRECT3DDEVICE_PTR(this))
  849. {
  850. D3D_ERR( "Invalid Direct3DDevice7 pointer" );
  851. return DDERR_INVALIDOBJECT;
  852. }
  853. if (!VALID_PTR(lpdwNumPasses, sizeof(DWORD)))
  854. {
  855. D3D_ERR( "Invalid lpdwNumPasses pointer" );
  856. return DDERR_INVALIDPARAMS;
  857. }
  858. // First, Update textures since drivers pass /fail this call based
  859. // on the current texture handles
  860. ret = UpdateTextures();
  861. if (ret != D3D_OK)
  862. {
  863. D3D_ERR("Error trying to update managed textures in ValidateDevice");
  864. return ret;
  865. }
  866. // First, flush states, so we can validate the current state
  867. ret = FlushStates();
  868. if (ret != D3D_OK)
  869. {
  870. D3D_ERR("Error trying to FlushStates in ValidateDevice");
  871. return ret;
  872. }
  873. // Now ask the driver!
  874. *lpdwNumPasses = 0;
  875. memset(&vbod, 0, sizeof(D3DHAL_VALIDATETEXTURESTAGESTATEDATA));
  876. vbod.dwhContext = this->dwhContext;
  877. if (this->lpD3DHALCallbacks3->ValidateTextureStageState)
  878. {
  879. CALL_HAL3ONLY(ret, this, ValidateTextureStageState, &vbod);
  880. if (ret != DDHAL_DRIVER_HANDLED)
  881. return DDERR_UNSUPPORTED;
  882. *lpdwNumPasses = vbod.dwNumPasses;
  883. return vbod.ddrval;
  884. }
  885. else
  886. {
  887. D3D_ERR("Error: ValidateTextureStageState not supported by the driver.");
  888. }
  889. return DDERR_UNSUPPORTED;
  890. }
  891. catch (HRESULT ret)
  892. {
  893. return ret;
  894. }
  895. }
  896. #undef DPF_MODNAME
  897. #define DPF_MODNAME "CDirect3DDeviceIDP2::StartPrimVB"
  898. //---------------------------------------------------------------------
  899. // This function prepares the batch for new primitive.
  900. // Called only if vertices from user memory are NOT used for rendering
  901. //
  902. HRESULT CDirect3DDeviceIDP2::StartPrimVB(LPDIRECT3DVERTEXBUFFERI lpVBI,
  903. DWORD dwStartVertex)
  904. {
  905. HRESULT ret = D3D_OK;
  906. // If VID has been changed or new vertex buffer is used we flush the batch
  907. if (this->dwVIDOut != dp2data.dwVertexType ||
  908. lpDP2CurrBatchVBI != lpVBI ||
  909. dp2data.lpDDVertex != ((LPDDRAWI_DDRAWSURFACE_INT)(lpVBI->GetDDS()))->lpLcl)
  910. {
  911. ret = FlushStates();
  912. if (ret != D3D_OK)
  913. return ret;
  914. dp2data.dwVertexType = this->dwVIDOut;
  915. dp2data.dwVertexSize = this->dwOutputSize;
  916. dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)(lpVBI->GetDDS()))->lpLcl;
  917. // Release previously used vertex buffer (if any), because we do not
  918. // need it any more. We did AddRef() to TL buffer, so it is safe.
  919. if (lpDP2CurrBatchVBI)
  920. {
  921. lpDP2CurrBatchVBI->lpDevIBatched = NULL;
  922. lpDP2CurrBatchVBI->Release();
  923. }
  924. // If a vertex buffer is used for rendering, make sure that it is not
  925. // released by user. So do AddRef().
  926. lpDP2CurrBatchVBI = lpVBI;
  927. lpDP2CurrBatchVBI->AddRef();
  928. }
  929. if (this->TLVbuf_GetVBI() == lpVBI)
  930. {
  931. this->dwVertexBase = this->dwDP2VertexCount;
  932. DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES);
  933. dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER;
  934. this->dwDP2VertexCount = this->dwVertexBase + this->dwNumVertices;
  935. #ifdef VTABLE_HACK
  936. VtblDrawPrimitiveVBDefault();
  937. VtblDrawIndexedPrimitiveVBDefault();
  938. #endif VTABLE_HACK
  939. }
  940. else
  941. {
  942. this->dwVertexBase = dwStartVertex;
  943. dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
  944. this->dwDP2VertexCount = max(this->dwDP2VertexCount, this->dwVertexBase + this->dwNumVertices);
  945. #ifdef VTABLE_HACK
  946. VtblDrawPrimitiveDefault();
  947. VtblDrawIndexedPrimitiveDefault();
  948. #endif VTABLE_HACK
  949. }
  950. return ret;
  951. }
  952. #undef DPF_MODNAME
  953. #define DPF_MODNAME "CDirect3DDeviceIDP2::StartPrimUserMem"
  954. //---------------------------------------------------------------------
  955. // This function prepares the batch for new primitive.
  956. // Called if vertices from user memory is used for rendering
  957. //
  958. HRESULT CDirect3DDeviceIDP2::StartPrimUserMem(LPVOID lpMem)
  959. {
  960. HRESULT ret = D3D_OK;
  961. // We fail vid mem VB for clipping
  962. bool bWriteOnly = ((this->dwDeviceFlags & D3DDEV_DONOTCLIP) || IS_TLHAL_DEVICE(this))!=0;
  963. // If the primitive is small, we copy vertices into the TL buffer
  964. // ATTENTION: Dont do this if the device is a TL device ?
  965. if (this->dwNumVertices < LOWVERTICESNUMBER)
  966. {
  967. if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
  968. {
  969. if (this->TLVbuf_Grow(this->dwVertexPoolSize, bWriteOnly) != D3D_OK)
  970. {
  971. D3D_ERR( "Could not grow TL vertex buffer" );
  972. return DDERR_OUTOFMEMORY;
  973. }
  974. }
  975. // So now user memory is not used any more.
  976. ret = StartPrimVB(this->TLVbuf_GetVBI(), 0);
  977. if (ret != D3D_OK)
  978. return ret;
  979. LPVOID tmp = this->TLVbuf_GetAddress();
  980. memcpy(tmp, this->lpvOut, this->dwVertexPoolSize);
  981. // We have to update lpvOut, because it was set to user memory
  982. this->lpvOut = tmp;
  983. }
  984. else
  985. {
  986. // We can not mix user memory primitive with other primitives, so
  987. // flush the batch.
  988. // Do not forget to flush the batch after rendering this primitive
  989. ret = this->FlushStates();
  990. if (ret != D3D_OK)
  991. return ret;
  992. // Release previously used vertex buffer (if any), because we do not
  993. // it any more
  994. if (lpDP2CurrBatchVBI)
  995. {
  996. lpDP2CurrBatchVBI->lpDevIBatched = NULL;
  997. lpDP2CurrBatchVBI->Release();
  998. lpDP2CurrBatchVBI = NULL;
  999. #ifdef VTABLE_HACK
  1000. VtblDrawPrimitiveVBDefault();
  1001. VtblDrawIndexedPrimitiveVBDefault();
  1002. VtblDrawPrimitiveDefault();
  1003. VtblDrawIndexedPrimitiveDefault();
  1004. #endif VTABLE_HACK
  1005. }
  1006. dp2data.dwVertexType = this->dwVIDOut;
  1007. dp2data.dwVertexSize = this->dwOutputSize;
  1008. dp2data.lpVertices = lpMem;
  1009. dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES;
  1010. dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER;
  1011. this->dwDP2VertexCount = this->dwNumVertices;
  1012. this->dwFlags |= D3DPV_USERMEMVERTICES;
  1013. }
  1014. return ret;
  1015. }
  1016. #undef DPF_MODNAME
  1017. #define DPF_MODNAME "CDirect3DDeviceIDP2::EndPrim"
  1018. //---------------------------------------------------------------------
  1019. // This function should not be called from DrawVertexBufferVB
  1020. //
  1021. HRESULT CDirect3DDeviceIDP2::EndPrim()
  1022. {
  1023. HRESULT ret = D3D_OK;
  1024. if (this->dwFlags & D3DPV_USERMEMVERTICES)
  1025. // We can not mix user memory primitive, so flush it.
  1026. ret = this->FlushStates();
  1027. else
  1028. {
  1029. // If TL buffer was used, we have to move its internal base pointer
  1030. this->TLVbuf_Base() += this->dwVertexPoolSize;
  1031. DDASSERT(TLVbuf_base <= TLVbuf_size);
  1032. DDASSERT(TLVbuf_base == this->dwDP2VertexCount * this->dwOutputSize);
  1033. }
  1034. this->dwFlags &= ~D3DPV_USERMEMVERTICES;
  1035. return ret;
  1036. }
  1037. //---------------------------------------------------------------------
  1038. //
  1039. //
  1040. void CDirect3DDeviceIDP2::UpdateDrvViewInfo(LPD3DVIEWPORT7 lpVwpData)
  1041. {
  1042. LPD3DHAL_DP2VIEWPORTINFO pData;
  1043. pData = (LPD3DHAL_DP2VIEWPORTINFO)GetHalBufferPointer(D3DDP2OP_VIEWPORTINFO, sizeof(*pData));
  1044. pData->dwX = lpVwpData->dwX;
  1045. pData->dwY = lpVwpData->dwY;
  1046. pData->dwWidth = lpVwpData->dwWidth;
  1047. pData->dwHeight = lpVwpData->dwHeight;
  1048. }
  1049. //---------------------------------------------------------------------
  1050. //
  1051. //
  1052. void CDirect3DDeviceIDP2::UpdateDrvWInfo()
  1053. {
  1054. LPD3DHAL_DP2WINFO pData;
  1055. pData = (LPD3DHAL_DP2WINFO)GetHalBufferPointer(D3DDP2OP_WINFO, sizeof(*pData));
  1056. D3DMATRIXI &m = transform.proj;
  1057. if( (m._33 == m._34) || (m._33 == 0.0f) )
  1058. {
  1059. D3D_WARN(1, "Cannot compute WNear and WFar from the supplied projection matrix.\n Setting wNear to 0.0 and wFar to 1.0" );
  1060. pData->dvWNear = 0.0f;
  1061. pData->dvWFar = 1.0f;
  1062. return;
  1063. }
  1064. pData->dvWNear = m._44 - m._43/m._33*m._34;
  1065. pData->dvWFar = (m._44 - m._43)/(m._33 - m._34)*m._34 + m._44;
  1066. }
  1067. //---------------------------------------------------------------------
  1068. // Initializes command header in the DP2 command buffer,
  1069. // reserves space for the command data and returns pointer to the command
  1070. // data
  1071. //
  1072. #undef DPF_MODNAME
  1073. #define DPF_MODNAME "CDirect3DDeviceIDP2::GetHalBufferPointer"
  1074. LPVOID CDirect3DDeviceIDP2::GetHalBufferPointer(D3DHAL_DP2OPERATION op, DWORD dwDataSize)
  1075. {
  1076. DWORD dwCommandSize = sizeof(D3DHAL_DP2COMMAND) + dwDataSize;
  1077. // Check to see if there is space to add a new command for space
  1078. if (dwCommandSize + dwDP2CommandLength > dwDP2CommandBufSize)
  1079. {
  1080. HRESULT ret = FlushStates();
  1081. if (ret != D3D_OK)
  1082. {
  1083. D3D_ERR("Error trying to render batched commands in GetHalBufferPointer");
  1084. throw ret;
  1085. }
  1086. }
  1087. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  1088. dwDP2CommandLength + dp2data.dwCommandOffset);
  1089. lpDP2CurrCommand->bCommand = op;
  1090. bDP2CurrCmdOP = op;
  1091. lpDP2CurrCommand->bReserved = 0;
  1092. lpDP2CurrCommand->wStateCount = 1;
  1093. wDP2CurrCmdCnt = 1;
  1094. dwDP2CommandLength += dwCommandSize;
  1095. return (LPVOID)(lpDP2CurrCommand + 1);
  1096. }
  1097. //---------------------------------------------------------------------
  1098. #undef DPF_MODNAME
  1099. #define DPF_MODNAME "CDirect3DDeviceIDP2::UpdateDriverStates"
  1100. HRESULT
  1101. CDirect3DDeviceIDP2::UpdateDriverStates()
  1102. {
  1103. static D3DRENDERSTATETYPE dp2states[] =
  1104. {
  1105. D3DRENDERSTATE_SPECULARENABLE,
  1106. D3DRENDERSTATE_ZENABLE,
  1107. D3DRENDERSTATE_FILLMODE,
  1108. D3DRENDERSTATE_SHADEMODE,
  1109. D3DRENDERSTATE_LINEPATTERN,
  1110. D3DRENDERSTATE_ZWRITEENABLE,
  1111. D3DRENDERSTATE_ALPHATESTENABLE,
  1112. D3DRENDERSTATE_LASTPIXEL,
  1113. D3DRENDERSTATE_SRCBLEND,
  1114. D3DRENDERSTATE_DESTBLEND,
  1115. D3DRENDERSTATE_CULLMODE,
  1116. D3DRENDERSTATE_ZFUNC,
  1117. D3DRENDERSTATE_ALPHAREF,
  1118. D3DRENDERSTATE_ALPHAFUNC,
  1119. D3DRENDERSTATE_DITHERENABLE,
  1120. D3DRENDERSTATE_FOGENABLE,
  1121. D3DRENDERSTATE_ZVISIBLE,
  1122. D3DRENDERSTATE_STIPPLEDALPHA,
  1123. D3DRENDERSTATE_FOGCOLOR,
  1124. D3DRENDERSTATE_FOGTABLEMODE,
  1125. D3DRENDERSTATE_FOGSTART,
  1126. D3DRENDERSTATE_FOGEND,
  1127. D3DRENDERSTATE_FOGDENSITY,
  1128. D3DRENDERSTATE_COLORKEYENABLE,
  1129. D3DRENDERSTATE_ALPHABLENDENABLE,
  1130. D3DRENDERSTATE_ZBIAS,
  1131. D3DRENDERSTATE_RANGEFOGENABLE,
  1132. D3DRENDERSTATE_STIPPLEENABLE,
  1133. D3DRENDERSTATE_MONOENABLE,
  1134. D3DRENDERSTATE_ROP2,
  1135. D3DRENDERSTATE_PLANEMASK,
  1136. D3DRENDERSTATE_WRAPU,
  1137. D3DRENDERSTATE_WRAPV,
  1138. D3DRENDERSTATE_ANTIALIAS,
  1139. D3DRENDERSTATE_SUBPIXEL,
  1140. D3DRENDERSTATE_SUBPIXELX,
  1141. D3DRENDERSTATE_EDGEANTIALIAS,
  1142. D3DRENDERSTATE_STIPPLEPATTERN00,
  1143. D3DRENDERSTATE_STIPPLEPATTERN01,
  1144. D3DRENDERSTATE_STIPPLEPATTERN02,
  1145. D3DRENDERSTATE_STIPPLEPATTERN03,
  1146. D3DRENDERSTATE_STIPPLEPATTERN04,
  1147. D3DRENDERSTATE_STIPPLEPATTERN05,
  1148. D3DRENDERSTATE_STIPPLEPATTERN06,
  1149. D3DRENDERSTATE_STIPPLEPATTERN07,
  1150. D3DRENDERSTATE_STIPPLEPATTERN08,
  1151. D3DRENDERSTATE_STIPPLEPATTERN09,
  1152. D3DRENDERSTATE_STIPPLEPATTERN10,
  1153. D3DRENDERSTATE_STIPPLEPATTERN11,
  1154. D3DRENDERSTATE_STIPPLEPATTERN12,
  1155. D3DRENDERSTATE_STIPPLEPATTERN13,
  1156. D3DRENDERSTATE_STIPPLEPATTERN14,
  1157. D3DRENDERSTATE_STIPPLEPATTERN15,
  1158. D3DRENDERSTATE_STIPPLEPATTERN16,
  1159. D3DRENDERSTATE_STIPPLEPATTERN17,
  1160. D3DRENDERSTATE_STIPPLEPATTERN18,
  1161. D3DRENDERSTATE_STIPPLEPATTERN19,
  1162. D3DRENDERSTATE_STIPPLEPATTERN20,
  1163. D3DRENDERSTATE_STIPPLEPATTERN21,
  1164. D3DRENDERSTATE_STIPPLEPATTERN22,
  1165. D3DRENDERSTATE_STIPPLEPATTERN23,
  1166. D3DRENDERSTATE_STIPPLEPATTERN24,
  1167. D3DRENDERSTATE_STIPPLEPATTERN25,
  1168. D3DRENDERSTATE_STIPPLEPATTERN26,
  1169. D3DRENDERSTATE_STIPPLEPATTERN27,
  1170. D3DRENDERSTATE_STIPPLEPATTERN28,
  1171. D3DRENDERSTATE_STIPPLEPATTERN29,
  1172. D3DRENDERSTATE_STIPPLEPATTERN30,
  1173. D3DRENDERSTATE_STIPPLEPATTERN31,
  1174. D3DRENDERSTATE_TEXTUREPERSPECTIVE,
  1175. D3DRENDERSTATE_STENCILENABLE,
  1176. D3DRENDERSTATE_STENCILFAIL,
  1177. D3DRENDERSTATE_STENCILZFAIL,
  1178. D3DRENDERSTATE_STENCILPASS,
  1179. D3DRENDERSTATE_STENCILFUNC,
  1180. D3DRENDERSTATE_STENCILREF,
  1181. D3DRENDERSTATE_STENCILMASK,
  1182. D3DRENDERSTATE_STENCILWRITEMASK,
  1183. D3DRENDERSTATE_TEXTUREFACTOR,
  1184. D3DRENDERSTATE_WRAP0,
  1185. D3DRENDERSTATE_WRAP1,
  1186. D3DRENDERSTATE_WRAP2,
  1187. D3DRENDERSTATE_WRAP3,
  1188. D3DRENDERSTATE_WRAP4,
  1189. D3DRENDERSTATE_WRAP5,
  1190. D3DRENDERSTATE_WRAP6,
  1191. D3DRENDERSTATE_WRAP7
  1192. };
  1193. HRESULT ret;
  1194. for (DWORD i=0;i<sizeof(dp2states)/sizeof(D3DRENDERSTATETYPE); ++i)
  1195. {
  1196. ret = this->SetRenderStateI(dp2states[i], this->rstates[dp2states[i]]);
  1197. if (ret != D3D_OK)
  1198. return ret;
  1199. }
  1200. // Update new states
  1201. for (i=0; i<dwMaxTextureBlendStages; ++i)
  1202. for (DWORD j=D3DTSS_COLOROP; j<=D3DTSS_BUMPENVLOFFSET; ++j) // D3DTSS_BUMPENVLOFFSET is the max. TSS understood by a DP2HAL (DX6) driver
  1203. {
  1204. D3D_INFO(6,"Calling SetTSSI(%d,%d,%08lx)",i,j, this->tsstates[i][j]);
  1205. ret = this->SetTSSI(i, (D3DTEXTURESTAGESTATETYPE)j, this->tsstates[i][j]);
  1206. if (ret != D3D_OK)
  1207. return ret;
  1208. }
  1209. return D3D_OK;
  1210. }
  1211. //---------------------------------------------------------------------
  1212. // ProcessPrimitive processes indexed, non-indexed primitives or
  1213. // vertices only as defined by "op"
  1214. //
  1215. // op = __PROCPRIMOP_NONINDEXEDPRIM by default
  1216. //
  1217. HRESULT CDirect3DDeviceIDP2::ProcessPrimitive(__PROCPRIMOP op)
  1218. {
  1219. HRESULT ret=D3D_OK;
  1220. // Grow clip flags buffer if we need clipping
  1221. //
  1222. if (!(this->dwDeviceFlags & D3DDEV_DONOTCLIP))
  1223. {
  1224. DWORD size = this->dwNumVertices * sizeof(D3DFE_CLIPCODE);
  1225. if (size > this->HVbuf.GetSize())
  1226. {
  1227. if (this->HVbuf.Grow(size) != D3D_OK)
  1228. {
  1229. D3D_ERR( "Could not grow clip buffer" );
  1230. ret = DDERR_OUTOFMEMORY;
  1231. return ret;
  1232. }
  1233. }
  1234. this->lpClipFlags = (D3DFE_CLIPCODE*)this->HVbuf.GetAddress();
  1235. }
  1236. if (FVF_TRANSFORMED(this->dwVIDIn))
  1237. {
  1238. // Pass vertices directly from the user memory
  1239. this->dwVIDOut = this->dwVIDIn;
  1240. this->dwOutputSize = this->position.dwStride;
  1241. this->lpvOut = this->position.lpvData;
  1242. this->dwVertexPoolSize = this->dwNumVertices * this->dwOutputSize;
  1243. StartPrimUserMem(this->position.lpvData);
  1244. if (ret != D3D_OK)
  1245. return ret;
  1246. if (this->dwDeviceFlags & D3DDEV_DONOTCLIP)
  1247. {
  1248. if (!(this->dwDeviceFlags & D3DDEV_DONOTUPDATEEXTENTS))
  1249. D3DFE_updateExtents(this);
  1250. #ifdef VTABLE_HACK
  1251. else
  1252. if (!IS_MT_DEVICE(this) && this->dwNumVertices < LOWVERTICESNUMBER)
  1253. if (op == __PROCPRIMOP_INDEXEDPRIM)
  1254. VtblDrawIndexedPrimitiveTL();
  1255. else
  1256. VtblDrawPrimitiveTL();
  1257. #endif // VTABLE_HACK
  1258. if (op == __PROCPRIMOP_INDEXEDPRIM)
  1259. {
  1260. ret = this->DrawIndexPrim();
  1261. }
  1262. else
  1263. {
  1264. ret = this->DrawPrim();
  1265. }
  1266. }
  1267. else
  1268. {
  1269. DWORD clip_intersect = D3DFE_GenClipFlags(this);
  1270. D3DFE_UpdateClipStatus(this);
  1271. if (!clip_intersect)
  1272. {
  1273. this->dwFlags |= D3DPV_TLVCLIP;
  1274. if (op == __PROCPRIMOP_INDEXEDPRIM)
  1275. {
  1276. ret = DoDrawIndexedPrimitive(this);
  1277. }
  1278. else
  1279. {
  1280. ret = DoDrawPrimitive(this);
  1281. }
  1282. }
  1283. }
  1284. }
  1285. else
  1286. {
  1287. this->dwVertexPoolSize = this->dwNumVertices * this->dwOutputSize;
  1288. if (op == __PROCPRIMOP_INDEXEDPRIM)
  1289. {
  1290. if ((this->dwDeviceFlags & (D3DDEV_DONOTCLIP | D3DDEV_TLVBUFWRITEONLY))==D3DDEV_TLVBUFWRITEONLY)
  1291. {
  1292. if( FAILED(this->TLVbuf_Grow(this->dwVertexPoolSize, false)) )
  1293. {
  1294. D3D_ERR( "Could not grow TL vertex buffer" );
  1295. return DDERR_OUTOFMEMORY;
  1296. }
  1297. }
  1298. else if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
  1299. {
  1300. if (this->TLVbuf_Grow(this->dwVertexPoolSize,
  1301. (this->dwDeviceFlags & D3DDEV_DONOTCLIP)!=0) != D3D_OK)
  1302. {
  1303. D3D_ERR( "Could not grow TL vertex buffer" );
  1304. ret = DDERR_OUTOFMEMORY;
  1305. return ret;
  1306. }
  1307. }
  1308. #ifdef VTABLE_HACK
  1309. // Use fast path if single threaded device and not using strided API
  1310. if (!(IS_MT_DEVICE(this) || (this->dwDeviceFlags & D3DDEV_STRIDE))
  1311. && IS_FPU_SETUP(this))
  1312. VtblDrawIndexedPrimitiveFE();
  1313. #endif // VTABLE_HACK
  1314. }
  1315. else
  1316. {
  1317. if (this->dwVertexPoolSize > this->TLVbuf_GetSize())
  1318. {
  1319. if (this->TLVbuf_Grow(this->dwVertexPoolSize, true) != D3D_OK)
  1320. {
  1321. D3D_ERR( "Could not grow TL vertex buffer" );
  1322. ret = DDERR_OUTOFMEMORY;
  1323. return ret;
  1324. }
  1325. }
  1326. #ifdef VTABLE_HACK
  1327. // Use fast path if single threaded device and not using strided API
  1328. if (!(IS_MT_DEVICE(this) || (this->dwDeviceFlags & D3DDEV_STRIDE))
  1329. && IS_FPU_SETUP(this))
  1330. VtblDrawPrimitiveFE();
  1331. #endif // VTABLE_HACK
  1332. }
  1333. ret = StartPrimVB(this->TLVbuf_GetVBI(), 0);
  1334. if (ret != D3D_OK)
  1335. return ret;
  1336. this->lpvOut = this->TLVbuf_GetAddress();
  1337. // Update Lighting and related flags
  1338. DoUpdateState(this);
  1339. #ifdef VTABLE_HACK
  1340. // Save the flags that can be persisted if state does not change
  1341. this->dwLastFlags = this->dwFlags & D3DPV_PERSIST;
  1342. #endif // VTABLE_HACK
  1343. // Call PSGP or our implementation
  1344. if (op == __PROCPRIMOP_INDEXEDPRIM)
  1345. {
  1346. ret = this->pGeometryFuncs->ProcessIndexedPrimitive(this);
  1347. }
  1348. else
  1349. {
  1350. ret = this->pGeometryFuncs->ProcessPrimitive(this);
  1351. }
  1352. D3DFE_UpdateClipStatus(this);
  1353. }
  1354. if (ret != D3D_OK)
  1355. {
  1356. D3D_ERR("ProcessPrimitive failed");
  1357. return ret;
  1358. }
  1359. return EndPrim();
  1360. }
  1361. //----------------------------------------------------------------------
  1362. // Growing aligned vertex buffer implementation.
  1363. //
  1364. HRESULT CDirect3DDeviceIDP2::TLVbuf_Grow(DWORD growSize, bool bWriteOnly)
  1365. {
  1366. D3DVERTEXBUFFERDESC vbdesc = {sizeof(D3DVERTEXBUFFERDESC), 0, D3DFVF_TLVERTEX, 0};
  1367. DWORD dwRefCnt = 1;
  1368. DWORD bTLVbufIsCurr = static_cast<CDirect3DVertexBuffer*>(allocatedBuf) == lpDP2CurrBatchVBI; // Is ref cnt of TLVbuf 1 or 2 ?
  1369. bool bDP2WriteOnly = (this->dwDeviceFlags & D3DDEV_TLVBUFWRITEONLY) != 0;
  1370. // Avoid to many changes. Restrict TLVbuf to sys mem if too many changes
  1371. if (this->dwTLVbufChanges >= D3D_MAX_TLVBUF_CHANGES)
  1372. {
  1373. #if DBG
  1374. if (this->dwTLVbufChanges == D3D_MAX_TLVBUF_CHANGES)
  1375. DPF(1, "Too many changes: Limiting internal VB to sys mem.");
  1376. #endif
  1377. bWriteOnly = false;
  1378. }
  1379. if (TLVbuf_base || (bWriteOnly != bDP2WriteOnly))
  1380. {
  1381. HRESULT ret;
  1382. ret = FlushStatesReq(growSize);
  1383. if (ret != D3D_OK)
  1384. {
  1385. D3D_ERR("Error trying to render batched commands in CDirect3DDeviceIDP2::TLVbuf_Grow");
  1386. return ret;
  1387. }
  1388. TLVbuf_base = 0;
  1389. }
  1390. if (growSize <= TLVbuf_size)
  1391. {
  1392. if (bWriteOnly == bDP2WriteOnly)
  1393. return D3D_OK;
  1394. else
  1395. this->dwTLVbufChanges++;
  1396. }
  1397. if (allocatedBuf)
  1398. {
  1399. allocatedBuf->Release();
  1400. allocatedBuf = NULL;
  1401. }
  1402. if (bTLVbufIsCurr)
  1403. {
  1404. if (lpDP2CurrBatchVBI)
  1405. {
  1406. lpDP2CurrBatchVBI->lpDevIBatched = NULL;
  1407. lpDP2CurrBatchVBI->Release();
  1408. }
  1409. lpDP2CurrBatchVBI = NULL;
  1410. dp2data.lpDDVertex = NULL;
  1411. }
  1412. // Make sure we do not shrink the VB since it will
  1413. // grow it only as large to fit the largest primitive and might not
  1414. // be enough to get good batching perf.
  1415. DWORD size = max(growSize, TLVbuf_size);
  1416. size = (DWORD)max(size, (__INIT_VERTEX_NUMBER*2)*sizeof(D3DTLVERTEX));
  1417. vbdesc.dwNumVertices = (size + 31) / sizeof(D3DTLVERTEX);
  1418. TLVbuf_size = vbdesc.dwNumVertices * sizeof(D3DTLVERTEX);
  1419. if (!IS_HW_DEVICE(this))
  1420. {
  1421. vbdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
  1422. }
  1423. if (bWriteOnly)
  1424. {
  1425. vbdesc.dwCaps |= D3DVBCAPS_WRITEONLY;
  1426. this->dwDeviceFlags |= D3DDEV_TLVBUFWRITEONLY;
  1427. }
  1428. else
  1429. {
  1430. this->dwDeviceFlags &= ~D3DDEV_TLVBUFWRITEONLY;
  1431. }
  1432. vbdesc.dwCaps |= D3DVBCAPS_DONOTCLIP;
  1433. if (this->lpDirect3DI->CreateVertexBufferI(&vbdesc, &allocatedBuf, D3DVBFLAGS_CREATEMULTIBUFFER) != DD_OK)
  1434. {
  1435. // This should fail duirng mode switches or ulta-low memory situations. In either case,
  1436. // we set allocatedBuf to a valid VB object since it gets dereferenced many places without
  1437. // checking for it being NULL. WE use the special "NULL" VB created at init time for just
  1438. // this purpose
  1439. allocatedBuf = pNullVB;
  1440. if (pNullVB)
  1441. {
  1442. allocatedBuf->AddRef();
  1443. if (bTLVbufIsCurr)
  1444. {
  1445. lpDP2CurrBatchVBI = static_cast<CDirect3DVertexBuffer*>(allocatedBuf);
  1446. lpDP2CurrBatchVBI->AddRef();
  1447. dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)(lpDP2CurrBatchVBI->GetDDS()))->lpLcl;
  1448. }
  1449. }
  1450. TLVbuf_size = 0;
  1451. alignedBuf = NULL; // Lets see if some one tries to use this...
  1452. D3D_ERR("Could not allocate internal vertex buffer");
  1453. return DDERR_OUTOFMEMORY;
  1454. }
  1455. // Update lpDP2CurrentBatchVBI if necessary
  1456. if (bTLVbufIsCurr)
  1457. {
  1458. lpDP2CurrBatchVBI = static_cast<CDirect3DVertexBuffer*>(allocatedBuf);
  1459. lpDP2CurrBatchVBI->AddRef();
  1460. dp2data.lpDDVertex = ((LPDDRAWI_DDRAWSURFACE_INT)(lpDP2CurrBatchVBI->GetDDS()))->lpLcl;
  1461. }
  1462. if (allocatedBuf->Lock(DDLOCK_WAIT, &alignedBuf, NULL) != DD_OK)
  1463. {
  1464. D3D_ERR("Could not lock internal vertex buffer");
  1465. TLVbuf_size = 0;
  1466. alignedBuf = NULL; // Lets see if some one tries to use this...
  1467. return DDERR_OUTOFMEMORY;
  1468. }
  1469. return D3D_OK;
  1470. }
  1471. //---------------------------------------------------------------------
  1472. // Computes the following data
  1473. // - dwTextureCoordOffset[] offset of every input texture coordinates
  1474. static __inline void ComputeInpTexCoordOffsets(DWORD dwNumTexCoord,
  1475. DWORD dwFVF,
  1476. DWORD *pdwTextureCoordOffset)
  1477. {
  1478. // Compute texture coordinate size
  1479. DWORD dwTextureFormats = dwFVF >> 16;
  1480. if (dwTextureFormats == 0)
  1481. {
  1482. for (DWORD i=0; i < dwNumTexCoord; i++)
  1483. {
  1484. pdwTextureCoordOffset[i] = i << 3;
  1485. }
  1486. }
  1487. else
  1488. {
  1489. DWORD dwOffset = 0;
  1490. for (DWORD i=0; i < dwNumTexCoord; i++)
  1491. {
  1492. pdwTextureCoordOffset[i] = dwOffset;
  1493. dwOffset += g_TextureSize[dwTextureFormats & 3];
  1494. dwTextureFormats >>= 2;
  1495. }
  1496. }
  1497. return;
  1498. }
  1499. //---------------------------------------------------------------------
  1500. // Returns 2 bits of FVF texture format for the texture index
  1501. //
  1502. static inline DWORD FVFGetTextureFormat(DWORD dwFVF, DWORD dwTextureIndex)
  1503. {
  1504. return (dwFVF >> (dwTextureIndex*2 + 16)) & 3;
  1505. }
  1506. //---------------------------------------------------------------------
  1507. // Returns texture format bits shifted to the right place
  1508. //
  1509. static inline DWORD FVFMakeTextureFormat(DWORD dwNumberOfCoordinates, DWORD dwTextureIndex)
  1510. {
  1511. return g_dwTextureFormat[dwNumberOfCoordinates] << ((dwTextureIndex << 1) + 16);
  1512. }
  1513. //---------------------------------------------------------------------
  1514. inline DWORD GetOutTexCoordSize(DWORD *pdwStage, DWORD dwInpTexCoordSize)
  1515. {
  1516. // Low byte has texture coordinate count
  1517. const DWORD dwTextureTransformFlags = pdwStage[D3DTSS_TEXTURETRANSFORMFLAGS] & 0xFF;
  1518. if (dwTextureTransformFlags == 0)
  1519. return dwInpTexCoordSize;
  1520. else
  1521. return (dwTextureTransformFlags << 2);
  1522. }
  1523. //----------------------------------------------------------------------
  1524. // pDevI->nOutTexCoord should be initialized to the number of input texture coord sets
  1525. //
  1526. HRESULT EvalTextureTransforms(LPDIRECT3DDEVICEI pDevI, DWORD dwTexTransform,
  1527. DWORD *pdwOutTextureSize, DWORD *pdwOutTextureFormat)
  1528. {
  1529. DWORD dwOutTextureSize = 0; // Used to compute output vertex size
  1530. DWORD dwOutTextureFormat = 0; // Used to compute output texture FVF
  1531. // The bits are used to find out how the texture coordinates are used.
  1532. const DWORD __USED_BY_TRANSFORM = 1;
  1533. const DWORD __USED = 2;
  1534. // The low 16 bits are for _USED bits. The high 16 bits will hold
  1535. // re-mapped texture index for a stage
  1536. DWORD dwTexCoordUsage[D3DDP_MAXTEXCOORD];
  1537. memset(dwTexCoordUsage, 0, sizeof(dwTexCoordUsage));
  1538. // Re-mapping buffer will contain only stages that use texture
  1539. // This variable is used to count them
  1540. pDevI->dwNumTextureStages = 0;
  1541. DWORD dwNewIndex = 0; // Used to generate output index
  1542. // We need offsets for every input texture coordinate, because
  1543. // we could access them in random order.
  1544. // Offsets are not needed for strided input
  1545. DWORD dwTextureCoordOffset[D3DDP_MAXTEXCOORD];
  1546. if (!(pDevI->dwDeviceFlags & D3DDEV_STRIDE))
  1547. {
  1548. ComputeInpTexCoordOffsets(pDevI->nTexCoord, pDevI->dwVIDIn, dwTextureCoordOffset);
  1549. }
  1550. DWORD dwOutTextureCoordSize[D3DDP_MAXTEXCOORD];
  1551. // Go through all texture stages and find those which use texture coordinates
  1552. for (DWORD i=0; i < D3DDP_MAXTEXCOORD; i++)
  1553. {
  1554. if (pDevI->tsstates[i][D3DTSS_COLOROP] == D3DTOP_DISABLE)
  1555. break;
  1556. DWORD dwIndex = pDevI->tsstates[i][D3DTSS_TEXCOORDINDEX];
  1557. DWORD dwInpTextureFormat;
  1558. DWORD dwInpTexSize;
  1559. DWORD dwMapArrayIndex = pDevI->dwNumTextureStages;
  1560. LPD3DFE_TEXTURESTAGE pStage = &pDevI->textureStage[dwMapArrayIndex];
  1561. DWORD dwTexGenMode = dwIndex & ~0xFFFF;
  1562. dwIndex = dwIndex & 0xFFFF; // Remove texture generation mode
  1563. if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL ||
  1564. dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION ||
  1565. dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR)
  1566. {
  1567. dwInpTextureFormat = D3DFVF_TEXCOORDSIZE3(dwIndex);
  1568. dwInpTexSize = 3*sizeof(D3DVALUE);
  1569. pDevI->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES;
  1570. if (dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR)
  1571. pDevI->dwDeviceFlags |= D3DDEV_NORMALINCAMERASPACE | D3DDEV_POSITIONINCAMERASPACE;
  1572. else
  1573. if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL)
  1574. pDevI->dwDeviceFlags |= D3DDEV_NORMALINCAMERASPACE;
  1575. else
  1576. if (dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION)
  1577. pDevI->dwDeviceFlags |= D3DDEV_POSITIONINCAMERASPACE;
  1578. }
  1579. else
  1580. {
  1581. if (dwIndex >= pDevI->nTexCoord)
  1582. {
  1583. D3D_ERR("Texture index in a stage is greater than number of input texture coordinates");
  1584. return DDERR_GENERIC;
  1585. }
  1586. dwInpTextureFormat = FVFGetTextureFormat(pDevI->dwVIDIn, dwIndex);
  1587. dwInpTexSize = pDevI->dwTextureCoordSize[dwIndex];
  1588. pStage->dwInpOffset = dwTextureCoordOffset[dwIndex];
  1589. }
  1590. pStage->dwInpCoordIndex = dwIndex;
  1591. pStage->dwTexGenMode = dwTexGenMode;
  1592. pStage->dwOrgStage = i;
  1593. DWORD dwOutTexCoordSize; // Size of the texture coord set in bytes for this stage
  1594. if (dwTexTransform & 1)
  1595. {
  1596. pDevI->dwDeviceFlags |= D3DDEV_TEXTURETRANSFORM;
  1597. pStage->pmTextureTransform = &pDevI->mTexture[i];
  1598. dwOutTexCoordSize = GetOutTexCoordSize((DWORD*)&pDevI->tsstates[i], dwInpTexSize);
  1599. // If we have to add or remove some coordinates we go through
  1600. // the re-mapping path
  1601. if (dwOutTexCoordSize != dwInpTexSize)
  1602. pDevI->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES;
  1603. }
  1604. else
  1605. {
  1606. pStage->pmTextureTransform = NULL;
  1607. dwOutTexCoordSize = dwInpTexSize;
  1608. }
  1609. pStage->dwTexTransformFuncIndex = MakeTexTransformFuncIndex
  1610. (dwInpTexSize >> 2, dwOutTexCoordSize >> 2);
  1611. if ((dwTexCoordUsage[dwIndex] & 0xFFFF) == 0)
  1612. {
  1613. // Texture coordinate set is used first time
  1614. if (dwTexTransform & 1)
  1615. dwTexCoordUsage[dwIndex] |= __USED_BY_TRANSFORM;
  1616. dwTexCoordUsage[dwIndex] |= __USED;
  1617. }
  1618. else
  1619. {
  1620. // Texture coordinate set is used second or more time
  1621. if (dwTexTransform & 1)
  1622. {
  1623. // This set is used by two texture transforms or a
  1624. // texture transform and without it, so we have to
  1625. // generate an additional output texture coordinate
  1626. dwTexCoordUsage[dwIndex] |= __USED_BY_TRANSFORM;
  1627. pDevI->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES;
  1628. }
  1629. else
  1630. {
  1631. if (dwTexCoordUsage[dwIndex] & __USED_BY_TRANSFORM)
  1632. {
  1633. // This set is used by two texture transforms or a
  1634. // texture transform and without it, so we have to
  1635. // generate an additional output texture coordinate
  1636. pDevI->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES;
  1637. }
  1638. else
  1639. if (dwTexGenMode == 0)
  1640. {
  1641. // We do not have to generate new texture coord for this,
  1642. // we can re-use the same input texture coordinate
  1643. DWORD dwOutIndex = dwTexCoordUsage[dwIndex] >> 16;
  1644. pStage->dwOutCoordIndex = dwOutIndex;
  1645. goto l_NoNewOutTexCoord;
  1646. }
  1647. }
  1648. }
  1649. // If we are here, we have to generate new output texture coordinate set
  1650. pStage->dwOutCoordIndex = dwNewIndex;
  1651. dwTexCoordUsage[dwIndex] |= dwNewIndex << 16;
  1652. dwOutTextureSize += dwOutTexCoordSize;
  1653. dwOutTextureCoordSize[dwNewIndex] = dwOutTexCoordSize;
  1654. dwOutTextureFormat |= FVFMakeTextureFormat(dwOutTexCoordSize >> 2, dwNewIndex);
  1655. dwNewIndex++;
  1656. l_NoNewOutTexCoord:
  1657. pDevI->dwNumTextureStages++;
  1658. dwTexTransform >>= 1;
  1659. }
  1660. if (pDevI->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES)
  1661. {
  1662. // Now, when we have to do re-mapping, we have to set new output texture
  1663. // coordinate set sizes
  1664. for (DWORD i=0; i < pDevI->dwNumTextureStages; i++)
  1665. {
  1666. pDevI->dwTextureCoordSize[i] = dwOutTextureCoordSize[i];
  1667. }
  1668. pDevI->nOutTexCoord = dwNewIndex;
  1669. }
  1670. *pdwOutTextureSize = dwOutTextureSize;
  1671. *pdwOutTextureFormat = dwOutTextureFormat;
  1672. return D3D_OK;
  1673. }
  1674. //----------------------------------------------------------------------
  1675. // Sets texture transform pointer for every input texture coordinate set
  1676. //
  1677. void SetupTextureTransforms(LPDIRECT3DDEVICEI pDevI)
  1678. {
  1679. // Set texture transforms to NULL in case when some texture coordinates
  1680. // are not used by texture stages
  1681. memset(pDevI->pmTexture, 0, sizeof(pDevI->pmTexture));
  1682. for (DWORD i=0; i < pDevI->dwNumTextureStages; i++)
  1683. {
  1684. LPD3DFE_TEXTURESTAGE pStage = &pDevI->textureStage[i];
  1685. pDevI->pmTexture[pStage->dwInpCoordIndex] = pStage->pmTextureTransform;
  1686. }
  1687. }
  1688. //----------------------------------------------------------------------
  1689. HRESULT CDirect3DDeviceIDP2::SetupFVFData(DWORD *pdwInpVertexSize)
  1690. {
  1691. if (this->dwDeviceFlags & D3DDEV_FVF)
  1692. return DIRECT3DDEVICEI::SetupFVFDataCommon(pdwInpVertexSize);
  1693. else
  1694. return DIRECT3DDEVICEI::SetupFVFData(pdwInpVertexSize);
  1695. }
  1696. //----------------------------------------------------------------------
  1697. // Computes the following device data
  1698. // - dwVIDOut, based on input FVF id and device settings
  1699. // - nTexCoord
  1700. // - dwTextureCoordSizeTotal
  1701. // - dwTextureCoordSize[] array, based on the input FVF id
  1702. // - dwOutputSize, based on the output FVF id
  1703. //
  1704. // The function is called from ProcessVertices and DrawPrimitives code paths
  1705. //
  1706. // The following variables should be set in the pDevI:
  1707. // - dwVIDIn
  1708. //
  1709. // Number of texture coordinates is set based on dwVIDIn. ValidateFVF should
  1710. // make sure that it is not greater than supported by the driver
  1711. // Last settings for dwVIDOut and dwVIDIn are saved to speed up processing
  1712. //
  1713. #undef DPF_MODNAME
  1714. #define DPF_MODNAME "CDirect3DDeviceIDP2::SetupFVFData"
  1715. HRESULT DIRECT3DDEVICEI::SetupFVFDataCommon(DWORD *pdwInpVertexSize)
  1716. {
  1717. HRESULT ret;
  1718. this->dwFEFlags &= ~D3DFE_FVF_DIRTY;
  1719. // We have to restore texture stage indices if previous primitive
  1720. // re-mapped them
  1721. if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES)
  1722. {
  1723. RestoreTextureStages(this);
  1724. }
  1725. // Compute number of the input texture coordinates
  1726. this->nTexCoord = FVF_TEXCOORD_NUMBER(this->dwVIDIn);
  1727. // Compute size of input texture coordinates
  1728. this->dwTextureCoordSizeTotal = ComputeTextureCoordSize(this->dwVIDIn, this->dwInpTextureCoordSize);
  1729. // This size is the same for input and output FVFs in case when we do not have to
  1730. // expand number of texture coordinates
  1731. for (DWORD i=0; i < this->nTexCoord; i++)
  1732. this->dwTextureCoordSize[i] = this->dwInpTextureCoordSize[i];
  1733. if (pdwInpVertexSize)
  1734. {
  1735. *pdwInpVertexSize = GetVertexSizeFVF(this->dwVIDIn) + this->dwTextureCoordSizeTotal;
  1736. }
  1737. this->nOutTexCoord = this->nTexCoord;
  1738. if (FVF_TRANSFORMED(this->dwVIDIn))
  1739. {
  1740. // Set up vertex pointers
  1741. this->dwVIDOut = this->dwVIDIn;
  1742. ComputeOutputVertexOffsets(this);
  1743. return D3D_OK;
  1744. }
  1745. // Compute output FVF
  1746. this->dwVIDOut = D3DFVF_XYZRHW;
  1747. if (this->dwDeviceFlags & D3DDEV_DONOTSTRIPELEMENTS)
  1748. {
  1749. this->dwVIDOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
  1750. }
  1751. else
  1752. {
  1753. // If normal present we have to compute specular and duffuse
  1754. // Otherwise set these bits the same as input.
  1755. // Not that normal should not be present for XYZRHW position type
  1756. if (this->dwDeviceFlags & D3DDEV_LIGHTING)
  1757. this->dwVIDOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR;
  1758. else
  1759. this->dwVIDOut |= this->dwVIDIn & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR);
  1760. // Always set specular flag if fog is enabled
  1761. if (this->rstates[D3DRENDERSTATE_FOGENABLE])
  1762. this->dwVIDOut |= D3DFVF_SPECULAR;
  1763. else
  1764. // Clear specular flag if specular disabled and we do not have specular in the input
  1765. if (!this->rstates[D3DRENDERSTATE_SPECULARENABLE] && !(this->dwVIDIn & D3DFVF_SPECULAR))
  1766. this->dwVIDOut &= ~D3DFVF_SPECULAR;
  1767. }
  1768. // Compute output vertex size without texture
  1769. this->dwOutputSize = GetVertexSizeFVF(this->dwVIDOut);
  1770. // Compute number of the output texture coordinates
  1771. // Transform enable bits
  1772. DWORD dwTexTransform = this->dwFlags2 & __FLAGS2_TEXTRANSFORM;
  1773. this->dwDeviceFlags &= ~D3DDEV_TEXTURETRANSFORM;
  1774. // When texture transform is enabled or texture coordinates are taken from
  1775. // the vertex data, output texture coordinates could be generated. so we go
  1776. // and evaluate texture stages
  1777. if ((dwTexTransform && this->nTexCoord > 0) ||
  1778. this->dwFlags2 & __FLAGS2_TEXGEN)
  1779. {
  1780. DWORD dwOutTextureSize; // Used to compute output vertex size
  1781. DWORD dwOutTextureFormat; // Used to compute output texture FVF
  1782. // There are texture transforms.
  1783. // Now we find out if some of the texture coordinates are used two or more
  1784. // times and used by a texture transform. In this case we have expand number
  1785. // of output texture coordinates.
  1786. ret = EvalTextureTransforms(this, dwTexTransform, &dwOutTextureSize, &dwOutTextureFormat);
  1787. if (ret != D3D_OK)
  1788. return ret;
  1789. if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES)
  1790. {
  1791. // For ProcessVertices calls user should set texture stages and
  1792. // wrap modes himself
  1793. if (!(this->dwFlags & D3DPV_VBCALL))
  1794. {
  1795. // dwVIDIn is used to force re-compute FVF in the
  1796. // SetTextureStageState. so we save and restore it.
  1797. DWORD dwVIDInSaved = this->dwVIDIn;
  1798. // Re-map indices in the texture stages and wrap modes
  1799. DWORD dwOrgWrapModes[D3DDP_MAXTEXCOORD];
  1800. memcpy(dwOrgWrapModes, &this->rstates[D3DRENDERSTATE_WRAP0], sizeof(dwOrgWrapModes));
  1801. for (DWORD i=0; i < this->dwNumTextureStages; i++)
  1802. {
  1803. LPD3DFE_TEXTURESTAGE pStage = &this->textureStage[i];
  1804. DWORD dwOutIndex = pStage->dwOutCoordIndex;
  1805. DWORD dwInpIndex = pStage->dwInpCoordIndex;
  1806. if (dwOutIndex != dwInpIndex || pStage->dwTexGenMode)
  1807. {
  1808. DWORD dwState = D3DRENDERSTATE_WRAP0 + dwOutIndex;
  1809. pStage->dwOrgWrapMode = dwOrgWrapModes[dwOutIndex];
  1810. DWORD dwValue = dwOrgWrapModes[dwInpIndex];
  1811. // We do not call UpdateInternaState because it
  1812. // will call ForceRecomputeFVF and we do not want this.
  1813. this->rstates[dwState] = dwValue;
  1814. this->SetRenderStateI((D3DRENDERSTATETYPE)dwState, dwValue);
  1815. // We do not call UpdateInternalTextureStageState because it
  1816. // will call ForceRecomputeFVF and we do not want this.
  1817. this->SetTSSI(pStage->dwOrgStage, D3DTSS_TEXCOORDINDEX, dwOutIndex);
  1818. // We do not call UpdateInternalTextureStageState because it
  1819. // will call ForceRecomputeFVF and we do not want this.
  1820. // We set some invalid value to the internal array, because otherwise
  1821. // a new SetTextureStageState could be filtered as redundant
  1822. tsstates[pStage->dwOrgStage][D3DTSS_TEXCOORDINDEX] = 0xFFFFFFFF;
  1823. }
  1824. }
  1825. this->dwVIDIn = dwVIDInSaved;
  1826. }
  1827. this->dwVIDOut |= dwOutTextureFormat;
  1828. this->dwOutputSize += dwOutTextureSize;
  1829. this->dwTextureCoordSizeTotal = dwOutTextureSize;
  1830. }
  1831. else
  1832. { // We do not do re-mapping but we have to make correspondence between
  1833. // texture sets and texture transforms
  1834. SetupTextureTransforms(this);
  1835. // Copy input texture formats
  1836. this->dwVIDOut |= this->dwVIDIn & 0xFFFF0000;
  1837. this->dwOutputSize += this->dwTextureCoordSizeTotal;
  1838. }
  1839. }
  1840. else
  1841. {
  1842. // Copy input texture formats
  1843. this->dwVIDOut |= this->dwVIDIn & 0xFFFF0000;
  1844. this->dwOutputSize += this->dwTextureCoordSizeTotal;
  1845. }
  1846. if (this->dwDeviceFlags & D3DDEV_DONOTSTRIPELEMENTS)
  1847. {
  1848. if (this->nOutTexCoord == 0 && !(this->dwFlags & D3DPV_VBCALL))
  1849. {
  1850. this->dwOutputSize += 2*sizeof(D3DVALUE);
  1851. this->dwTextureCoordSize[0] = 0;
  1852. this->dwVIDOut |= (1 << D3DFVF_TEXCOUNT_SHIFT);
  1853. }
  1854. }
  1855. // Set up number of output texture coordinates
  1856. this->dwVIDOut |= (this->nOutTexCoord << D3DFVF_TEXCOUNT_SHIFT);
  1857. if (this->dwVIDOut & 0xFFFF0000 && this->deviceType < D3DDEVTYPE_DX7HAL)
  1858. {
  1859. D3D_ERR("Texture format bits in the output FVF for this device should be 0");
  1860. return DDERR_INVALIDPARAMS;
  1861. }
  1862. // Set up vertex pointers
  1863. if (!(this->dwFlags & D3DPV_VBCALL))
  1864. UpdateGeometryLoopData(this);
  1865. // In case if COLORVERTEX is TRUE, the vertexAlpha could be overriden
  1866. // by vertex alpha
  1867. this->lighting.alpha = (DWORD)this->lighting.materialAlpha;
  1868. this->lighting.alphaSpecular = (DWORD)this->lighting.materialAlphaS;
  1869. this->dwFEFlags |= D3DFE_VERTEXBLEND_DIRTY;
  1870. return D3D_OK;
  1871. }
  1872. #if DBG
  1873. void CDirect3DDeviceIDP2::ValidateVertex(LPDWORD lpdwVertex)
  1874. {
  1875. if (FVF_TRANSFORMED(dp2data.dwVertexType))
  1876. {
  1877. float left, right, top, bottom;
  1878. if (dwDeviceFlags & D3DDEV_GUARDBAND)
  1879. {
  1880. left = lpD3DExtendedCaps->dvGuardBandLeft;
  1881. right = lpD3DExtendedCaps->dvGuardBandRight;
  1882. top = lpD3DExtendedCaps->dvGuardBandTop;
  1883. bottom = lpD3DExtendedCaps->dvGuardBandBottom;
  1884. }
  1885. else
  1886. {
  1887. left = (float)m_Viewport.dwX;
  1888. top = (float)m_Viewport.dwY;
  1889. right = (float)m_Viewport.dwX + m_Viewport.dwWidth;
  1890. bottom = (float)m_Viewport.dwY + m_Viewport.dwHeight;
  1891. }
  1892. if (*(float*)lpdwVertex < left || *(float*)lpdwVertex++ > right)
  1893. DPF_ERR("X coordinate out of range!");
  1894. if (*(float*)lpdwVertex < top || *(float*)lpdwVertex++ > bottom)
  1895. DPF_ERR("Y coordinate out of range!");
  1896. if (rstates[D3DRENDERSTATE_ZENABLE] ||
  1897. rstates[D3DRENDERSTATE_ZWRITEENABLE])
  1898. {
  1899. // Allow a little slack for those generating triangles exactly on the
  1900. // depth limit. Needed for Quake.
  1901. if (*(float*)lpdwVertex < -0.00015f || *(float*)lpdwVertex++ > 1.00015f)
  1902. DPF_ERR("Z coordinate out of range!");
  1903. }
  1904. if (FVF_TEXCOORD_NUMBER(dp2data.dwVertexType) > 0)
  1905. {
  1906. if (*(float*)lpdwVertex <= 0 )
  1907. {
  1908. DPF_ERR("RHW out of range!");
  1909. }
  1910. }
  1911. }
  1912. }
  1913. void CDirect3DDeviceIDP2::ValidateCommand(LPD3DHAL_DP2COMMAND lpCmd)
  1914. {
  1915. DWORD dwTexCoordSizeDummy[8];
  1916. DWORD dwVertexSize = GetVertexSizeFVF(dp2data.dwVertexType) + ComputeTextureCoordSize(dp2data.dwVertexType, dwTexCoordSizeDummy);
  1917. WORD wStart, wCount;
  1918. switch (lpCmd->bCommand)
  1919. {
  1920. case D3DDP2OP_TRIANGLELIST:
  1921. {
  1922. LPD3DHAL_DP2TRIANGLELIST pTri = (LPD3DHAL_DP2TRIANGLELIST)(lpCmd + 1);
  1923. wStart = pTri->wVStart;
  1924. wCount =lpCmd->wPrimitiveCount * 3;
  1925. }
  1926. break;
  1927. case D3DDP2OP_TRIANGLESTRIP:
  1928. case D3DDP2OP_TRIANGLEFAN:
  1929. {
  1930. LPD3DHAL_DP2TRIANGLEFAN pFan = (LPD3DHAL_DP2TRIANGLEFAN)(lpCmd + 1);
  1931. wStart = pFan->wVStart;
  1932. wCount = lpCmd->wPrimitiveCount + 2;
  1933. }
  1934. break;
  1935. case D3DDP2OP_TRIANGLEFAN_IMM:
  1936. {
  1937. wCount = lpCmd->wPrimitiveCount + 2;
  1938. for (WORD i=0; i < wCount; ++i)
  1939. {
  1940. ValidateVertex((LPDWORD)((LPBYTE)(lpCmd + 1) + i * dwVertexSize));
  1941. }
  1942. }
  1943. // Fall through
  1944. default:
  1945. return;
  1946. }
  1947. for (WORD i = wStart; i < wStart + wCount; ++i)
  1948. {
  1949. if( dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES )
  1950. ValidateVertex((LPDWORD)((LPBYTE)(dp2data.lpVertices) + i * dwVertexSize));
  1951. else
  1952. ValidateVertex((LPDWORD)((LPBYTE)(dp2data.lpDDVertex->lpGbl->fpVidMem) + i * dwVertexSize));
  1953. }
  1954. }
  1955. #endif