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.

2741 lines
98 KiB

  1. #include "pch.cpp"
  2. #pragma hdrstop
  3. /*==========================================================================;
  4. *
  5. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * File: ddidx8.cpp
  8. * Content: Direct3D Dx8 DDI encapsulation implementations
  9. *
  10. ***************************************************************************/
  11. #include "d3d8p.h"
  12. #include "ddi.h"
  13. #include "fe.h"
  14. #include "ddi.inl"
  15. extern DWORD g_DebugFlags;
  16. extern HRESULT ProcessClippedPointSprites(D3DFE_PROCESSVERTICES *pv);
  17. extern DWORD D3DFE_GenClipFlags(D3DFE_PROCESSVERTICES *pv);
  18. //-----------------------------------------------------------------------------
  19. // TL stream which is read-only
  20. //
  21. class CTLStreamRO: public CTLStream
  22. {
  23. public:
  24. CTLStreamRO(): CTLStream(TRUE) {m_dwIndex = 0; m_bUserMemStream = FALSE;}
  25. void Init(CVertexBuffer* pVB, UINT primitiveBase);
  26. BYTE* Lock(UINT NeededSize, CD3DDDIDX6* pDDI);
  27. void Unlock() {}
  28. BOOL IsUserMemStream() {return m_bUserMemStream;}
  29. void AddVertices(UINT NumVertices) {}
  30. void SubVertices(UINT NumVertices) {}
  31. void MovePrimitiveBase(int NumVertices)
  32. {
  33. m_dwPrimitiveBase += NumVertices * m_dwStride;
  34. }
  35. void SkipVertices(DWORD NumVertices)
  36. {
  37. m_dwPrimitiveBase += NumVertices * m_dwStride;
  38. }
  39. protected:
  40. BOOL m_bUserMemStream;
  41. };
  42. //-----------------------------------------------------------------------------
  43. void CTLStreamRO::Init(CVertexBuffer* pVB, UINT primitiveBase)
  44. {
  45. if (m_pVB)
  46. {
  47. m_pVB->DecrementUseCount();
  48. m_pVB = NULL;
  49. }
  50. m_pVB = pVB;
  51. if (pVB)
  52. {
  53. m_bUserMemStream = FALSE;
  54. m_pVB->IncrementUseCount();
  55. }
  56. else
  57. {
  58. m_bUserMemStream = TRUE;
  59. }
  60. m_dwPrimitiveBase = primitiveBase;
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Index stream which is read-only
  64. //
  65. class CTLIndexStreamRO: public CTLIndexStream
  66. {
  67. public:
  68. CTLIndexStreamRO() {m_dwIndex = __NUMSTREAMS;}
  69. void Init(CIndexBuffer* pVB, UINT primitiveBase);
  70. BYTE* Lock(UINT NeededSize, CD3DDDIDX6* pDDI);
  71. void Unlock() {}
  72. void AddVertices(UINT NumVertices) {}
  73. void SubVertices(UINT NumVertices) {}
  74. void MovePrimitiveBase(int NumVertices)
  75. {
  76. m_dwPrimitiveBase += NumVertices * m_dwStride;
  77. }
  78. void SkipVertices(DWORD NumVertices)
  79. {
  80. m_dwPrimitiveBase += NumVertices * m_dwStride;
  81. }
  82. };
  83. //-----------------------------------------------------------------------------
  84. void CTLIndexStreamRO::Init(CIndexBuffer* pVB, UINT primitiveBase)
  85. {
  86. if (m_pVBI)
  87. {
  88. m_pVBI->DecrementUseCount();
  89. m_pVBI = NULL;
  90. }
  91. m_pVBI = pVB;
  92. if (m_pVBI)
  93. m_pVBI->IncrementUseCount();
  94. m_dwPrimitiveBase = primitiveBase;
  95. }
  96. //-----------------------------------------------------------------------------
  97. CTLStream::CTLStream(BOOL bWriteOnly)
  98. {
  99. m_bWriteOnly = bWriteOnly;
  100. m_dwSize = 0;
  101. m_dwPrimitiveBase = 0;
  102. m_dwUsedSize = 0;
  103. m_dwIndex = 0;
  104. m_Usage = 0;
  105. }
  106. //-----------------------------------------------------------------------------
  107. CTLStream::CTLStream(BOOL bWriteOnly, UINT Usage)
  108. {
  109. m_bWriteOnly = bWriteOnly;
  110. m_dwSize = 0;
  111. m_dwPrimitiveBase = 0;
  112. m_dwUsedSize = 0;
  113. m_dwIndex = 0;
  114. m_Usage = Usage;
  115. }
  116. //-----------------------------------------------------------------------------
  117. void CTLStream::Grow(UINT RequiredSize, CD3DDDIDX6* pDDI)
  118. {
  119. if (RequiredSize > m_dwSize)
  120. {
  121. // We create the new vertex buffer before releasing the old one to
  122. // prevent creating the buffer on the same place in memory
  123. DWORD dwUsage = D3DUSAGE_INTERNALBUFFER | D3DUSAGE_DYNAMIC | m_Usage;
  124. if (m_bWriteOnly)
  125. dwUsage |= D3DUSAGE_WRITEONLY;
  126. IDirect3DVertexBuffer8 * pVB;
  127. HRESULT ret = CVertexBuffer::Create(pDDI->GetDevice(),
  128. RequiredSize,
  129. dwUsage,
  130. 0,
  131. D3DPOOL_DEFAULT,
  132. REF_INTERNAL,
  133. &pVB);
  134. if (ret != DD_OK)
  135. {
  136. D3D_THROW(ret, "Could not allocate internal vertex buffer");
  137. }
  138. if (m_pVB)
  139. m_pVB->DecrementUseCount();
  140. m_pVB = static_cast<CVertexBuffer*>(pVB);
  141. m_dwSize = RequiredSize;
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. BYTE* CTLStream::Lock(UINT NeededSize, CD3DDDIDX6* pDDI)
  146. {
  147. HRESULT ret;
  148. DXGASSERT(m_dwSize >= m_dwUsedSize);
  149. if (NeededSize > m_dwSize - m_dwUsedSize || m_dwUsedSize == 0)
  150. {
  151. Grow(NeededSize, pDDI);
  152. ret = m_pVB->Lock(0, m_dwSize, &m_pData, D3DLOCK_DISCARD |
  153. D3DLOCK_NOSYSLOCK);
  154. this->Reset();
  155. }
  156. else
  157. {
  158. ret = m_pVB->Lock(0, m_dwSize, &m_pData, D3DLOCK_NOOVERWRITE |
  159. D3DLOCK_NOSYSLOCK);
  160. }
  161. if (ret != DD_OK)
  162. {
  163. D3D_THROW(ret, "Could not lock internal vertex buffer");
  164. }
  165. // m_dwPrimitiveBase could be out of sync with m_dwUsedSize, because
  166. // sometimes we re-use vertices (like when clipping line strips). Make
  167. // sure that they are in sync.
  168. m_dwPrimitiveBase = m_dwUsedSize;
  169. return m_pData + m_dwUsedSize;
  170. }
  171. //-----------------------------------------------------------------------------
  172. void CTLStream::Unlock()
  173. {
  174. m_pVB->Unlock();
  175. }
  176. //-----------------------------------------------------------------------------
  177. CTLIndexStream::CTLIndexStream()
  178. {
  179. m_dwSize = 0;
  180. m_dwPrimitiveBase = 0;
  181. m_dwUsedSize = 0;
  182. m_dwIndex = 0;
  183. }
  184. //-----------------------------------------------------------------------------
  185. void CTLIndexStream::Grow(UINT RequiredSize, CD3DDDIDX6* pDDI)
  186. {
  187. if (RequiredSize > m_dwSize)
  188. {
  189. // We create the new vertex buffer before releasing the old one to
  190. // prevent creating the buffer on the same place in memory
  191. DWORD dwUsage = D3DUSAGE_INTERNALBUFFER | D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
  192. IDirect3DIndexBuffer8 * pVB;
  193. HRESULT ret = CIndexBuffer::Create(pDDI->GetDevice(),
  194. RequiredSize,
  195. dwUsage,
  196. D3DFMT_INDEX16,
  197. D3DPOOL_DEFAULT,
  198. REF_INTERNAL,
  199. &pVB);
  200. if (ret != DD_OK)
  201. {
  202. D3D_THROW(ret, "Could not allocate internal index buffer");
  203. }
  204. if (m_pVBI)
  205. m_pVBI->DecrementUseCount();
  206. m_pVBI = static_cast<CIndexBuffer*>(pVB);
  207. m_dwSize = RequiredSize;
  208. }
  209. }
  210. //-----------------------------------------------------------------------------
  211. BYTE* CTLIndexStream::Lock(UINT NeededSize, CD3DDDIDX6* pDDI)
  212. {
  213. HRESULT ret;
  214. DXGASSERT(m_dwSize >= m_dwUsedSize);
  215. if (NeededSize > m_dwSize - m_dwUsedSize || m_dwUsedSize == 0)
  216. {
  217. Grow(NeededSize, pDDI);
  218. ret = m_pVBI->Lock(0, m_dwSize, &m_pData, D3DLOCK_DISCARD |
  219. D3DLOCK_NOSYSLOCK);
  220. this->Reset();
  221. }
  222. else
  223. {
  224. ret = m_pVBI->Lock(0, m_dwSize, &m_pData, D3DLOCK_NOOVERWRITE |
  225. D3DLOCK_NOSYSLOCK);
  226. }
  227. if (ret != DD_OK)
  228. {
  229. D3D_THROW(ret, "Could not lock internal index buffer");
  230. }
  231. // m_dwPrimitiveBase could be out of sync with m_dwUsedSize, because
  232. // sometimes we re-use vertices (like when clipping line strips). Make
  233. // sure that they are in sync.
  234. m_dwPrimitiveBase = m_dwUsedSize;
  235. return m_pData + m_dwUsedSize;
  236. }
  237. //-----------------------------------------------------------------------------
  238. BYTE* CTLIndexStream::LockDiscard(UINT NeededSize, CD3DDDIDX6* pDDI)
  239. {
  240. HRESULT ret;
  241. DXGASSERT(m_dwSize >= m_dwUsedSize);
  242. Grow(NeededSize, pDDI);
  243. ret = m_pVBI->Lock(0, m_dwSize, &m_pData, D3DLOCK_DISCARD |
  244. D3DLOCK_NOSYSLOCK);
  245. this->Reset();
  246. if (ret != DD_OK)
  247. {
  248. D3D_THROW(ret, "Could not lock internal index buffer");
  249. }
  250. // We have called Reset() so no need to set PrimitiveBase
  251. return m_pData;
  252. }
  253. //-----------------------------------------------------------------------------
  254. void CTLIndexStream::Unlock()
  255. {
  256. m_pVBI->Unlock();
  257. }
  258. //-----------------------------------------------------------------------------
  259. BYTE* CTLStreamRO::Lock(UINT NeededSize, CD3DDDIDX6* pDDI)
  260. {
  261. return m_pVB->Data();
  262. }
  263. //-----------------------------------------------------------------------------
  264. BYTE* CTLIndexStreamRO::Lock(UINT NeededSize, CD3DDDIDX6* pDDI)
  265. {
  266. return m_pVBI->Data();
  267. }
  268. /////////////////////////////////////////////////////////////////////////////
  269. // //
  270. // CD3DDDIDX8 //
  271. // //
  272. /////////////////////////////////////////////////////////////////////////////
  273. const DWORD CD3DDDIDX8::m_dwDummyVertexLength = 10;
  274. const DWORD CD3DDDIDX8::m_dwDummyVertexSize = sizeof(D3DVERTEX);
  275. CD3DDDIDX8::CD3DDDIDX8()
  276. {
  277. m_ddiType = D3DDDITYPE_DX8;
  278. m_pTLStream = NULL;
  279. m_pTLStreamRO = NULL;
  280. m_pTLStreamW = NULL;
  281. m_pCurrentTLStream = NULL;
  282. m_pIndexStream = NULL;
  283. m_pTLStreamClip = NULL;
  284. m_pCurrentIndexStream = NULL;
  285. m_pTLIndexStreamRO = NULL;
  286. m_dwInterfaceNumber = 4;
  287. m_pvDummyArray = NULL;
  288. }
  289. //-----------------------------------------------------------------------------
  290. CD3DDDIDX8::~CD3DDDIDX8()
  291. {
  292. // During deletion of the objects below, the Flush could happen.
  293. // We have to assing pointers to NULL to prevent accessing objects
  294. // during the Flush.
  295. m_pCurrentTLStream = NULL;
  296. delete m_pTLStreamW;
  297. m_pTLStreamW = NULL;
  298. delete m_pTLStream;
  299. m_pTLStream = NULL;
  300. delete m_pTLStreamRO;
  301. m_pTLStreamRO = NULL;
  302. delete m_pTLIndexStreamRO;
  303. m_pTLIndexStreamRO = NULL;
  304. delete m_pIndexStream;
  305. m_pIndexStream = NULL;
  306. delete m_pTLStreamClip;
  307. m_pTLStreamClip = NULL;
  308. if (m_pvDummyArray)
  309. {
  310. delete [] m_pvDummyArray;
  311. m_pvDummyArray = NULL;
  312. }
  313. delete m_pPointStream;
  314. m_pPointStream = NULL;
  315. return;
  316. }
  317. //---------------------------------------------------------------------
  318. #undef DPF_MODNAME
  319. #define DPF_MODNAME "CD3DDDIDX8::Init"
  320. void
  321. CD3DDDIDX8::Init(CD3DBase* pDevice)
  322. {
  323. // CD3DDDIDX6::Init( pDevice );
  324. m_pDevice = pDevice;
  325. CreateContext();
  326. GrowCommandBuffer(dwD3DDefaultCommandBatchSize);
  327. m_pvDummyArray =
  328. (VOID *)new BYTE[m_dwDummyVertexSize*m_dwDummyVertexLength];
  329. if( m_pvDummyArray == NULL )
  330. {
  331. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate dummy array");
  332. }
  333. // Fill the dp2data structure with initial values
  334. dp2data.dwFlags = D3DHALDP2_SWAPCOMMANDBUFFER;
  335. dp2data.dwVertexType = 0; // Initial assumption
  336. // We always pass this flag to prevent NT kernel from validation of vertex
  337. // buffer pointer
  338. dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES;
  339. SetDummyData();
  340. ClearBatch(FALSE);
  341. m_pTLStream = new CTLStream(FALSE);
  342. if (m_pTLStream == NULL)
  343. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStream");
  344. m_pTLStreamW = new CTLStream(TRUE);
  345. if (m_pTLStreamW == NULL)
  346. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStreamW");
  347. m_pTLStreamClip = new CTLStream(TRUE);
  348. if (m_pTLStreamClip == NULL)
  349. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStreamClip");
  350. m_pIndexStream = new CTLIndexStream();
  351. if (m_pIndexStream == NULL)
  352. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pIndexStream");
  353. m_pTLStreamRO = new CTLStreamRO();
  354. if (m_pTLStreamRO == NULL)
  355. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStreamRO");
  356. m_pTLIndexStreamRO = new CTLIndexStreamRO();
  357. if (m_pTLIndexStreamRO == NULL)
  358. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLIndexStreamRO");
  359. m_pTLStream->Grow(__INIT_VERTEX_NUMBER*2*sizeof(D3DTLVERTEX), this);
  360. m_pTLStreamW->Grow(__INIT_VERTEX_NUMBER*2*sizeof(D3DTLVERTEX), this);
  361. m_pTLStreamClip->Grow(__INIT_VERTEX_NUMBER*2*sizeof(D3DTLVERTEX), this);
  362. m_pIndexStream->Grow(__INIT_VERTEX_NUMBER*4, this);
  363. m_CurrentVertexShader = 0;
  364. m_pPointStream = new CTLStream(FALSE);
  365. if (m_pPointStream == NULL)
  366. D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal data structure CTLStream");
  367. #if DBG
  368. m_bValidateCommands = FALSE;
  369. #endif
  370. }
  371. //-----------------------------------------------------------------------------
  372. #undef DPF_MODNAME
  373. #define DPF_MODNAME "CD3DDDIDX8::ValidateDevice"
  374. void
  375. CD3DDDIDX8::ValidateDevice(LPDWORD lpdwNumPasses)
  376. {
  377. HRESULT ret;
  378. D3D8_VALIDATETEXTURESTAGESTATEDATA vd;
  379. memset( &vd, 0, sizeof( vd ) );
  380. vd.dwhContext = m_dwhContext;
  381. // First, Update textures since drivers pass /fail this call based
  382. // on the current texture handles
  383. m_pDevice->UpdateTextures();
  384. UpdateDirtyStreams();
  385. // Flush states, so we can validate the current state
  386. FlushStates();
  387. // Now ask the driver!
  388. ret = m_pDevice->GetHalCallbacks()->ValidateTextureStageState(&vd);
  389. *lpdwNumPasses = vd.dwNumPasses;
  390. if (ret != DDHAL_DRIVER_HANDLED)
  391. throw E_NOTIMPL;
  392. else if (FAILED(vd.ddrval))
  393. throw vd.ddrval;
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Sends "dirty" streams to the command buffer
  397. //
  398. #undef DPF_MODNAME
  399. #define DPF_MODNAME "CD3DDDIDX8::UpdateDirtyStreams"
  400. void CD3DDDIDX8::UpdateDirtyStreams()
  401. {
  402. DWORD dwNumStreams = m_pDevice->m_dwNumStreams;
  403. if (m_pDevice->m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)
  404. {
  405. // For software vertex processing we should update only stream 0
  406. // and index stream
  407. dwNumStreams = 1;
  408. }
  409. for(unsigned dwStream = 0, StreamMask = 1; dwStream <= dwNumStreams; dwStream++, StreamMask <<= 1)
  410. {
  411. // When max number of vertex stream is reached, process index stream
  412. if (dwStream == dwNumStreams)
  413. {
  414. dwStream = __NUMSTREAMS;
  415. StreamMask = (1 << __NUMSTREAMS);
  416. }
  417. BOOL bDirty = (m_pDevice->m_dwStreamDirty & StreamMask) != 0;
  418. m_pDevice->m_dwStreamDirty &= ~StreamMask; // reset stage dirty
  419. CBuffer *pBuf;
  420. if(dwStream < dwNumStreams)
  421. {
  422. pBuf = m_pDevice->m_pStream[dwStream].m_pVB;
  423. }
  424. else
  425. {
  426. pBuf = m_pDevice->m_pIndexStream->m_pVBI;
  427. }
  428. if(pBuf != 0)
  429. {
  430. if(pBuf->IsD3DManaged())
  431. {
  432. HRESULT result;
  433. result = m_pDevice->ResourceManager()->UpdateVideo(pBuf->RMHandle(), &bDirty);
  434. if(result != D3D_OK)
  435. {
  436. D3D_THROW(result, "Resource manager failed to create or update video memory VB/IB");
  437. }
  438. }
  439. }
  440. if (!bDirty)
  441. {
  442. continue;
  443. }
  444. if(dwStream < dwNumStreams)
  445. {
  446. InsertStreamSource(&m_pDevice->m_pStream[dwStream]);
  447. CDDIStream &Stream = m_pDDIStream[dwStream];
  448. Stream.m_pStream = &m_pDevice->m_pStream[dwStream];
  449. Stream.m_pBuf = pBuf;
  450. Stream.m_dwStride = m_pDevice->m_pStream[dwStream].m_dwStride;
  451. }
  452. else
  453. {
  454. DXGASSERT(dwStream == __NUMSTREAMS);
  455. InsertIndices(m_pDevice->m_pIndexStream);
  456. CDDIStream &Stream = m_pDDIStream[dwStream];
  457. Stream.m_pStream = m_pDevice->m_pIndexStream;
  458. Stream.m_pBuf = pBuf;
  459. Stream.m_dwStride = m_pDevice->m_pIndexStream->m_dwStride;
  460. }
  461. }
  462. }
  463. //-----------------------------------------------------------------------------
  464. #undef DPF_MODNAME
  465. #define DPF_MODNAME "CD3DDDIDX8::LockVB"
  466. HRESULT __declspec(nothrow) CD3DDDIDX8::LockVB(CDriverVertexBuffer *pVB, DWORD dwFlags)
  467. {
  468. HRESULT hr;
  469. if (pVB->GetCachedDataPointer() != 0) // if lock was cached
  470. {
  471. DXGASSERT((dwFlags & (D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE)) == 0);
  472. DXGASSERT((pVB->GetBufferDesc()->Usage & D3DUSAGE_DYNAMIC) != 0);
  473. hr = pVB->UnlockI();
  474. if(FAILED(hr))
  475. {
  476. DPF_ERR("Driver failed to unlock a vertex buffer"
  477. " when attempting to re-cache the lock.");
  478. pVB->SetCachedDataPointer(0);
  479. return hr;
  480. }
  481. }
  482. hr = pVB->LockI(dwFlags | D3DLOCK_NOSYSLOCK);
  483. if (FAILED(hr))
  484. {
  485. DPF_ERR("Driver failed to lock a vertex buffer"
  486. " when attempting to cache the lock.");
  487. pVB->SetCachedDataPointer(0);
  488. return hr;
  489. }
  490. return D3D_OK;
  491. }
  492. //-----------------------------------------------------------------------------
  493. #undef DPF_MODNAME
  494. #define DPF_MODNAME "CD3DDDIDX8::UnlockVB"
  495. HRESULT __declspec(nothrow) CD3DDDIDX8::UnlockVB(CDriverVertexBuffer *pVB)
  496. {
  497. return pVB->UnlockI();
  498. }
  499. //-----------------------------------------------------------------------------
  500. #undef DPF_MODNAME
  501. #define DPF_MODNAME "CD3DDDIDX8::SetTSS"
  502. void
  503. CD3DDDIDX8::SetTSS(DWORD dwStage,
  504. D3DTEXTURESTAGESTATETYPE dwState,
  505. DWORD dwValue)
  506. {
  507. // Filter unsupported states
  508. if (dwState >= m_pDevice->m_tssMax)
  509. return;
  510. if (bDP2CurrCmdOP == D3DDP2OP_TEXTURESTAGESTATE)
  511. { // Last instruction is a texture stage state, append this one to it
  512. if (dwDP2CommandLength + sizeof(D3DHAL_DP2TEXTURESTAGESTATE) <=
  513. dwDP2CommandBufSize)
  514. {
  515. LPD3DHAL_DP2TEXTURESTAGESTATE lpRState =
  516. (LPD3DHAL_DP2TEXTURESTAGESTATE)((LPBYTE)lpvDP2Commands +
  517. dwDP2CommandLength + dp2data.dwCommandOffset);
  518. lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
  519. lpRState->wStage = (WORD)dwStage;
  520. lpRState->TSState = (WORD)dwState;
  521. lpRState->dwValue = dwValue;
  522. dwDP2CommandLength += sizeof(D3DHAL_DP2TEXTURESTAGESTATE);
  523. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  524. return;
  525. }
  526. }
  527. // Check for space
  528. if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  529. sizeof(D3DHAL_DP2TEXTURESTAGESTATE) > dwDP2CommandBufSize)
  530. {
  531. FlushStates();
  532. }
  533. // Add new renderstate instruction
  534. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  535. dwDP2CommandLength + dp2data.dwCommandOffset);
  536. lpDP2CurrCommand->bCommand = D3DDP2OP_TEXTURESTAGESTATE;
  537. bDP2CurrCmdOP = D3DDP2OP_TEXTURESTAGESTATE;
  538. lpDP2CurrCommand->bReserved = 0;
  539. lpDP2CurrCommand->wStateCount = 1;
  540. wDP2CurrCmdCnt = 1;
  541. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  542. // Add renderstate data
  543. LPD3DHAL_DP2TEXTURESTAGESTATE lpRState =
  544. (LPD3DHAL_DP2TEXTURESTAGESTATE)(lpDP2CurrCommand + 1);
  545. lpRState->wStage = (WORD)dwStage;
  546. lpRState->TSState = (WORD)dwState;
  547. lpRState->dwValue = dwValue;
  548. dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) +
  549. sizeof(D3DHAL_DP2TEXTURESTAGESTATE);
  550. }
  551. //-----------------------------------------------------------------------------
  552. #undef DPF_MODNAME
  553. #define DPF_MODNAME "CD3DDDIDX8::CreatePixelShader"
  554. void
  555. CD3DDDIDX8::CreatePixelShader(CONST DWORD* pdwFunction,
  556. DWORD dwCodeSize,
  557. DWORD dwHandle)
  558. {
  559. FlushStates();
  560. LPD3DHAL_DP2CREATEPIXELSHADER pData;
  561. pData = (LPD3DHAL_DP2CREATEPIXELSHADER)
  562. GetHalBufferPointer(D3DDP2OP_CREATEPIXELSHADER,
  563. sizeof(*pData) + dwCodeSize);
  564. pData->dwHandle = dwHandle;
  565. pData->dwCodeSize = dwCodeSize;
  566. LPBYTE p = (LPBYTE)&pData[1];
  567. memcpy(p, pdwFunction, dwCodeSize);
  568. FlushStates(TRUE,FALSE);
  569. }
  570. //-----------------------------------------------------------------------------
  571. #undef DPF_MODNAME
  572. #define DPF_MODNAME "CD3DDDIDX8::SetPixelShader"
  573. void
  574. CD3DDDIDX8::SetPixelShader( DWORD dwHandle )
  575. {
  576. LPD3DHAL_DP2PIXELSHADER pData;
  577. pData = (LPD3DHAL_DP2PIXELSHADER)
  578. GetHalBufferPointer(D3DDP2OP_SETPIXELSHADER, sizeof(*pData));
  579. pData->dwHandle = dwHandle;
  580. }
  581. //-----------------------------------------------------------------------------
  582. #undef DPF_MODNAME
  583. #define DPF_MODNAME "CD3DDDIDX8::DeletePixelShader"
  584. void
  585. CD3DDDIDX8::DeletePixelShader(DWORD dwHandle)
  586. {
  587. LPD3DHAL_DP2PIXELSHADER pData;
  588. pData = (LPD3DHAL_DP2PIXELSHADER)
  589. GetHalBufferPointer(D3DDP2OP_DELETEPIXELSHADER, sizeof(*pData));
  590. pData->dwHandle = dwHandle;
  591. }
  592. //-----------------------------------------------------------------------------
  593. #undef DPF_MODNAME
  594. #define DPF_MODNAME "CD3DDDIDX8::SetPixelShaderConstant"
  595. void
  596. CD3DDDIDX8::SetPixelShaderConstant(DWORD dwRegister, CONST VOID* data,
  597. DWORD count)
  598. {
  599. const DWORD size = count << 4;
  600. LPD3DHAL_DP2SETPIXELSHADERCONST pData;
  601. pData = (LPD3DHAL_DP2SETPIXELSHADERCONST)
  602. GetHalBufferPointer(D3DDP2OP_SETPIXELSHADERCONST,
  603. sizeof(*pData) + size);
  604. pData->dwRegister = dwRegister;
  605. pData->dwCount = count;
  606. memcpy(pData+1, data, size);
  607. }
  608. //-----------------------------------------------------------------------------
  609. // Inserts SetStreamSource command into the command buffer
  610. //
  611. #undef DPF_MODNAME
  612. #define DPF_MODNAME "CD3DDDIDX8::InsertStreamSource"
  613. void
  614. CD3DDDIDX8::InsertStreamSource(CVStream* pStream)
  615. {
  616. if (pStream->IsUserMemStream())
  617. {
  618. InsertStreamSourceUP(pStream->m_dwStride);
  619. return;
  620. }
  621. LPD3DHAL_DP2SETSTREAMSOURCE pData;
  622. pData = (LPD3DHAL_DP2SETSTREAMSOURCE)
  623. GetHalBufferPointer(D3DDP2OP_SETSTREAMSOURCE, sizeof(*pData));
  624. pData->dwStream = pStream->m_dwIndex;
  625. pData->dwVBHandle = pStream->m_pVB != 0 ? pStream->m_pVB->DriverAccessibleDrawPrimHandle() : 0;
  626. pData->dwStride = pStream->m_dwStride;
  627. CDDIStream* pDDIStream = &m_pDDIStream[pStream->m_dwIndex];
  628. pDDIStream->m_dwStride = pStream->m_dwStride;
  629. pDDIStream->m_pStream = pStream;
  630. pDDIStream->m_pBuf = pStream->m_pVB;
  631. if (pStream->m_pVB != 0)
  632. {
  633. pStream->m_pVB->Batch();
  634. }
  635. }
  636. //-----------------------------------------------------------------------------
  637. #undef DPF_MODNAME
  638. #define DPF_MODNAME "CD3DDDIDX8::InsertStreamSourceUP"
  639. void
  640. CD3DDDIDX8::InsertStreamSourceUP(DWORD dwStride)
  641. {
  642. // User memory source
  643. LPD3DHAL_DP2SETSTREAMSOURCEUM pData;
  644. pData = (LPD3DHAL_DP2SETSTREAMSOURCEUM)
  645. GetHalBufferPointer(D3DDP2OP_SETSTREAMSOURCEUM, sizeof(*pData));
  646. pData->dwStream = 0;
  647. pData->dwStride = dwStride;
  648. CDDIStream* pDDIStream = &m_pDDIStream[0];
  649. pDDIStream->m_dwStride = dwStride;
  650. pDDIStream->m_pStream = NULL;
  651. pDDIStream->m_pBuf = NULL;
  652. }
  653. //-----------------------------------------------------------------------------
  654. #undef DPF_MODNAME
  655. #define DPF_MODNAME "CD3DDDIDX8::InsertIndices"
  656. void
  657. CD3DDDIDX8::InsertIndices(CVIndexStream* pStream)
  658. {
  659. LPD3DHAL_DP2SETINDICES pData;
  660. pData = (LPD3DHAL_DP2SETINDICES)
  661. GetHalBufferPointer(D3DDP2OP_SETINDICES, sizeof(*pData));
  662. pData->dwVBHandle = pStream->m_pVBI != 0 ? pStream->m_pVBI->DriverAccessibleDrawPrimHandle() : 0;
  663. pData->dwStride = pStream->m_dwStride;
  664. m_pDDIStream[__NUMSTREAMS].m_dwStride = pStream->m_dwStride;
  665. m_pDDIStream[__NUMSTREAMS].m_pStream = pStream;
  666. m_pDDIStream[__NUMSTREAMS].m_pBuf = pStream->m_pVBI;
  667. if(pStream->m_pVBI != 0)
  668. {
  669. pStream->m_pVBI->Batch();
  670. }
  671. }
  672. //-----------------------------------------------------------------------------
  673. #undef DPF_MODNAME
  674. #define DPF_MODNAME "CD3DDDIDX8_DrawPrimitive"
  675. void
  676. CD3DDDIDX8_DrawPrimitive(CD3DBase* pDevice, D3DPRIMITIVETYPE PrimitiveType,
  677. UINT StartVertex, UINT PrimitiveCount)
  678. {
  679. #if DBG
  680. if (!(pDevice->BehaviorFlags() & D3DCREATE_PUREDEVICE))
  681. {
  682. CD3DHal* pDev = static_cast<CD3DHal*>(pDevice);
  683. UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
  684. pDev->ValidateDraw2(PrimitiveType, StartVertex, PrimitiveCount,
  685. nVer, FALSE);
  686. }
  687. #endif // DBG
  688. CD3DDDIDX8* pDDI = static_cast<CD3DDDIDX8*>(pDevice->m_pDDI);
  689. if(pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  690. {
  691. pDevice->UpdateTextures();
  692. pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  693. }
  694. if (pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  695. {
  696. pDDI->UpdateDirtyStreams();
  697. pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  698. }
  699. if (pDDI->bDP2CurrCmdOP == D3DDP2OP_DRAWPRIMITIVE)
  700. { // Last instruction is a DrawPrimitive, append this one to it
  701. //
  702. // First check if the new instruction is a TRIANGLELIST. If it is,
  703. // AND if the new StartVertex = prev StartVertex + prev PrimitiveCount * 3
  704. // then we can simply bump up the prev primitive count. This makes
  705. // drivers go a LOT faster. (snene - 12/00)
  706. //
  707. //!!!!!!!!!!!!!!!!!!!!!!!!!!ALERT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  708. // The following code READS BACK from the batched command. This is
  709. // NOT a problem for sysmem command buffers in DX8. However, going
  710. // forward, if we ever implement vidmem command buffers, we need
  711. // to FIX this code to not read back. (snene - 12/00)
  712. LPD3DHAL_DP2DRAWPRIMITIVE pData = (LPD3DHAL_DP2DRAWPRIMITIVE)
  713. ((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength - sizeof(D3DHAL_DP2DRAWPRIMITIVE) +
  714. pDDI->dp2data.dwCommandOffset);
  715. if(pData->primType == D3DPT_TRIANGLELIST &&
  716. pData->primType == PrimitiveType &&
  717. pData->VStart + pData->PrimitiveCount * 3 == StartVertex &&
  718. pData->PrimitiveCount + PrimitiveCount >= pData->PrimitiveCount) // overflow
  719. {
  720. pData->PrimitiveCount += PrimitiveCount;
  721. return;
  722. }
  723. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  724. if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2DRAWPRIMITIVE) <=
  725. pDDI->dwDP2CommandBufSize)
  726. {
  727. ++pData;
  728. pDDI->lpDP2CurrCommand->wStateCount = ++pDDI->wDP2CurrCmdCnt;
  729. pData->primType = PrimitiveType;
  730. pData->VStart = StartVertex;
  731. pData->PrimitiveCount = PrimitiveCount;
  732. pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2DRAWPRIMITIVE);
  733. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand);
  734. return;
  735. }
  736. }
  737. // Check for space
  738. if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  739. sizeof(D3DHAL_DP2DRAWPRIMITIVE) > pDDI->dwDP2CommandBufSize)
  740. {
  741. pDDI->FlushStates();
  742. }
  743. // Add new DrawPrimitive instruction
  744. pDDI->lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)pDDI->lpvDP2Commands +
  745. pDDI->dwDP2CommandLength + pDDI->dp2data.dwCommandOffset);
  746. pDDI->lpDP2CurrCommand->bCommand = D3DDP2OP_DRAWPRIMITIVE;
  747. pDDI->bDP2CurrCmdOP = D3DDP2OP_DRAWPRIMITIVE;
  748. pDDI->lpDP2CurrCommand->bReserved = 0;
  749. pDDI->lpDP2CurrCommand->wStateCount = 1;
  750. pDDI->wDP2CurrCmdCnt = 1;
  751. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand);
  752. // Add DrawPrimitive data
  753. LPD3DHAL_DP2DRAWPRIMITIVE pData;
  754. pData = (LPD3DHAL_DP2DRAWPRIMITIVE)(pDDI->lpDP2CurrCommand + 1);
  755. pData->primType = PrimitiveType;
  756. pData->VStart = StartVertex;
  757. pData->PrimitiveCount = PrimitiveCount;
  758. pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) +
  759. sizeof(D3DHAL_DP2DRAWPRIMITIVE);
  760. }
  761. //-----------------------------------------------------------------------------
  762. #undef DPF_MODNAME
  763. #define DPF_MODNAME "CD3DDDIDX8::SetDummyData"
  764. void
  765. CD3DDDIDX8::SetDummyData()
  766. {
  767. dp2data.dwVertexSize = m_dwDummyVertexSize;
  768. dp2data.lpVertices = m_pvDummyArray;
  769. dp2data.dwVertexLength = m_dwDummyVertexLength;
  770. }
  771. //-----------------------------------------------------------------------------
  772. #undef DPF_MODNAME
  773. #define DPF_MODNAME "CD3DDDIDX8_DrawIndexedPrimitive"
  774. void
  775. CD3DDDIDX8_DrawIndexedPrimitive(CD3DBase* pDevice,
  776. D3DPRIMITIVETYPE PrimitiveType,
  777. UINT BaseVertexIndex,
  778. UINT MinIndex, UINT NumVertices,
  779. UINT StartIndex, UINT PrimitiveCount)
  780. {
  781. #if DBG
  782. if (!(pDevice->BehaviorFlags() & D3DCREATE_PUREDEVICE))
  783. {
  784. CD3DHal* pDev = static_cast<CD3DHal*>(pDevice);
  785. pDev->ValidateDraw2(PrimitiveType, MinIndex + BaseVertexIndex,
  786. PrimitiveCount, NumVertices, TRUE, StartIndex);
  787. }
  788. #endif // DBG
  789. CD3DDDIDX8* pDDI = static_cast<CD3DDDIDX8*>(pDevice->m_pDDI);
  790. if(pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  791. {
  792. pDevice->UpdateTextures();
  793. pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  794. }
  795. if (pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  796. {
  797. pDDI->UpdateDirtyStreams();
  798. pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  799. }
  800. if (pDDI->bDP2CurrCmdOP == D3DDP2OP_DRAWINDEXEDPRIMITIVE)
  801. { // Last instruction is a DrawIndexedPrimitive, append this one to it
  802. //
  803. // First check if the new instruction is a TRIANGLELIST. If it is,
  804. // AND if the new StartIndex = prev StartIndex + prev PrimitiveCount * 3
  805. // AND if the new BaseVertexIndex = prev BaseVertexIndex
  806. // then we can simply bump up the prev primitive count. This makes
  807. // drivers go a LOT faster. (snene - 12/00)
  808. //
  809. //!!!!!!!!!!!!!!!!!!!!!!!!!!ALERT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  810. // The following code READS BACK from the batched command. This is
  811. // NOT a problem for sysmem command buffers in DX8. However, going
  812. // forward, if we ever implement vidmem command buffers, we need
  813. // to FIX this code to not read back. (snene - 12/00)
  814. LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE)
  815. ((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength - sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE) +
  816. pDDI->dp2data.dwCommandOffset);
  817. if(pData->primType == D3DPT_TRIANGLELIST &&
  818. pData->primType == PrimitiveType &&
  819. pData->BaseVertexIndex == BaseVertexIndex &&
  820. pData->StartIndex + pData->PrimitiveCount * 3 == StartIndex &&
  821. pData->PrimitiveCount + PrimitiveCount >= pData->PrimitiveCount) // overflow
  822. {
  823. UINT mnidx = min(pData->MinIndex, MinIndex);
  824. UINT mxidx = max(pData->MinIndex + pData->NumVertices, MinIndex + NumVertices);
  825. if(mxidx - mnidx <= pData->NumVertices + NumVertices)
  826. {
  827. pData->NumVertices = mxidx - mnidx;
  828. pData->MinIndex = mnidx;
  829. pData->PrimitiveCount += PrimitiveCount;
  830. return;
  831. }
  832. }
  833. //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  834. if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE) <=
  835. pDDI->dwDP2CommandBufSize)
  836. {
  837. ++pData;
  838. pDDI->lpDP2CurrCommand->wStateCount = ++pDDI->wDP2CurrCmdCnt;
  839. pData->BaseVertexIndex = BaseVertexIndex;
  840. pData->primType = PrimitiveType;
  841. pData->PrimitiveCount = PrimitiveCount;
  842. pData->MinIndex = MinIndex;
  843. pData->NumVertices = NumVertices;
  844. pData->StartIndex = StartIndex;
  845. pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE);
  846. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand);
  847. return;
  848. }
  849. }
  850. // Check for space
  851. if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  852. sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE) > pDDI->dwDP2CommandBufSize)
  853. {
  854. pDDI->FlushStates();
  855. }
  856. // Add new DrawIndexedPrimitive instruction
  857. pDDI->lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)pDDI->lpvDP2Commands +
  858. pDDI->dwDP2CommandLength + pDDI->dp2data.dwCommandOffset);
  859. pDDI->lpDP2CurrCommand->bCommand = D3DDP2OP_DRAWINDEXEDPRIMITIVE;
  860. pDDI->bDP2CurrCmdOP = D3DDP2OP_DRAWINDEXEDPRIMITIVE;
  861. pDDI->lpDP2CurrCommand->bReserved = 0;
  862. pDDI->lpDP2CurrCommand->wStateCount = 1;
  863. pDDI->wDP2CurrCmdCnt = 1;
  864. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand);
  865. // Add DrawIndexedPrimitive data
  866. LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pData;
  867. pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE)(pDDI->lpDP2CurrCommand + 1);
  868. pData->BaseVertexIndex = BaseVertexIndex;
  869. pData->primType = PrimitiveType;
  870. pData->PrimitiveCount = PrimitiveCount;
  871. pData->MinIndex = MinIndex;
  872. pData->NumVertices = NumVertices;
  873. pData->StartIndex = StartIndex;
  874. pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) +
  875. sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE);
  876. #if DBG
  877. // if (m_bValidateCommands)
  878. // ValidateCommand(lpDP2CurrCommand);
  879. #endif
  880. }
  881. //-----------------------------------------------------------------------------
  882. #undef DPF_MODNAME
  883. #define DPF_MODNAME "CD3DDDIDX8::DrawPrimitiveUP"
  884. void
  885. CD3DDDIDX8::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount)
  886. {
  887. UINT NumVertices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
  888. if (NumVertices > LOWVERTICESNUMBER)
  889. {
  890. if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  891. {
  892. UpdateDirtyStreams();
  893. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  894. }
  895. this->FlushStates();
  896. dp2data.dwVertexType = 0;
  897. dp2data.dwVertexSize = m_pDevice->m_pStream[0].m_dwStride;
  898. dp2data.lpVertices = m_pDevice->m_pStream[0].m_pData;
  899. dp2data.dwVertexLength = NumVertices;
  900. try
  901. {
  902. InsertStreamSourceUP(m_pDevice->m_pStream[0].m_dwStride);
  903. CD3DDDIDX8_DrawPrimitive(m_pDevice, PrimitiveType, 0, PrimitiveCount);
  904. this->FlushStates();
  905. }
  906. catch( HRESULT hr )
  907. {
  908. SetDummyData();
  909. throw hr;
  910. }
  911. SetDummyData();
  912. }
  913. else
  914. {
  915. // Copy vertices to the internal TL buffer
  916. UINT VertexSize = m_pDevice->m_pStream[0].m_dwStride;
  917. // When vertex size has been changed we need to start from the
  918. // beginning of the vertex buffer to correctly handle vertex offsets
  919. if (m_pTLStreamW->GetPrimitiveBase() % VertexSize)
  920. {
  921. this->FlushStates();
  922. m_pTLStreamW->Reset();
  923. }
  924. // Copy vertices into the internal write only buffer
  925. m_pTLStreamW->SetVertexSize(VertexSize);
  926. UINT VertexPoolSize = VertexSize * NumVertices;
  927. LPVOID lpvOut = m_pTLStreamW->Lock(VertexPoolSize, this);
  928. UINT StartVertex = m_pTLStreamW->GetPrimitiveBase() / VertexSize;
  929. memcpy(lpvOut, m_pDevice->m_pStream[0].m_pData, VertexPoolSize);
  930. m_pTLStreamW->Unlock();
  931. m_pTLStreamW->SkipVertices(NumVertices);
  932. // To prevent overriding of stream 0 we clear D3DRT_NEED_VB_UPDATE and
  933. // stream dirty bit. We need to clear the stream dirty bit, because during
  934. // UpdateTextures D3DRT_NEED_VB_UPDATE could be set again
  935. DWORD dwRuntimeFlags = m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE;
  936. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  937. m_pDevice->m_dwStreamDirty &= ~1;
  938. if (m_pDDIStream[0].m_pBuf != m_pTLStreamW->m_pVB ||
  939. m_pDDIStream[0].m_dwStride != m_pTLStreamW->m_dwStride)
  940. {
  941. InsertStreamSource(m_pTLStreamW);
  942. }
  943. #if DBG
  944. // Need this to pass validation
  945. m_pDevice->m_pStream[0].m_dwNumVertices = StartVertex + NumVertices;
  946. #endif
  947. // Insert drawing command
  948. CD3DDDIDX8_DrawPrimitive(m_pDevice, PrimitiveType, StartVertex, PrimitiveCount);
  949. m_pDevice->m_dwRuntimeFlags |= dwRuntimeFlags;
  950. }
  951. }
  952. //-----------------------------------------------------------------------------
  953. #undef DPF_MODNAME
  954. #define DPF_MODNAME "CD3DDDIDX8::DrawIndexedPrimitiveUP"
  955. void
  956. CD3DDDIDX8::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType,
  957. UINT MinVertexIndex,
  958. UINT NumVertices,
  959. UINT PrimitiveCount)
  960. {
  961. if (NumVertices > LOWVERTICESNUMBER)
  962. {
  963. if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  964. {
  965. UpdateDirtyStreams();
  966. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  967. }
  968. this->FlushStates();
  969. dp2data.dwVertexType = 0;
  970. dp2data.dwVertexSize = m_pDevice->m_pStream[0].m_dwStride;
  971. dp2data.lpVertices = m_pDevice->m_pStream[0].m_pData;
  972. dp2data.dwVertexLength = NumVertices;
  973. try
  974. {
  975. InsertStreamSourceUP(m_pDevice->m_pStream[0].m_dwStride);
  976. UINT NumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
  977. m_pIndexStream->SetVertexSize(m_pDevice->m_pIndexStream->m_dwStride);
  978. // Always start from the beginning of the index stream
  979. // Copy indices into the internal stream
  980. DWORD dwIndicesByteCount = NumIndices * m_pIndexStream->m_dwStride;
  981. BYTE* pIndexData = m_pIndexStream->LockDiscard(dwIndicesByteCount, this);
  982. memcpy(pIndexData, m_pDevice->m_pIndexStream->m_pData, dwIndicesByteCount);
  983. m_pIndexStream->Unlock();
  984. InsertIndices(m_pIndexStream);
  985. CD3DDDIDX8_DrawIndexedPrimitive(m_pDevice, PrimitiveType, 0,
  986. MinVertexIndex, NumVertices, 0,
  987. PrimitiveCount);
  988. this->FlushStates();
  989. }
  990. catch( HRESULT hr )
  991. {
  992. SetDummyData();
  993. throw hr;
  994. }
  995. SetDummyData();
  996. }
  997. else
  998. {
  999. // Copy user data into internal buffers
  1000. UINT VertexSize = m_pDevice->m_pStream[0].m_dwStride;
  1001. UINT IndexSize = m_pDevice->m_pIndexStream->m_dwStride;
  1002. if ((m_pTLStreamW->GetPrimitiveBase() % VertexSize) ||
  1003. (m_pIndexStream->GetPrimitiveBase() % IndexSize))
  1004. {
  1005. this->FlushStates();
  1006. m_pTLStreamW->Reset();
  1007. m_pIndexStream->Reset();
  1008. }
  1009. // Copy vertices into the internal write only buffer
  1010. m_pTLStreamW->SetVertexSize(VertexSize);
  1011. UINT VertexPoolSize = VertexSize * NumVertices;
  1012. LPVOID lpvOut = m_pTLStreamW->Lock(VertexPoolSize, this);
  1013. UINT StartVertex = m_pTLStreamW->GetPrimitiveBase() / VertexSize;
  1014. UINT FirstVertexOffset = MinVertexIndex * VertexSize;
  1015. memcpy(lpvOut, m_pDevice->m_pStream[0].m_pData + FirstVertexOffset,
  1016. VertexPoolSize);
  1017. m_pTLStreamW->Unlock();
  1018. m_pTLStreamW->SkipVertices(NumVertices);
  1019. // To prevent overriding of stream 0 we clear D3DRT_NEED_VB_UPDATE and
  1020. // stream dirty bit. We need to clear the stream dirty bit, because during
  1021. // UpdateTextures D3DRT_NEED_VB_UPDATE could be set again
  1022. DWORD dwRuntimeFlags = m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE;
  1023. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  1024. m_pDevice->m_dwStreamDirty &= ~(1 | (1 << __NUMSTREAMS));
  1025. if (m_pDDIStream[0].m_pBuf != m_pTLStreamW->m_pVB ||
  1026. m_pDDIStream[0].m_dwStride != m_pTLStreamW->m_dwStride)
  1027. {
  1028. InsertStreamSource(m_pTLStreamW);
  1029. }
  1030. // Copy indices into the internal buffer. Re-base indices if necessery.
  1031. m_pIndexStream->SetVertexSize(IndexSize);
  1032. UINT NumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
  1033. UINT IndexPoolSize = IndexSize * NumIndices;
  1034. lpvOut = m_pIndexStream->Lock(IndexPoolSize, this);
  1035. UINT StartIndex = m_pIndexStream->GetPrimitiveBase() / IndexSize;
  1036. memcpy(lpvOut, m_pDevice->m_pIndexStream->m_pData, IndexPoolSize);
  1037. m_pIndexStream->Unlock();
  1038. m_pIndexStream->SkipVertices(NumIndices);
  1039. if (m_pDDIStream[__NUMSTREAMS].m_pBuf != m_pIndexStream->m_pVBI ||
  1040. m_pDDIStream[__NUMSTREAMS].m_dwStride != m_pIndexStream->m_dwStride)
  1041. {
  1042. InsertIndices(m_pIndexStream);
  1043. }
  1044. #if DBG
  1045. // Need this to pass validation
  1046. m_pDevice->m_pStream[0].m_dwNumVertices = StartVertex + NumVertices;
  1047. m_pDevice->m_pIndexStream->m_dwNumVertices = StartIndex + NumIndices;
  1048. #endif
  1049. // Draw primitive
  1050. CD3DDDIDX8_DrawIndexedPrimitive(m_pDevice, PrimitiveType,
  1051. StartVertex - MinVertexIndex,
  1052. MinVertexIndex, NumVertices, StartIndex,
  1053. PrimitiveCount);
  1054. m_pDevice->m_dwRuntimeFlags |= dwRuntimeFlags;
  1055. }
  1056. }
  1057. //-----------------------------------------------------------------------------
  1058. #undef DPF_MODNAME
  1059. #define DPF_MODNAME "CD3DDDIDX8::DrawRectPatch"
  1060. void
  1061. CD3DDDIDX8::DrawRectPatch(UINT Handle, CONST D3DRECTPATCH_INFO *pSurf,
  1062. CONST FLOAT *pNumSegs)
  1063. {
  1064. if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  1065. {
  1066. m_pDevice->UpdateTextures();
  1067. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  1068. }
  1069. if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  1070. {
  1071. UpdateDirtyStreams();
  1072. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  1073. }
  1074. LPD3DHAL_DP2DRAWRECTPATCH pData;
  1075. pData = (LPD3DHAL_DP2DRAWRECTPATCH)
  1076. GetHalBufferPointer(D3DDP2OP_DRAWRECTPATCH,
  1077. sizeof(*pData) + (pSurf != 0 ? sizeof(D3DRECTPATCH_INFO) : 0) + (pNumSegs != 0 ? sizeof(FLOAT) * 4 : 0));
  1078. pData->Handle = Handle;
  1079. DWORD offset;
  1080. if(pNumSegs != 0)
  1081. {
  1082. offset = sizeof(FLOAT) * 4;
  1083. memcpy(pData + 1, pNumSegs, offset);
  1084. pData->Flags = RTPATCHFLAG_HASSEGS;
  1085. }
  1086. else
  1087. {
  1088. pData->Flags = 0;
  1089. offset = 0;
  1090. }
  1091. if(pSurf != 0)
  1092. {
  1093. memcpy((BYTE*)(pData + 1) + offset, pSurf, sizeof(D3DRECTPATCH_INFO));
  1094. pData->Flags |= RTPATCHFLAG_HASINFO;
  1095. }
  1096. }
  1097. //-----------------------------------------------------------------------------
  1098. #undef DPF_MODNAME
  1099. #define DPF_MODNAME "CD3DDDIDX8::DrawTriSurface"
  1100. void
  1101. CD3DDDIDX8::DrawTriPatch(UINT Handle, CONST D3DTRIPATCH_INFO *pSurf,
  1102. CONST FLOAT *pNumSegs)
  1103. {
  1104. if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  1105. {
  1106. m_pDevice->UpdateTextures();
  1107. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  1108. }
  1109. if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  1110. {
  1111. UpdateDirtyStreams();
  1112. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  1113. }
  1114. LPD3DHAL_DP2DRAWTRIPATCH pData;
  1115. pData = (LPD3DHAL_DP2DRAWTRIPATCH)
  1116. GetHalBufferPointer(D3DDP2OP_DRAWTRIPATCH,
  1117. sizeof(*pData) + (pSurf != 0 ? sizeof(D3DTRIPATCH_INFO) : 0) + (pNumSegs != 0 ? sizeof(FLOAT) * 3 : 0));
  1118. pData->Handle = Handle;
  1119. DWORD offset;
  1120. if(pNumSegs != 0)
  1121. {
  1122. offset = sizeof(FLOAT) * 3;
  1123. memcpy(pData + 1, pNumSegs, offset);
  1124. pData->Flags = RTPATCHFLAG_HASSEGS;
  1125. }
  1126. else
  1127. {
  1128. pData->Flags = 0;
  1129. offset = 0;
  1130. }
  1131. if(pSurf != 0)
  1132. {
  1133. memcpy((BYTE*)(pData + 1) + offset, pSurf, sizeof(D3DTRIPATCH_INFO));
  1134. pData->Flags |= RTPATCHFLAG_HASINFO;
  1135. }
  1136. }
  1137. //-----------------------------------------------------------------------------
  1138. // This function prepares the batch for new primitive.
  1139. // Called only if vertices from user memory are NOT used for rendering
  1140. //
  1141. #undef DPF_MODNAME
  1142. #define DPF_MODNAME "CD3DDDIDX8::StartPrimVB"
  1143. void
  1144. CD3DDDIDX8::StartPrimVB(D3DFE_PROCESSVERTICES * pv, CVStream* pStream,
  1145. DWORD dwStartVertex)
  1146. {
  1147. SetWithinPrimitive(TRUE);
  1148. UINT size = dwStartVertex * pv->dwOutputSize;
  1149. if (pStream)
  1150. m_pTLStreamRO->Init(pStream->m_pVB, size);
  1151. else
  1152. m_pTLStreamRO->Init(NULL, size);
  1153. m_pTLStreamRO->SetVertexSize(pv->dwOutputSize);
  1154. m_pCurrentTLStream = m_pTLStreamRO;
  1155. }
  1156. //-----------------------------------------------------------------------------
  1157. // This function prepares the batch for new primitive.
  1158. // Called only if vertices from user memory are NOT used for rendering
  1159. //
  1160. #undef DPF_MODNAME
  1161. #define DPF_MODNAME "CD3DDDIDX8::StartIndexPrimVB"
  1162. void
  1163. CD3DDDIDX8::StartIndexPrimVB(CVIndexStream* pStream, UINT StartIndex,
  1164. UINT IndexSize)
  1165. {
  1166. m_pTLIndexStreamRO->Init(pStream->m_pVBI, StartIndex * IndexSize);
  1167. m_pTLIndexStreamRO->SetVertexSize(IndexSize);
  1168. m_pCurrentIndexStream = m_pTLIndexStreamRO;
  1169. }
  1170. //-----------------------------------------------------------------------------
  1171. // This function prepares the batch for new primitive.
  1172. // Called when the runtime needs to output vertices to a TL buffer
  1173. // TL buffer grows if necessary
  1174. //
  1175. // Uses the following global variables:
  1176. // pv->dwOutputSize
  1177. // Sets "within primitive" to TRUE
  1178. // Returns:
  1179. // TL buffer address
  1180. //
  1181. //
  1182. #undef DPF_MODNAME
  1183. #define DPF_MODNAME "CD3DDDIDX8::StartPrimTL"
  1184. LPVOID
  1185. CD3DDDIDX8::StartPrimTL(D3DFE_PROCESSVERTICES * pv, DWORD dwVertexPoolSize,
  1186. BOOL bWriteOnly)
  1187. {
  1188. CTLStream* pStream = bWriteOnly? m_pTLStreamW : m_pTLStream;
  1189. LPVOID p = pStream->Lock(dwVertexPoolSize, this);
  1190. pStream->SetVertexSize(pv->dwOutputSize);
  1191. m_pCurrentTLStream = pStream;
  1192. SetWithinPrimitive(TRUE);
  1193. return p;
  1194. }
  1195. //---------------------------------------------------------------------
  1196. // Uses the following members of D3DFE_PROCESSVERTICES:
  1197. // primType
  1198. // dwNumVertices
  1199. // dwNumPrimitives
  1200. //
  1201. #undef DPF_MODNAME
  1202. #define DPF_MODNAME "CD3DDDIDX8::DrawPrim"
  1203. void
  1204. CD3DDDIDX8::DrawPrim(D3DFE_PROCESSVERTICES* pv)
  1205. {
  1206. #ifdef DEBUG_PIPELINE
  1207. if (g_DebugFlags & __DEBUG_NORENDERING)
  1208. return;
  1209. #endif
  1210. if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  1211. {
  1212. m_pDevice->UpdateTextures();
  1213. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  1214. }
  1215. if (m_pDDIStream[0].m_pBuf != static_cast<CBuffer*>(m_pCurrentTLStream->m_pVB) ||
  1216. pv->dwOutputSize != m_pDDIStream[0].m_dwStride)
  1217. {
  1218. InsertStreamSource(m_pCurrentTLStream);
  1219. // API stream should be set dirty, in case it is later passed to DDI directly
  1220. m_pDevice->m_dwStreamDirty |= 1;
  1221. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE;
  1222. }
  1223. if (pv->primType == D3DPT_POINTLIST &&
  1224. pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION)
  1225. {
  1226. DrawPrimPS(pv);
  1227. return;
  1228. }
  1229. LPD3DHAL_DP2DRAWPRIMITIVE2 pData;
  1230. pData = (LPD3DHAL_DP2DRAWPRIMITIVE2)
  1231. GetHalBufferPointer(D3DDP2OP_DRAWPRIMITIVE2, sizeof(*pData));
  1232. pData->primType = pv->primType;
  1233. pData->FirstVertexOffset = m_pCurrentTLStream->GetPrimitiveBase();
  1234. pData->PrimitiveCount = pv->dwNumPrimitives;
  1235. m_pCurrentTLStream->SkipVertices(pv->dwNumVertices);
  1236. #if DBG
  1237. if (m_bValidateCommands)
  1238. ValidateCommand(lpDP2CurrCommand);
  1239. #endif
  1240. }
  1241. //---------------------------------------------------------------------
  1242. //
  1243. // The vertices are already in the vertex buffer.
  1244. //
  1245. // Uses the following members of D3DFE_PROCESSVERTICES:
  1246. // primType
  1247. // dwNumVertices
  1248. // dwNumPrimitives
  1249. // dwNumIndices
  1250. // dwIndexSize
  1251. // lpwIndices
  1252. //
  1253. #undef DPF_MODNAME
  1254. #define DPF_MODNAME "CD3DDDIDX8::DrawIndexPrim"
  1255. void
  1256. CD3DDDIDX8::DrawIndexPrim(D3DFE_PROCESSVERTICES* pv)
  1257. {
  1258. #ifdef DEBUG_PIPELINE
  1259. if (g_DebugFlags & __DEBUG_NORENDERING)
  1260. return;
  1261. #endif
  1262. this->dwDP2Flags |= D3DDDI_INDEXEDPRIMDRAWN;
  1263. if (m_pCurrentIndexStream == m_pIndexStream)
  1264. {
  1265. // We always copy user provided indices to the internal index stream.
  1266. // Therefore we have to check the available stream size and do Lock/Unlock
  1267. DWORD dwIndicesByteCount = pv->dwNumIndices * pv->dwIndexSize;
  1268. // We cannot mix DWORD and WORD indices because of alignment issues
  1269. // on ia64
  1270. if (m_pIndexStream->GetVertexSize() != pv->dwIndexSize)
  1271. {
  1272. this->FlushStates();
  1273. m_pIndexStream->Reset();
  1274. m_pIndexStream->SetVertexSize(pv->dwIndexSize);
  1275. }
  1276. BYTE* pIndexData = m_pIndexStream->Lock(dwIndicesByteCount, this);
  1277. memcpy(pIndexData, pv->lpwIndices, dwIndicesByteCount);
  1278. m_pIndexStream->Unlock();
  1279. }
  1280. if (m_pCurrentIndexStream->m_pVBI->IsD3DManaged())
  1281. {
  1282. if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE)
  1283. {
  1284. BOOL bDirty = FALSE;
  1285. HRESULT result = m_pDevice->ResourceManager()->UpdateVideo(m_pCurrentIndexStream->m_pVBI->RMHandle(), &bDirty);
  1286. if(result != D3D_OK)
  1287. {
  1288. D3D_THROW(result, "Resource manager failed to create or update video memory IB");
  1289. }
  1290. if((m_pDevice->m_dwStreamDirty & (1 << __NUMSTREAMS)) != 0 || bDirty)
  1291. {
  1292. InsertIndices(m_pCurrentIndexStream);
  1293. CDDIStream &Stream = m_pDDIStream[__NUMSTREAMS];
  1294. Stream.m_pStream = m_pCurrentIndexStream;
  1295. Stream.m_pBuf = m_pCurrentIndexStream->m_pVBI;
  1296. Stream.m_dwStride = m_pCurrentIndexStream->m_dwStride;
  1297. m_pDevice->m_dwStreamDirty &= ~(1 << __NUMSTREAMS); // reset stage dirty
  1298. }
  1299. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE;
  1300. }
  1301. }
  1302. else
  1303. {
  1304. if (m_pDDIStream[__NUMSTREAMS].m_pBuf != static_cast<CBuffer*>(m_pCurrentIndexStream->m_pVBI) ||
  1305. pv->dwIndexSize != m_pDDIStream[__NUMSTREAMS].m_dwStride)
  1306. {
  1307. m_pCurrentIndexStream->SetVertexSize(pv->dwIndexSize);
  1308. InsertIndices(m_pCurrentIndexStream);
  1309. // API stream should be set dirty, in case it is later passed to DDI directly
  1310. m_pDevice->m_dwStreamDirty |= (1 << __NUMSTREAMS);
  1311. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
  1312. }
  1313. }
  1314. if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  1315. {
  1316. m_pDevice->UpdateTextures();
  1317. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  1318. }
  1319. if (m_pDDIStream[0].m_pBuf != static_cast<CBuffer*>(m_pCurrentTLStream->m_pVB) ||
  1320. pv->dwOutputSize != m_pDDIStream[0].m_dwStride)
  1321. {
  1322. m_pDDIStream[0].m_dwStride = pv->dwOutputSize;
  1323. InsertStreamSource(m_pCurrentTLStream);
  1324. // API stream should be set dirty, in case it is later passed to DDI directly
  1325. m_pDevice->m_dwStreamDirty |= 1;
  1326. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
  1327. }
  1328. LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pData;
  1329. pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2)
  1330. GetHalBufferPointer(D3DDP2OP_DRAWINDEXEDPRIMITIVE2, sizeof(*pData));
  1331. pData->primType = pv->primType;
  1332. pData->BaseVertexOffset = m_BaseVertexIndex;
  1333. pData->MinIndex = m_MinVertexIndex;
  1334. pData->NumVertices = m_NumVertices;
  1335. pData->StartIndexOffset = m_pCurrentIndexStream->GetPrimitiveBase();
  1336. pData->PrimitiveCount = pv->dwNumPrimitives;
  1337. m_pCurrentIndexStream->SkipVertices(pv->dwNumIndices);
  1338. }
  1339. //-----------------------------------------------------------------------------
  1340. // This primitive is generated by the clipper.
  1341. // The vertices of this primitive are pointed to by the
  1342. // lpvOut member, which need to be copied into the
  1343. // command stream immediately after the command itself.
  1344. //
  1345. // Uses the following members of D3DFE_PROCESSVERTICES:
  1346. // primType
  1347. // dwNumVertices
  1348. // dwNumPrimitives
  1349. // dwOutputSize
  1350. // dwFlags (D3DPV_NONCLIPPED)
  1351. // lpdwRStates (FILLMODE)
  1352. // lpvOut
  1353. // ClipperState.current_vbuf
  1354. //
  1355. #undef DPF_MODNAME
  1356. #define DPF_MODNAME "CD3DDDIDX8::DrawClippedPrim"
  1357. void
  1358. CD3DDDIDX8::DrawClippedPrim(D3DFE_PROCESSVERTICES* pv)
  1359. {
  1360. #ifdef DEBUG_PIPELINE
  1361. if (g_DebugFlags & __DEBUG_NORENDERING)
  1362. return;
  1363. #endif
  1364. if (m_pDDIStream[0].m_pBuf != static_cast<CBuffer*>(m_pTLStreamClip->m_pVB) ||
  1365. pv->dwOutputSize != m_pDDIStream[0].m_dwStride)
  1366. {
  1367. m_pTLStreamClip->SetVertexSize(pv->dwOutputSize);
  1368. InsertStreamSource(m_pTLStreamClip);
  1369. // API stream should be set dirty, in case it is later passed to DDI directly
  1370. m_pDevice->m_dwStreamDirty |= 1;
  1371. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
  1372. }
  1373. if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  1374. {
  1375. m_pDevice->UpdateTextures();
  1376. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  1377. }
  1378. DWORD dwVertexPoolSize = pv->dwNumVertices * pv->dwOutputSize;
  1379. LPVOID pVertices;
  1380. if (pv->primType == D3DPT_TRIANGLEFAN)
  1381. {
  1382. if (pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME &&
  1383. pv->dwFlags & D3DPV_NONCLIPPED)
  1384. {
  1385. // For unclipped (but pretended to be clipped) tri fans in
  1386. // wireframe mode we generate 3-vertex tri fans to enable drawing
  1387. // of interior edges
  1388. BYTE vertices[__MAX_VERTEX_SIZE*3];
  1389. BYTE *pV1 = vertices + pv->dwOutputSize;
  1390. BYTE *pV2 = pV1 + pv->dwOutputSize;
  1391. BYTE *pInput = (BYTE*)pv->lpvOut;
  1392. memcpy(vertices, pInput, pv->dwOutputSize);
  1393. pInput += pv->dwOutputSize;
  1394. const DWORD nTriangles = pv->dwNumVertices - 2;
  1395. pv->dwNumVertices = 3;
  1396. pv->dwNumPrimitives = 1;
  1397. pv->lpvOut = vertices;
  1398. // Remove this flag for recursive call
  1399. pv->dwFlags &= ~D3DPV_NONCLIPPED;
  1400. for (DWORD i = nTriangles; i; i--)
  1401. {
  1402. memcpy(pV1, pInput, pv->dwOutputSize);
  1403. memcpy(pV2, pInput + pv->dwOutputSize, pv->dwOutputSize);
  1404. pInput += pv->dwOutputSize;
  1405. // To enable all edge flag we set the fill mode to SOLID.
  1406. // This will prevent checking the clip flags in the clipper
  1407. // state
  1408. pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] = D3DFILL_SOLID;
  1409. DrawClippedPrim(pv);
  1410. pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] = D3DFILL_WIREFRAME;
  1411. }
  1412. return;
  1413. }
  1414. // Lock should be before GetPrimitiveBase(), because the primitive
  1415. // base could be changed during Lock()
  1416. pVertices = m_pTLStreamClip->Lock(dwVertexPoolSize, this);
  1417. LPD3DHAL_CLIPPEDTRIANGLEFAN pData;
  1418. pData = (LPD3DHAL_CLIPPEDTRIANGLEFAN)
  1419. GetHalBufferPointer(D3DDP2OP_CLIPPEDTRIANGLEFAN, sizeof(*pData));
  1420. pData->FirstVertexOffset = m_pTLStreamClip->GetPrimitiveBase();
  1421. pData->PrimitiveCount = pv->dwNumPrimitives;
  1422. if (pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] != D3DFILL_WIREFRAME)
  1423. {
  1424. // Mark all exterior edges visible
  1425. pData->dwEdgeFlags = 0xFFFFFFFF;
  1426. }
  1427. else
  1428. {
  1429. pData->dwEdgeFlags = 0;
  1430. ClipVertex **clip = pv->ClipperState.current_vbuf;
  1431. // Look at the exterior edges and mark the visible ones
  1432. for(DWORD i = 0; i < pv->dwNumVertices; ++i)
  1433. {
  1434. if (clip[i]->clip & CLIPPED_ENABLE)
  1435. pData->dwEdgeFlags |= (1 << i);
  1436. }
  1437. }
  1438. }
  1439. else
  1440. {
  1441. // Lock should be before GetPrimitiveBase(), because the primitive
  1442. // base could be changed during Lock()
  1443. pVertices = m_pTLStreamClip->Lock(dwVertexPoolSize, this);
  1444. #if DBG
  1445. if (pv->primType != D3DPT_LINELIST)
  1446. {
  1447. D3D_THROW_FAIL("Internal error - invalid primitive type");
  1448. }
  1449. #endif
  1450. LPD3DHAL_DP2DRAWPRIMITIVE2 pData;
  1451. pData = (LPD3DHAL_DP2DRAWPRIMITIVE2)
  1452. GetHalBufferPointer(D3DDP2OP_DRAWPRIMITIVE2, sizeof(*pData));
  1453. pData->primType = D3DPT_LINELIST;
  1454. pData->FirstVertexOffset = m_pTLStreamClip->GetPrimitiveBase();
  1455. pData->PrimitiveCount = pv->dwNumPrimitives;
  1456. }
  1457. // Copy vertices to the clipped stream
  1458. memcpy(pVertices, pv->lpvOut, dwVertexPoolSize);
  1459. m_pTLStreamClip->Unlock();
  1460. m_pTLStreamClip->SkipVertices(pv->dwNumVertices);
  1461. #if DBG
  1462. if (m_bValidateCommands)
  1463. ValidateCommand(lpDP2CurrCommand);
  1464. #endif
  1465. }
  1466. //-----------------------------------------------------------------------------
  1467. // This function is called whe software vertex processing is used
  1468. // Handle should be always legacy
  1469. //
  1470. #undef DPF_MODNAME
  1471. #define DPF_MODNAME "CD3DDDIDX8::SetVertexShader"
  1472. void
  1473. CD3DDDIDX8::SetVertexShader( DWORD dwHandle )
  1474. {
  1475. DXGASSERT(D3DVSD_ISLEGACY(dwHandle));
  1476. if (dwHandle != m_CurrentVertexShader)
  1477. {
  1478. m_CurrentVertexShader = dwHandle;
  1479. LPD3DHAL_DP2VERTEXSHADER pData;
  1480. pData = (LPD3DHAL_DP2VERTEXSHADER)
  1481. GetHalBufferPointer(D3DDP2OP_SETVERTEXSHADER, sizeof(*pData));
  1482. {
  1483. // Drivers do not need to know about D3DFVF_LASTBETA_UBYTE4 bit
  1484. dwHandle &= ~D3DFVF_LASTBETA_UBYTE4;
  1485. }
  1486. pData->dwHandle = dwHandle;
  1487. }
  1488. }
  1489. //-----------------------------------------------------------------------------
  1490. // This function is called whe hardware vertex processing is used
  1491. // Redundant shader check has been done at the API level
  1492. //
  1493. #undef DPF_MODNAME
  1494. #define DPF_MODNAME "CD3DDDIDX8::SetVertexShaderHW"
  1495. void
  1496. CD3DDDIDX8::SetVertexShaderHW( DWORD dwHandle )
  1497. {
  1498. m_CurrentVertexShader = dwHandle;
  1499. LPD3DHAL_DP2VERTEXSHADER pData;
  1500. pData = (LPD3DHAL_DP2VERTEXSHADER)
  1501. GetHalBufferPointer(D3DDP2OP_SETVERTEXSHADER, sizeof(*pData));
  1502. if( D3DVSD_ISLEGACY(dwHandle) )
  1503. {
  1504. // Drivers do not need to know about D3DFVF_LASTBETA_UBYTE4 bit
  1505. dwHandle &= ~D3DFVF_LASTBETA_UBYTE4;
  1506. }
  1507. pData->dwHandle = dwHandle;
  1508. }
  1509. //-----------------------------------------------------------------------------
  1510. // Point sprites are drawn as indexed triangle list
  1511. //
  1512. #undef DPF_MODNAME
  1513. #define DPF_MODNAME "CD3DDDIDX8::StartPointSprites"
  1514. void CD3DDDIDX8::StartPointSprites()
  1515. {
  1516. D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv;
  1517. // For StartPrimTL we should use vertex size, which will go to the driver
  1518. DWORD tmpVertexSize = pv->dwOutputSize;
  1519. pv->dwOutputSize = m_dwOutputSizePS;
  1520. // Set new output vertex shader for the DDI
  1521. SetVertexShader(m_dwVIDOutPS);
  1522. // Reserve place for the output vertices
  1523. const UINT size = NUM_SPRITES_IN_BATCH * 4 * pv->dwOutputSize;
  1524. m_pCurSpriteVertex = (BYTE*)StartPrimTL(pv, size, TRUE);
  1525. // Restore vertex size, which is size before point sprite emulation
  1526. pv->dwOutputSize = tmpVertexSize;
  1527. // Index stream used to hold indices
  1528. m_pCurrentIndexStream = m_pIndexStream;
  1529. pv->dwIndexSize = 2;
  1530. // Reserve place for indices
  1531. UINT count = NUM_SPRITES_IN_BATCH * 2 * 6;
  1532. m_pCurPointSpriteIndex = (WORD*)m_pIndexStream->Lock(count, this);
  1533. m_CurNumberOfSprites = 0;
  1534. SetWithinPrimitive(TRUE);
  1535. }
  1536. //-----------------------------------------------------------------------------
  1537. #undef DPF_MODNAME
  1538. #define DPF_MODNAME "CD3DDDIDX8::EndPointSprites"
  1539. void CD3DDDIDX8::EndPointSprites()
  1540. {
  1541. D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv;
  1542. m_pCurrentIndexStream->Unlock();
  1543. m_pCurrentTLStream->Unlock();
  1544. if (m_CurNumberOfSprites)
  1545. {
  1546. if (m_pDDIStream[__NUMSTREAMS].m_pBuf != static_cast<CBuffer*>(m_pCurrentIndexStream->m_pVBI) ||
  1547. pv->dwIndexSize != m_pDDIStream[__NUMSTREAMS].m_dwStride)
  1548. {
  1549. m_pCurrentIndexStream->SetVertexSize(pv->dwIndexSize);
  1550. InsertIndices(m_pCurrentIndexStream);
  1551. }
  1552. if (m_pDDIStream[0].m_pBuf != static_cast<CBuffer*>(m_pCurrentTLStream->m_pVB) ||
  1553. m_dwOutputSizePS != m_pDDIStream[0].m_dwStride)
  1554. {
  1555. InsertStreamSource(m_pCurrentTLStream);
  1556. }
  1557. if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE)
  1558. {
  1559. m_pDevice->UpdateTextures();
  1560. m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE;
  1561. }
  1562. UINT NumVertices = m_CurNumberOfSprites * 4;
  1563. LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pData;
  1564. pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2)
  1565. GetHalBufferPointer(D3DDP2OP_DRAWINDEXEDPRIMITIVE2, sizeof(*pData));
  1566. pData->primType = D3DPT_TRIANGLELIST;
  1567. pData->BaseVertexOffset = m_pCurrentTLStream->GetPrimitiveBase();
  1568. pData->MinIndex = 0;
  1569. pData->NumVertices = NumVertices;
  1570. pData->StartIndexOffset = m_pCurrentIndexStream->GetPrimitiveBase();
  1571. pData->PrimitiveCount = m_CurNumberOfSprites * 2;
  1572. m_pCurrentIndexStream->SkipVertices(m_CurNumberOfSprites * 6);
  1573. m_pCurrentTLStream->SkipVertices(NumVertices);
  1574. m_CurNumberOfSprites = 0;
  1575. }
  1576. SetWithinPrimitive(FALSE);
  1577. }
  1578. /////////////////////////////////////////////////////////////////////////////
  1579. // //
  1580. // CD3DDDIDX8TL //
  1581. // //
  1582. /////////////////////////////////////////////////////////////////////////////
  1583. CD3DDDIDX8TL::CD3DDDIDX8TL()
  1584. {
  1585. m_ddiType = D3DDDITYPE_DX8TL;
  1586. m_dwInterfaceNumber = 4;
  1587. }
  1588. //-----------------------------------------------------------------------------
  1589. CD3DDDIDX8TL::~CD3DDDIDX8TL()
  1590. {
  1591. return;
  1592. }
  1593. //-----------------------------------------------------------------------------
  1594. #undef DPF_MODNAME
  1595. #define DPF_MODNAME "CD3DDDIDX8TL::CreateVertexShader"
  1596. void
  1597. CD3DDDIDX8TL::CreateVertexShader(CONST DWORD* pdwDeclaration,
  1598. DWORD dwDeclSize,
  1599. CONST DWORD* pdwFunction,
  1600. DWORD dwCodeSize,
  1601. DWORD dwHandle,
  1602. BOOL bLegacyFVF)
  1603. {
  1604. FlushStates();
  1605. LPD3DHAL_DP2CREATEVERTEXSHADER pData;
  1606. pData = (LPD3DHAL_DP2CREATEVERTEXSHADER)
  1607. GetHalBufferPointer(D3DDP2OP_CREATEVERTEXSHADER,
  1608. sizeof(*pData) + dwDeclSize + dwCodeSize);
  1609. pData->dwHandle = dwHandle;
  1610. pData->dwDeclSize = dwDeclSize;
  1611. pData->dwCodeSize = dwCodeSize;
  1612. LPBYTE p = (LPBYTE)&pData[1];
  1613. memcpy(p, pdwDeclaration, dwDeclSize);
  1614. if (pdwFunction)
  1615. {
  1616. p += dwDeclSize;
  1617. memcpy(p, pdwFunction, dwCodeSize);
  1618. }
  1619. FlushStates();
  1620. }
  1621. //-----------------------------------------------------------------------------
  1622. #undef DPF_MODNAME
  1623. #define DPF_MODNAME "CD3DDDIDX8TL::DeleteVertexShader"
  1624. void
  1625. CD3DDDIDX8TL::DeleteVertexShader(DWORD dwHandle)
  1626. {
  1627. if (dwHandle == m_CurrentVertexShader)
  1628. m_CurrentVertexShader = 0;
  1629. LPD3DHAL_DP2VERTEXSHADER pData;
  1630. pData = (LPD3DHAL_DP2VERTEXSHADER)
  1631. GetHalBufferPointer(D3DDP2OP_DELETEVERTEXSHADER, sizeof(*pData));
  1632. pData->dwHandle = dwHandle;
  1633. }
  1634. //-----------------------------------------------------------------------------
  1635. #undef DPF_MODNAME
  1636. #define DPF_MODNAME "CD3DDDIDX8TL::SetVertexShaderConstant"
  1637. void
  1638. CD3DDDIDX8TL::SetVertexShaderConstant(DWORD dwRegister, CONST VOID* data, DWORD count)
  1639. {
  1640. const DWORD size = count << 4;
  1641. LPD3DHAL_DP2SETVERTEXSHADERCONST pData;
  1642. pData = (LPD3DHAL_DP2SETVERTEXSHADERCONST)
  1643. GetHalBufferPointer(D3DDP2OP_SETVERTEXSHADERCONST,
  1644. sizeof(*pData) + size);
  1645. pData->dwRegister = dwRegister;
  1646. pData->dwCount = count;
  1647. memcpy(pData+1, data, size);
  1648. }
  1649. //-----------------------------------------------------------------------------
  1650. #undef DPF_MODNAME
  1651. #define DPF_MODNAME "CD3DDDIDX8TL::MultiplyTransform"
  1652. void
  1653. CD3DDDIDX8TL::MultiplyTransform(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat)
  1654. {
  1655. // Send down the state and the matrix
  1656. LPD3DHAL_DP2MULTIPLYTRANSFORM pData;
  1657. pData = (LPD3DHAL_DP2MULTIPLYTRANSFORM)
  1658. GetHalBufferPointer(D3DDP2OP_MULTIPLYTRANSFORM, sizeof(*pData));
  1659. pData->xfrmType = state;
  1660. pData->matrix = *lpMat;
  1661. }
  1662. //-----------------------------------------------------------------------------
  1663. #undef DPF_MODNAME
  1664. #define DPF_MODNAME "CD3DDDIDX8TL::SetTransform"
  1665. void
  1666. CD3DDDIDX8TL::SetTransform(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat)
  1667. {
  1668. // Send down the state and the matrix
  1669. LPD3DHAL_DP2SETTRANSFORM pData;
  1670. pData = (LPD3DHAL_DP2SETTRANSFORM)
  1671. GetHalBufferPointer(D3DDP2OP_SETTRANSFORM, sizeof(*pData));
  1672. pData->xfrmType = state;
  1673. pData->matrix = *lpMat;
  1674. }
  1675. //-----------------------------------------------------------------------------
  1676. #undef DPF_MODNAME
  1677. #define DPF_MODNAME "CD3DDDIDX8TL::SetViewport"
  1678. void
  1679. CD3DDDIDX8TL::SetViewport(CONST D3DVIEWPORT8* lpVwpData)
  1680. {
  1681. // Update viewport size
  1682. CD3DDDIDX6::SetViewport(lpVwpData);
  1683. // Update Z range
  1684. LPD3DHAL_DP2ZRANGE pData;
  1685. pData = (LPD3DHAL_DP2ZRANGE)GetHalBufferPointer(D3DDP2OP_ZRANGE, sizeof(*pData));
  1686. pData->dvMinZ = lpVwpData->MinZ;
  1687. pData->dvMaxZ = lpVwpData->MaxZ;
  1688. }
  1689. //-----------------------------------------------------------------------------
  1690. #undef DPF_MODNAME
  1691. #define DPF_MODNAME "CD3DDDIDX8TL::SetMaterial"
  1692. void
  1693. CD3DDDIDX8TL::SetMaterial(CONST D3DMATERIAL8* pMat)
  1694. {
  1695. LPD3DHAL_DP2SETMATERIAL pData;
  1696. pData = (LPD3DHAL_DP2SETMATERIAL)GetHalBufferPointer(D3DDP2OP_SETMATERIAL, sizeof(*pData));
  1697. *pData = *((LPD3DHAL_DP2SETMATERIAL)pMat);
  1698. }
  1699. //-----------------------------------------------------------------------------
  1700. #undef DPF_MODNAME
  1701. #define DPF_MODNAME "CD3DDDIDX8TL::SetLight"
  1702. void
  1703. CD3DDDIDX8TL::SetLight(DWORD dwLightIndex, CONST D3DLIGHT8* pLight)
  1704. {
  1705. LPD3DHAL_DP2SETLIGHT pData;
  1706. pData = (LPD3DHAL_DP2SETLIGHT)
  1707. GetHalBufferPointer(D3DDP2OP_SETLIGHT,
  1708. sizeof(*pData) + sizeof(D3DLIGHT8));
  1709. pData->dwIndex = dwLightIndex;
  1710. pData->dwDataType = D3DHAL_SETLIGHT_DATA;
  1711. D3DLIGHT8 UNALIGNED64 * p = (D3DLIGHT8 UNALIGNED64 *)((LPBYTE)pData + sizeof(D3DHAL_DP2SETLIGHT));
  1712. *p = *pLight;
  1713. }
  1714. //-----------------------------------------------------------------------------
  1715. #undef DPF_MODNAME
  1716. #define DPF_MODNAME "CD3DDDIDX8TL::CreateLight"
  1717. void
  1718. CD3DDDIDX8TL::CreateLight(DWORD dwLightIndex)
  1719. {
  1720. LPD3DHAL_DP2CREATELIGHT pData;
  1721. pData = (LPD3DHAL_DP2CREATELIGHT)GetHalBufferPointer(D3DDP2OP_CREATELIGHT, sizeof(*pData));
  1722. pData->dwIndex = dwLightIndex;
  1723. }
  1724. //-----------------------------------------------------------------------------
  1725. #undef DPF_MODNAME
  1726. #define DPF_MODNAME "CD3DDDIDX8TL::LightEnable"
  1727. void
  1728. CD3DDDIDX8TL::LightEnable(DWORD dwLightIndex, BOOL bEnable)
  1729. {
  1730. LPD3DHAL_DP2SETLIGHT pData;
  1731. pData = (LPD3DHAL_DP2SETLIGHT)GetHalBufferPointer(D3DDP2OP_SETLIGHT, sizeof(*pData));
  1732. pData->dwIndex = dwLightIndex;
  1733. if (bEnable)
  1734. pData->dwDataType = D3DHAL_SETLIGHT_ENABLE;
  1735. else
  1736. pData->dwDataType = D3DHAL_SETLIGHT_DISABLE;
  1737. }
  1738. //-----------------------------------------------------------------------------
  1739. #undef DPF_MODNAME
  1740. #define DPF_MODNAME "CD3DDDIDX8TL::SetClipPlane"
  1741. void
  1742. CD3DDDIDX8TL::SetClipPlane(DWORD dwPlaneIndex, CONST D3DVALUE* pPlaneEquation)
  1743. {
  1744. LPD3DHAL_DP2SETCLIPPLANE pData;
  1745. pData = (LPD3DHAL_DP2SETCLIPPLANE)
  1746. GetHalBufferPointer(D3DDP2OP_SETCLIPPLANE, sizeof(*pData));
  1747. pData->dwIndex = dwPlaneIndex;
  1748. pData->plane[0] = pPlaneEquation[0];
  1749. pData->plane[1] = pPlaneEquation[1];
  1750. pData->plane[2] = pPlaneEquation[2];
  1751. pData->plane[3] = pPlaneEquation[3];
  1752. }
  1753. //---------------------------------------------------------------------
  1754. #undef DPF_MODNAME
  1755. #define DPF_MODNAME "CD3DDDIDX8::ClearBatch"
  1756. void
  1757. CD3DDDIDX8::ClearBatch(BOOL bWithinPrimitive)
  1758. {
  1759. // Reset command buffer
  1760. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)lpvDP2Commands;
  1761. dwDP2CommandLength = 0;
  1762. dp2data.dwCommandOffset = 0;
  1763. dp2data.dwCommandLength = 0;
  1764. bDP2CurrCmdOP = 0;
  1765. }
  1766. //-----------------------------------------------------------------------------
  1767. #undef DPF_MODNAME
  1768. #define DPF_MODNAME "CD3DDDIDX8::FlushStates"
  1769. void
  1770. CD3DDDIDX8::FlushStates(BOOL bReturnDriverError, BOOL bWithinPrimitive)
  1771. {
  1772. HRESULT dwRet=D3D_OK;
  1773. if (m_bWithinPrimitive)
  1774. bWithinPrimitive = TRUE;
  1775. if (dwDP2CommandLength) // Do we have some instructions to flush ?
  1776. {
  1777. m_pDevice->IncrementBatchCount();
  1778. // Batch currently set VB streams
  1779. CDDIStream* pStream = m_pDDIStream;
  1780. for (UINT i=0; i < __NUMSTREAMS; i++)
  1781. {
  1782. if (pStream->m_pStream)
  1783. {
  1784. CVStream* p = static_cast<CVStream*>(pStream->m_pStream);
  1785. CVertexBuffer* pVB = p->m_pVB;
  1786. if (pVB)
  1787. pVB->Batch();
  1788. }
  1789. pStream++;
  1790. }
  1791. // Now pStream points to the index stream
  1792. if (pStream->m_pStream)
  1793. {
  1794. CVIndexStream* p = static_cast<CVIndexStream*>(pStream->m_pStream);
  1795. CIndexBuffer* pVB = p->m_pVBI;
  1796. if (pVB)
  1797. pVB->Batch();
  1798. }
  1799. // Save since it will get overwritten by ddrval after DDI call
  1800. DWORD dwVertexSize = dp2data.dwVertexSize;
  1801. dp2data.dwCommandLength = dwDP2CommandLength;
  1802. //we clear this to break re-entering as SW rasterizer needs to lock DDRAWSURFACE
  1803. dwDP2CommandLength = 0;
  1804. // Try and set these 2 values only once during initialization
  1805. dp2data.dwhContext = m_dwhContext;
  1806. dp2data.lpdwRStates = (LPDWORD)lpwDPBuffer;
  1807. // Spin waiting on the driver if wait requested
  1808. do {
  1809. // Need to set this since the driver may have overwrote it by
  1810. // setting ddrval = DDERR_WASSTILLDRAWING
  1811. dp2data.dwVertexSize = dwVertexSize;
  1812. dwRet = m_pDevice->GetHalCallbacks()->DrawPrimitives2(&dp2data);
  1813. if (dwRet != DDHAL_DRIVER_HANDLED)
  1814. {
  1815. D3D_ERR ( "Driver not handled in DrawPrimitives2" );
  1816. // Need sensible return value in this case,
  1817. // currently we return whatever the driver stuck in here.
  1818. }
  1819. } while (dp2data.ddrval == DDERR_WASSTILLDRAWING);
  1820. dwRet= dp2data.ddrval;
  1821. // update command buffer pointer
  1822. if ((dwRet == D3D_OK) &&
  1823. (dp2data.dwFlags & D3DHALDP2_SWAPCOMMANDBUFFER))
  1824. {
  1825. // Implement VidMem command buffer and
  1826. // command buffer swapping.
  1827. }
  1828. // Restore to value before the DDI call
  1829. dp2data.dwVertexSize = dwVertexSize;
  1830. ClearBatch(bWithinPrimitive);
  1831. }
  1832. // There are situations when the command stream has no data,
  1833. // but there is data in the vertex pool. This could happen, for instance
  1834. // if every triangle got rejected while clipping. In this case we still
  1835. // need to "Flush out" the vertex data.
  1836. else if (dp2data.dwCommandLength == 0)
  1837. {
  1838. ClearBatch(bWithinPrimitive);
  1839. }
  1840. if( FAILED( dwRet ) )
  1841. {
  1842. ClearBatch(FALSE);
  1843. if( !bReturnDriverError )
  1844. {
  1845. switch( dwRet )
  1846. {
  1847. case D3DERR_OUTOFVIDEOMEMORY:
  1848. D3D_ERR("Driver out of video memory!");
  1849. break;
  1850. case D3DERR_COMMAND_UNPARSED:
  1851. D3D_ERR("Driver could not parse this batch!");
  1852. break;
  1853. default:
  1854. D3D_ERR("Driver returned error: %s", HrToStr(dwRet));
  1855. break;
  1856. }
  1857. DPF_ERR("Driver failed command batch. Attempting to reset device"
  1858. " state. The device may now be in an unstable state and"
  1859. " the application may experience an access violation.");
  1860. }
  1861. else
  1862. {
  1863. throw dwRet;
  1864. }
  1865. }
  1866. }
  1867. //-----------------------------------------------------------------------------
  1868. #undef DPF_MODNAME
  1869. #define DPF_MODNAME "CD3DDDIDX8::ProcessPointSprites"
  1870. void CD3DDDIDX8::PickProcessPrimitive()
  1871. {
  1872. D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv;
  1873. if (pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION)
  1874. {
  1875. m_pfnProcessPrimitive = ProcessPointSprites;
  1876. }
  1877. else
  1878. if (pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF)
  1879. {
  1880. m_pfnProcessPrimitive =
  1881. static_cast<PFN_PROCESSPRIM>(ProcessPrimitiveT);
  1882. m_pfnProcessIndexedPrimitive =
  1883. static_cast<PFN_PROCESSPRIM>(ProcessIndexedPrimitiveT);
  1884. }
  1885. else
  1886. if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
  1887. {
  1888. m_pfnProcessPrimitive =
  1889. static_cast<PFN_PROCESSPRIM>(ProcessPrimitive);
  1890. m_pfnProcessIndexedPrimitive =
  1891. static_cast<PFN_PROCESSPRIM>(ProcessIndexedPrimitive);
  1892. }
  1893. else
  1894. {
  1895. m_pfnProcessPrimitive =
  1896. static_cast<PFN_PROCESSPRIM>(ProcessPrimitiveC);
  1897. m_pfnProcessIndexedPrimitive =
  1898. static_cast<PFN_PROCESSPRIM>(ProcessIndexedPrimitiveC);
  1899. }
  1900. }
  1901. //-----------------------------------------------------------------------------
  1902. // Processes non-indexed primitives with untransformed vertices and without
  1903. // clipping
  1904. //
  1905. #undef DPF_MODNAME
  1906. #define DPF_MODNAME "CD3DDDIDX8::ProcessPrimitive"
  1907. void
  1908. CD3DDDIDX8::ProcessPrimitive(D3DFE_PROCESSVERTICES* pv, UINT StartVertex)
  1909. {
  1910. DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
  1911. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  1912. if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY)
  1913. DoUpdateState(pDevice);
  1914. pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, TRUE);
  1915. HRESULT ret = pv->pGeometryFuncs->ProcessVertices(pv);
  1916. if (ret != D3D_OK)
  1917. {
  1918. SetWithinPrimitive(FALSE);
  1919. m_pCurrentTLStream->Unlock();
  1920. D3D_THROW(ret, "Error in PSGP");
  1921. }
  1922. DrawPrim(pv);
  1923. SetWithinPrimitive(FALSE);
  1924. m_pCurrentTLStream->Unlock();
  1925. }
  1926. //-----------------------------------------------------------------------------
  1927. // Processes non-indexed primitives with untransformed vertices and with
  1928. // clipping
  1929. //
  1930. #undef DPF_MODNAME
  1931. #define DPF_MODNAME "CD3DDDIDX8::ProcessPrimitiveC"
  1932. void
  1933. CD3DDDIDX8::ProcessPrimitiveC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex)
  1934. {
  1935. DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
  1936. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  1937. // Update lighting and related flags
  1938. if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY)
  1939. DoUpdateState(pDevice);
  1940. PrepareForClipping(pv, 0);
  1941. pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize,
  1942. NeverReadFromTLBuffer(pv));
  1943. // When a triangle strip is clipped, we draw indexed primitives
  1944. // sometimes. This is why we need to initialize the index stream
  1945. m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase();
  1946. m_pCurrentIndexStream = m_pIndexStream;
  1947. HRESULT ret;
  1948. if (pv->primType == D3DPT_POINTLIST)
  1949. {
  1950. // When all points are clipped by X or Y planes we do not throw
  1951. // them away, because they could have point size and be visible
  1952. ret = D3D_OK;
  1953. DWORD clipIntersection = pv->pGeometryFuncs->ProcessVertices(pv);
  1954. clipIntersection &= ~(D3DCS_LEFT | D3DCS_RIGHT |
  1955. D3DCS_TOP | D3DCS_BOTTOM |
  1956. __D3DCLIPGB_ALL);
  1957. if (!clipIntersection)
  1958. {
  1959. // There are some vertices inside the screen
  1960. if (pv->dwClipUnion == 0)
  1961. DrawPrim(pv);
  1962. else
  1963. ret = ProcessClippedPointSprites(pv);
  1964. }
  1965. }
  1966. else
  1967. {
  1968. ret = pv->pGeometryFuncs->ProcessPrimitive(pv);
  1969. }
  1970. if (ret != D3D_OK)
  1971. {
  1972. SetWithinPrimitive(FALSE);
  1973. m_pCurrentTLStream->Unlock();
  1974. D3D_THROW(ret, "Error in PSGP");
  1975. }
  1976. SetWithinPrimitive(FALSE);
  1977. m_pCurrentTLStream->Unlock();
  1978. UpdateClipStatus(pDevice);
  1979. }
  1980. //-----------------------------------------------------------------------------
  1981. // Processes non-indexed primitives with transformed vertices with clipping
  1982. //
  1983. // Only transformed vertices generated by ProcessVertices call are allowed here
  1984. //
  1985. #undef DPF_MODNAME
  1986. #define DPF_MODNAME "CD3DDDIDX8::ProcessPrimitiveT"
  1987. void
  1988. CD3DDDIDX8::ProcessPrimitiveT(D3DFE_PROCESSVERTICES* pv, UINT StartVertex)
  1989. {
  1990. DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW);
  1991. // Clipping must be enabled when we are here
  1992. DXGASSERT((pv->dwDeviceFlags & D3DDEV_DONOTCLIP) == 0);
  1993. BOOL bNoClipping = FALSE;
  1994. pv->dwOutputSize = m_pDevice->m_pStream[0].m_dwStride;
  1995. // We need to do special processing for point sprites - they should not be
  1996. // clipped as points without size.
  1997. if (m_pDevice->m_dwRuntimeFlags & D3DRT_POINTSIZEPRESENT &&
  1998. pv->primType == D3DPT_POINTLIST)
  1999. {
  2000. // This function is called only if a device supports point sprites.
  2001. // Otherwise DrawPoints() function should be called.
  2002. DXGASSERT((pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION) == 0);
  2003. PrepareForClipping(pv, StartVertex);
  2004. if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER))
  2005. {
  2006. // Set emulation flag, because we want to compute clipping code as
  2007. // for point sprites
  2008. pv->dwDeviceFlags |= D3DDEV_DOPOINTSPRITEEMULATION;
  2009. // Compute clip codes, because there was no ProcessVertices
  2010. DWORD clip_intersect = D3DFE_GenClipFlags(pv);
  2011. UpdateClipStatus(static_cast<CD3DHal*>(m_pDevice));
  2012. pv->dwDeviceFlags &= ~D3DDEV_DOPOINTSPRITEEMULATION;
  2013. if (clip_intersect)
  2014. {
  2015. return;
  2016. }
  2017. }
  2018. // There are some vertices inside the screen. We need to do clipping if
  2019. // a result of ProcessVertices is used as input (clip union is unknown)
  2020. // or clipping is needed based on clip union and guard band flags.
  2021. if (pv->dwDeviceFlags & D3DDEV_VBPROCVER || CheckIfNeedClipping(pv))
  2022. {
  2023. // Set emulation flag, because clipped points should be expanded,
  2024. // not regected. We will clip point sprites by viewport during
  2025. // the expansion.
  2026. pv->dwDeviceFlags |= D3DDEV_DOPOINTSPRITEEMULATION;
  2027. // This will prevent computing clip codes second time.
  2028. pv->dwDeviceFlags |= D3DDEV_VBPROCVER | D3DDEV_DONOTCOMPUTECLIPCODES;
  2029. // Now we can call a function which will take care of point sprite
  2030. // expansion, clipping, culling mode etc.
  2031. ProcessPointSprites(pv, StartVertex);
  2032. pv->dwDeviceFlags &= ~(D3DDEV_DOPOINTSPRITEEMULATION |
  2033. D3DDEV_VBPROCVER |
  2034. D3DDEV_DONOTCOMPUTECLIPCODES);
  2035. return;
  2036. }
  2037. // We are here when all point centres are inside guard band. We can
  2038. // draw them as points without clipping, because device supports point
  2039. // sprites.
  2040. bNoClipping = TRUE;
  2041. }
  2042. if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE)
  2043. {
  2044. DXGASSERT(StartVertex == 0);
  2045. // Copy vertices to the TL buffer
  2046. UINT VertexPoolSize = pv->dwOutputSize * pv->dwNumVertices;
  2047. pv->lpvOut = (BYTE*)StartPrimTL(pv, VertexPoolSize, FALSE);
  2048. pv->position.lpvData = pv->lpvOut;
  2049. memcpy(pv->lpvOut, m_pDevice->m_pStream[0].m_pData, VertexPoolSize);
  2050. }
  2051. else
  2052. StartPrimVB(pv, &m_pDevice->m_pStream[0], StartVertex);
  2053. if (bNoClipping)
  2054. {
  2055. DrawPrim(pv);
  2056. goto l_exit;
  2057. }
  2058. PrepareForClipping(pv, StartVertex);
  2059. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  2060. pv->dwVIDOut = pv->dwVIDIn;
  2061. pv->dwIndexOffset = 0;
  2062. pv->lpvOut = pv->position.lpvData;
  2063. if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER))
  2064. {
  2065. pv->dwFlags |= D3DPV_TLVCLIP;
  2066. // Compute clip codes, because there was no ProcessVertices
  2067. DWORD clip_intersect = D3DFE_GenClipFlags(pv);
  2068. UpdateClipStatus(pDevice);
  2069. if (clip_intersect)
  2070. goto l_exit;
  2071. }
  2072. // When a triangle strip is clipped, we draw indexed primitives
  2073. // sometimes.
  2074. m_BaseVertexIndex = 0;
  2075. HRESULT ret = pDevice->GeometryFuncsGuaranteed->DoDrawPrimitive(pv);
  2076. if (ret != D3D_OK)
  2077. throw ret;
  2078. l_exit:
  2079. pv->dwFlags &= ~D3DPV_TLVCLIP;
  2080. SetWithinPrimitive(FALSE);
  2081. if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE)
  2082. {
  2083. m_pCurrentTLStream->Unlock();
  2084. }
  2085. else
  2086. {
  2087. // If DDI vertex stream has been set to the internal stream during
  2088. // clipping, we need to restore the original stream
  2089. if (m_pDDIStream[0].m_pBuf != m_pDevice->m_pStream[0].m_pVB)
  2090. {
  2091. m_pDevice->m_dwStreamDirty |= 1;
  2092. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
  2093. }
  2094. }
  2095. pv->dwFlags &= ~D3DPV_TLVCLIP;
  2096. }
  2097. //-----------------------------------------------------------------------------
  2098. // Processes indexed primitives with untransformed vertices and without
  2099. // clipping
  2100. //
  2101. #undef DPF_MODNAME
  2102. #define DPF_MODNAME "CD3DDDIDX8::ProcessIndexedPrimitive"
  2103. void
  2104. CD3DDDIDX8::ProcessIndexedPrimitive(D3DFE_PROCESSVERTICES* pv, UINT StartVertex)
  2105. {
  2106. DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
  2107. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  2108. // Update lighting and related flags
  2109. if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY)
  2110. DoUpdateState(pDevice);
  2111. pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, TRUE);
  2112. HRESULT ret = pv->pGeometryFuncs->ProcessVertices(pv);
  2113. if (ret != D3D_OK)
  2114. {
  2115. SetWithinPrimitive(FALSE);
  2116. m_pCurrentTLStream->Unlock();
  2117. D3D_THROW(ret, "Error in PSGP");
  2118. }
  2119. if (pDevice->m_pIndexStream->m_pVBI)
  2120. StartIndexPrimVB(pDevice->m_pIndexStream, m_StartIndex,
  2121. pv->dwIndexSize);
  2122. else
  2123. m_pCurrentIndexStream = m_pIndexStream;
  2124. // Let the driver map indices to be relative to the start of
  2125. // the processed vertices
  2126. m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase() -
  2127. m_MinVertexIndex * pv->dwOutputSize;
  2128. DrawIndexPrim(pv);
  2129. m_pCurrentTLStream->SkipVertices(pv->dwNumVertices);
  2130. SetWithinPrimitive(FALSE);
  2131. m_pCurrentTLStream->Unlock();
  2132. }
  2133. //-----------------------------------------------------------------------------
  2134. // Processes indexed primitives with untransformed vertices and with
  2135. // clipping
  2136. //
  2137. #undef DPF_MODNAME
  2138. #define DPF_MODNAME "CD3DDDIDX8::ProcessIndexedPrimitiveC"
  2139. void
  2140. CD3DDDIDX8::ProcessIndexedPrimitiveC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex)
  2141. {
  2142. DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
  2143. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  2144. // Update lighting and related flags
  2145. if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY)
  2146. DoUpdateState(pDevice);
  2147. pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data() +
  2148. m_StartIndex * pDevice->m_pIndexStream->m_dwStride);
  2149. PrepareForClipping(pv, 0);
  2150. pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, FALSE);
  2151. m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase() -
  2152. m_MinVertexIndex * pv->dwOutputSize;
  2153. pv->dwIndexOffset = m_MinVertexIndex; // Needed for clipping
  2154. m_pCurrentIndexStream = m_pIndexStream;
  2155. this->dwDP2Flags &= ~D3DDDI_INDEXEDPRIMDRAWN;
  2156. m_pCurrentTLStream->AddVertices(pv->dwNumVertices);
  2157. DWORD NumVertices = pv->dwNumVertices;
  2158. HRESULT ret = pv->pGeometryFuncs->ProcessIndexedPrimitive(pv);
  2159. if (this->dwDP2Flags & D3DDDI_INDEXEDPRIMDRAWN)
  2160. m_pCurrentTLStream->MovePrimitiveBase(NumVertices);
  2161. else
  2162. m_pCurrentTLStream->SubVertices(NumVertices);
  2163. SetWithinPrimitive(FALSE);
  2164. m_pCurrentTLStream->Unlock();
  2165. UpdateClipStatus(pDevice);
  2166. if (ret != D3D_OK)
  2167. {
  2168. D3D_THROW(ret, "Error in PSGP");
  2169. }
  2170. }
  2171. //-----------------------------------------------------------------------------
  2172. // Processes indexed primitives with transformed vertices and with clipping
  2173. //
  2174. #undef DPF_MODNAME
  2175. #define DPF_MODNAME "CD3DDDIDX8::ProcessIndexedPrimitiveT"
  2176. void
  2177. CD3DDDIDX8::ProcessIndexedPrimitiveT(D3DFE_PROCESSVERTICES* pv, UINT StartVertex)
  2178. {
  2179. DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW);
  2180. // Clipping must be enabled when we are here
  2181. DXGASSERT((pv->dwDeviceFlags & D3DDEV_DONOTCLIP) == 0);
  2182. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  2183. pv->dwOutputSize = m_pDevice->m_pStream[0].m_dwStride;
  2184. if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE)
  2185. {
  2186. // We copy user vertices, starting from MinVertexIndex, to the internal
  2187. // TL buffer and do the clipping. Vertex base changes in the process.
  2188. // m_NumVertices has been computed as MinVertexIndex + NumVertices, so
  2189. // it needs to be adjusted, because vertex base has benn changed
  2190. m_NumVertices -= m_MinVertexIndex;
  2191. pv->dwNumVertices = m_NumVertices;
  2192. // Copy vertices to the TL buffer
  2193. UINT VertexPoolSize = pv->dwOutputSize * pv->dwNumVertices;
  2194. pv->lpvOut = (BYTE*)StartPrimTL(pv, VertexPoolSize, FALSE);
  2195. pv->position.lpvData = pv->lpvOut;
  2196. memcpy(pv->lpvOut,
  2197. m_pDevice->m_pStream[0].m_pData + m_MinVertexIndex * pv->dwOutputSize,
  2198. VertexPoolSize);
  2199. // We need to adjust m_BaseVertexIndex, bacause we do not want to
  2200. // re-compute indices for the new vertex base
  2201. m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase() -
  2202. m_MinVertexIndex * pv->dwOutputSize;
  2203. m_pCurrentTLStream->AddVertices(pv->dwNumVertices);
  2204. // During clipping we need to adjust indices by m_MinVertexIndex
  2205. pv->dwIndexOffset = m_MinVertexIndex;
  2206. pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data());
  2207. }
  2208. else
  2209. {
  2210. StartPrimVB(pv, &m_pDevice->m_pStream[0], StartVertex);
  2211. m_BaseVertexIndex = pDevice->m_pIndexStream->m_dwBaseIndex *
  2212. pv->dwOutputSize;
  2213. pv->dwIndexOffset = m_MinVertexIndex; // For clipping
  2214. pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data() +
  2215. m_StartIndex * pDevice->m_pIndexStream->m_dwStride);
  2216. }
  2217. PrepareForClipping(pv, StartVertex);
  2218. if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER))
  2219. {
  2220. pv->dwFlags |= D3DPV_TLVCLIP;
  2221. // Compute clip codes, because there was no ProcessVertices
  2222. DWORD clip_intersect = D3DFE_GenClipFlags(pv);
  2223. UpdateClipStatus(pDevice);
  2224. if (clip_intersect)
  2225. goto l_exit;
  2226. }
  2227. pv->dwVIDOut = pv->dwVIDIn;
  2228. pv->lpvOut = pv->position.lpvData;
  2229. m_pCurrentIndexStream = m_pIndexStream;
  2230. HRESULT ret;
  2231. ret = pDevice->GeometryFuncsGuaranteed->DoDrawIndexedPrimitive(pv);
  2232. if (ret != D3D_OK)
  2233. throw ret;
  2234. l_exit:
  2235. SetWithinPrimitive(FALSE);
  2236. if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE)
  2237. {
  2238. m_pCurrentTLStream->Unlock();
  2239. m_pCurrentTLStream->MovePrimitiveBase(pv->dwNumVertices);
  2240. }
  2241. else
  2242. {
  2243. // If DDI vertex stream has been set to the internal stream during
  2244. // clipping, we need to restore the original stream
  2245. if (m_pDDIStream[0].m_pBuf != m_pDevice->m_pStream[0].m_pVB)
  2246. {
  2247. m_pDevice->m_dwStreamDirty |= 1;
  2248. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
  2249. }
  2250. // If DDI index stream has been set to the internal stream during
  2251. // clipping, we need to restore the original stream
  2252. if (m_pDDIStream[__NUMSTREAMS].m_pBuf != m_pDevice->m_pIndexStream->m_pVBI)
  2253. {
  2254. m_pDevice->m_dwStreamDirty |= (1 << __NUMSTREAMS);
  2255. m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams()
  2256. }
  2257. }
  2258. pv->dwFlags &= ~D3DPV_TLVCLIP;
  2259. }
  2260. //-----------------------------------------------------------------------------
  2261. #if DBG
  2262. #undef DPF_MODNAME
  2263. #define DPF_MODNAME "CD3DDDIDX8::ValidateCommand"
  2264. void CD3DDDIDX8::ValidateCommand(LPD3DHAL_DP2COMMAND lpCmd)
  2265. {
  2266. CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
  2267. D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv;
  2268. if (!(pDevice->m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING))
  2269. return;
  2270. DWORD dwVertexSize = pv->dwOutputSize;
  2271. BOOL bNeedUnlock = FALSE;
  2272. UINT count;
  2273. BYTE* pVertices;
  2274. CTLStream* pStream = (CTLStream*)m_pDDIStream[0].m_pStream;
  2275. if (pStream->m_pVB)
  2276. if (pStream->m_pVB->IsLocked())
  2277. pVertices = pStream->m_pData;
  2278. else
  2279. {
  2280. pVertices = pStream->Lock(pStream->m_pVB->GetBufferDesc()->Size, this);
  2281. bNeedUnlock = TRUE;
  2282. }
  2283. else
  2284. // User memory vertices
  2285. pVertices = (LPBYTE)(dp2data.lpVertices);
  2286. switch (lpCmd->bCommand)
  2287. {
  2288. case D3DDP2OP_DRAWPRIMITIVE:
  2289. {
  2290. LPD3DHAL_DP2DRAWPRIMITIVE pData = (LPD3DHAL_DP2DRAWPRIMITIVE)(lpCmd+1);
  2291. count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount);
  2292. pVertices += pData->VStart * dwVertexSize;
  2293. for (WORD i = 0; i < count; i++)
  2294. {
  2295. ValidateVertex((LPDWORD)(pVertices + i * dwVertexSize));
  2296. }
  2297. }
  2298. break;
  2299. case D3DDP2OP_DRAWPRIMITIVE2:
  2300. {
  2301. LPD3DHAL_DP2DRAWPRIMITIVE2 pData = (LPD3DHAL_DP2DRAWPRIMITIVE2)(lpCmd+1);
  2302. count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount);
  2303. pVertices += pData->FirstVertexOffset;
  2304. for (WORD i = 0; i < count; i++)
  2305. {
  2306. ValidateVertex((LPDWORD)(pVertices + i * dwVertexSize));
  2307. }
  2308. }
  2309. break;
  2310. case D3DDP2OP_DRAWINDEXEDPRIMITIVE:
  2311. case D3DDP2OP_DRAWINDEXEDPRIMITIVE2:
  2312. {
  2313. BYTE* pIndices;
  2314. BOOL bNeedUnlock = FALSE;
  2315. CTLIndexStream* pStream = (CTLIndexStream*)m_pDDIStream[__NUMSTREAMS].m_pStream;
  2316. if (pStream->m_pVBI->IsLocked())
  2317. pIndices = pStream->m_pData;
  2318. else
  2319. {
  2320. pIndices = pStream->Lock(pStream->m_pVBI->GetBufferDesc()->Size, this);
  2321. bNeedUnlock = TRUE;
  2322. }
  2323. UINT MaxIndex;
  2324. UINT MinIndex;
  2325. if (lpCmd->bCommand == D3DDP2OP_DRAWINDEXEDPRIMITIVE)
  2326. {
  2327. LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pData =
  2328. (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE)(lpCmd+1);
  2329. pIndices += pData->StartIndex * pv->dwIndexSize;
  2330. pVertices += pData->BaseVertexIndex * dwVertexSize;
  2331. MaxIndex = pData->MinIndex + pData->NumVertices - 1;
  2332. count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount);
  2333. MinIndex = pData->MinIndex;
  2334. }
  2335. else
  2336. {
  2337. LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pData =
  2338. (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2)(lpCmd+1);
  2339. pIndices += pData->StartIndexOffset;
  2340. pVertices += pData->BaseVertexOffset;
  2341. MaxIndex = pData->MinIndex + pData->NumVertices - 1;
  2342. count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount);
  2343. MinIndex = pData->MinIndex;
  2344. }
  2345. for (WORD i = 0; i < count; i++)
  2346. {
  2347. DWORD index;
  2348. if (pv->dwIndexSize == 4)
  2349. index = *(DWORD*)(pIndices + i * 4);
  2350. else
  2351. index = *(WORD*)(pIndices + i * 2);
  2352. if (index < MinIndex || index > MaxIndex)
  2353. {
  2354. D3D_THROW_FAIL("Invalid index in the index stream");
  2355. }
  2356. BYTE* pVertex = &pVertices[index];
  2357. if (pVertex < pVertices ||
  2358. pVertex > pVertices + dwVertexSize * MaxIndex)
  2359. {
  2360. D3D_THROW_FAIL("Bad vertex address");
  2361. }
  2362. ValidateVertex((LPDWORD)(pVertices + index * dwVertexSize));
  2363. }
  2364. if (bNeedUnlock)
  2365. pStream->Unlock();
  2366. }
  2367. break;
  2368. case D3DDP2OP_CLIPPEDTRIANGLEFAN:
  2369. if (bNeedUnlock)
  2370. pStream->Unlock();
  2371. CD3DDDIDX6::ValidateCommand(lpCmd);
  2372. return;
  2373. case D3DDP2OP_DRAWRECTPATCH:
  2374. case D3DDP2OP_DRAWTRIPATCH:
  2375. return;
  2376. default:
  2377. D3D_THROW_FAIL("Invalid DX8 drawing command in DP2 stream");
  2378. }
  2379. if (bNeedUnlock)
  2380. pStream->Unlock();
  2381. }
  2382. #endif
  2383. //-----------------------------------------------------------------------------
  2384. // Volume Blt
  2385. //
  2386. #undef DPF_MODNAME
  2387. #define DPF_MODNAME "CD3DDDIDX8::VolBlt"
  2388. void
  2389. CD3DDDIDX8::VolBlt(CBaseTexture *lpDst, CBaseTexture* lpSrc, DWORD dwDestX,
  2390. DWORD dwDestY, DWORD dwDestZ, D3DBOX *pBox)
  2391. {
  2392. if (bDP2CurrCmdOP == D3DDP2OP_VOLUMEBLT)
  2393. { // Last instruction is a tex blt, append this one to it
  2394. if (dwDP2CommandLength + sizeof(D3DHAL_DP2VOLUMEBLT) <=
  2395. dwDP2CommandBufSize)
  2396. {
  2397. LPD3DHAL_DP2VOLUMEBLT lpVolBlt =
  2398. (LPD3DHAL_DP2VOLUMEBLT)((LPBYTE)lpvDP2Commands +
  2399. dwDP2CommandLength +
  2400. dp2data.dwCommandOffset);
  2401. lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
  2402. lpVolBlt->dwDDDestSurface = lpDst == NULL ? 0 :
  2403. lpDst->DriverAccessibleDrawPrimHandle();
  2404. lpVolBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle();
  2405. lpVolBlt->dwDestX = dwDestX;
  2406. lpVolBlt->dwDestY = dwDestY;
  2407. lpVolBlt->dwDestZ = dwDestZ;
  2408. lpVolBlt->srcBox = *pBox;
  2409. lpVolBlt->dwFlags = 0;
  2410. dwDP2CommandLength += sizeof(D3DHAL_DP2VOLUMEBLT);
  2411. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  2412. // For the source, we want to call BatchBase since
  2413. // we want to batch the backing (or sysmem) texture
  2414. // rather than the promoted one.
  2415. lpSrc->BatchBase();
  2416. if(lpDst != 0)
  2417. {
  2418. lpDst->Batch();
  2419. }
  2420. return;
  2421. }
  2422. }
  2423. // Check for space
  2424. if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  2425. sizeof(D3DHAL_DP2VOLUMEBLT) > dwDP2CommandBufSize)
  2426. {
  2427. FlushStates();
  2428. }
  2429. // Add new instruction
  2430. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  2431. dwDP2CommandLength + dp2data.dwCommandOffset);
  2432. lpDP2CurrCommand->bCommand = D3DDP2OP_VOLUMEBLT;
  2433. bDP2CurrCmdOP = D3DDP2OP_VOLUMEBLT;
  2434. lpDP2CurrCommand->bReserved = 0;
  2435. lpDP2CurrCommand->wStateCount = 1;
  2436. wDP2CurrCmdCnt = 1;
  2437. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  2438. // Add texture blt data
  2439. LPD3DHAL_DP2VOLUMEBLT lpVolBlt =
  2440. (LPD3DHAL_DP2VOLUMEBLT)(lpDP2CurrCommand + 1);
  2441. lpVolBlt->dwDDDestSurface = lpDst == NULL ? 0 :
  2442. lpDst->DriverAccessibleDrawPrimHandle();
  2443. lpVolBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle();
  2444. lpVolBlt->dwDestX = dwDestX;
  2445. lpVolBlt->dwDestY = dwDestY;
  2446. lpVolBlt->dwDestZ = dwDestZ;
  2447. lpVolBlt->srcBox = *pBox;
  2448. lpVolBlt->dwFlags = 0;
  2449. dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) +
  2450. sizeof(D3DHAL_DP2VOLUMEBLT);
  2451. // For the source, we want to call BatchBase since
  2452. // we want to batch the backing (or sysmem) texture
  2453. // rather than the promoted one.
  2454. lpSrc->BatchBase();
  2455. if(lpDst != 0)
  2456. {
  2457. lpDst->Batch();
  2458. }
  2459. }
  2460. //-----------------------------------------------------------------------------
  2461. // Buffer Blt
  2462. //
  2463. #undef DPF_MODNAME
  2464. #define DPF_MODNAME "CD3DDDIDX8::BufBlt"
  2465. void
  2466. CD3DDDIDX8::BufBlt(CBuffer *lpDst, CBuffer* lpSrc, DWORD dwOffset,
  2467. D3DRANGE* pRange)
  2468. {
  2469. if (bDP2CurrCmdOP == D3DDP2OP_BUFFERBLT)
  2470. { // Last instruction is a tex blt, append this one to it
  2471. if (dwDP2CommandLength + sizeof(D3DHAL_DP2BUFFERBLT) <=
  2472. dwDP2CommandBufSize)
  2473. {
  2474. LPD3DHAL_DP2BUFFERBLT lpBufBlt =
  2475. (LPD3DHAL_DP2BUFFERBLT)((LPBYTE)lpvDP2Commands +
  2476. dwDP2CommandLength +
  2477. dp2data.dwCommandOffset);
  2478. lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
  2479. lpBufBlt->dwDDDestSurface = lpDst == NULL ? 0 :
  2480. lpDst->DriverAccessibleDrawPrimHandle();
  2481. lpBufBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle();
  2482. lpBufBlt->dwOffset = dwOffset;
  2483. lpBufBlt->rSrc = *pRange;
  2484. lpBufBlt->dwFlags = 0;
  2485. dwDP2CommandLength += sizeof(D3DHAL_DP2BUFFERBLT);
  2486. D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  2487. // For the source, we want to call BatchBase since
  2488. // we want to batch the backing (or sysmem) texture
  2489. // rather than the promoted one.
  2490. lpSrc->BatchBase();
  2491. if(lpDst != 0)
  2492. {
  2493. lpDst->Batch();
  2494. }
  2495. return;
  2496. }
  2497. }
  2498. // Check for space
  2499. if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
  2500. sizeof(D3DHAL_DP2BUFFERBLT) > dwDP2CommandBufSize)
  2501. {
  2502. FlushStates();
  2503. }
  2504. // Add new instruction
  2505. lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
  2506. dwDP2CommandLength + dp2data.dwCommandOffset);
  2507. lpDP2CurrCommand->bCommand = D3DDP2OP_BUFFERBLT;
  2508. bDP2CurrCmdOP = D3DDP2OP_BUFFERBLT;
  2509. lpDP2CurrCommand->bReserved = 0;
  2510. lpDP2CurrCommand->wStateCount = 1;
  2511. wDP2CurrCmdCnt = 1;
  2512. D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
  2513. // Add texture blt data
  2514. LPD3DHAL_DP2BUFFERBLT lpBufBlt =
  2515. (LPD3DHAL_DP2BUFFERBLT)(lpDP2CurrCommand + 1);
  2516. lpBufBlt->dwDDDestSurface = lpDst == NULL ? 0 :
  2517. lpDst->DriverAccessibleDrawPrimHandle();
  2518. lpBufBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle();
  2519. lpBufBlt->dwOffset = dwOffset;
  2520. lpBufBlt->rSrc = *pRange;
  2521. lpBufBlt->dwFlags = 0;
  2522. dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) +
  2523. sizeof(D3DHAL_DP2BUFFERBLT);
  2524. // For the source, we want to call BatchBase since
  2525. // we want to batch the backing (or sysmem) texture
  2526. // rather than the promoted one.
  2527. lpSrc->BatchBase();
  2528. if(lpDst != 0)
  2529. {
  2530. lpDst->Batch();
  2531. }
  2532. }
  2533. //-----------------------------------------------------------------------------
  2534. #undef DPF_MODNAME
  2535. #define DPF_MODNAME "CD3DDDIDX8::GetMaxRenderState"
  2536. // Note: This is a hack for DX8.1 release. The only renderstates that we added
  2537. // in DX8.1 pertain to the NPATCHES features. At the time of DX8.1 release
  2538. // there were no real drivers besides Reference that could support this feature.
  2539. // We also know that the only can driver that does support the NPATCH feature
  2540. // will support these renderstates (i.e. will be a DX8.1 driver. Hence it is
  2541. // safe to assume that if any driver supports the D3DDEVCAPS_NPATCHES cap, then
  2542. // it is a DX8.1 driver and understands the extra renderstates that were added
  2543. // in DX8.1.
  2544. D3DRENDERSTATETYPE CD3DDDIDX8::GetMaxRenderState()
  2545. {
  2546. const D3DCAPS8* pCaps = m_pDevice->GetD3DCaps();
  2547. if (pCaps->DevCaps & D3DDEVCAPS_NPATCHES)
  2548. {
  2549. return D3D_MAXRENDERSTATES;
  2550. }
  2551. else
  2552. {
  2553. return D3DRS_POSITIONORDER;
  2554. }
  2555. }