Clone of mesa.
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.

D3DTextureMgr.cpp 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  1. /*===========================================================================*/
  2. /* */
  3. /* Mesa-3.0 DirectX 6 Driver */
  4. /* */
  5. /* By Leigh McRae */
  6. /* */
  7. /* http://www.altsoftware.com/ */
  8. /* */
  9. /* Copyright (c) 1999-1998 alt.software inc. All Rights Reserved */
  10. /*===========================================================================*/
  11. #include "D3DHAL.h"
  12. /*===========================================================================*/
  13. /* Local function prototypes. */
  14. /*===========================================================================*/
  15. static void UpdateTexture( PTM_OBJECT pTMObj, BOOL bVideo, RECT *pRect, UCHAR *pixels );
  16. static BOOL LoadTextureInVideo( PMESAD3DHAL pHAL, PTM_OBJECT pTMObj );
  17. static BOOL FreeTextureMemory( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject );
  18. static BOOL DestroyTextureObject( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject );
  19. HRESULT CALLBACK EnumPFHook( LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext );
  20. /*===========================================================================*/
  21. /* This function will simply set the top of stack to NULL. I only used it */
  22. /* just incase I want to add something later. */
  23. /*===========================================================================*/
  24. /* RETURN: TRUE. */
  25. /*===========================================================================*/
  26. BOOL InitTMgrHAL( PMESAD3DHAL pHAL )
  27. {
  28. DPF(( DBG_FUNC, "InitTMgrHAL();" ));
  29. /* Be clean my friend. */
  30. pHAL->pTMList = NULL;
  31. return TRUE;
  32. }
  33. /*===========================================================================*/
  34. /* This function will walk the Texture Managers linked list and destroy all */
  35. /* surfaces (SYSTEM/VIDEO). The texture objects themselves also will be */
  36. /* freed. */
  37. /* NOTE: this is per/context. */
  38. /*===========================================================================*/
  39. /* RETURN: */
  40. /*===========================================================================*/
  41. void TermTMgrHAL( PMESAD3DHAL pHAL )
  42. {
  43. DPF(( DBG_FUNC, "TermTMgrHAL();" ));
  44. if ( pHAL && pHAL->pTMList )
  45. {
  46. /* Destroy the surface and remove the TMO from the stack. */
  47. while( DestroyTextureObject(pHAL,NULL) );
  48. /* Be clean my friend. */
  49. pHAL->pTMList = NULL;
  50. }
  51. }
  52. /*===========================================================================*/
  53. /* This function is a HACK as I don't know how I can disable a texture with-*/
  54. /* out booting it out. Is there know state change? */
  55. /*===========================================================================*/
  56. /* RETURN: */
  57. /*===========================================================================*/
  58. extern "C" void DisableTMgrHAL( PMESAD3DSHARED pShared )
  59. {
  60. PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
  61. DPF(( DBG_FUNC, "DisableTMgrHAL();" ));
  62. /* Check too see that we have a valid context. */
  63. if ( (pHAL == NULL) && (pHAL->lpD3DDevice != NULL) )
  64. {
  65. DPF(( DBG_TXT_WARN, "Null HAL/Direct3D Device!" ));
  66. return;
  67. }
  68. // TODO: This is a hack to shut off textures.
  69. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  70. }
  71. /*===========================================================================*/
  72. /* This function is the only entry into the TextureManager that Mesa/wgl */
  73. /* will see. It uses a dwAction to specify what we are doing. I did this as*/
  74. /* depending on the cards resources the action taken can change. */
  75. /* When this function is called we will always search the Texture Managers */
  76. /* linked list (per context remember) and try and find a structure that has */
  77. /* the same dwName. If we have a match we pull it out of the list and put it*/
  78. /* at the top of the list (TOL). If we don't find one then we create a struc*/
  79. /* and put it a TOL. This TOL idea makes for some caching as we will always */
  80. /* destroy Texture Surfaces from the bottom up... */
  81. /* All texture objects at this point will create a texture surface in System*/
  82. /* memory (SMEM). Then we will copy the Mesa texture into the surface using */
  83. /* the 'pixel' struc to get the translation info. So now this means that all*/
  84. /* textures that Mesa gives me I will have a Surface with a copy. If Mesa */
  85. /* changes the texture the I update the surface in (SMEM). */
  86. /* Now we have a texture struc and a Texture Surface in SMEM. At this point*/
  87. /* we create another surface on the card (VMEM). Finally we blt from the */
  88. /* SMEM to the VMEM and set the texture as current. Why do I need two? First*/
  89. /* this solves square textures. If the cards CAPS is square textures only */
  90. /* then I change the dimensions of the VMEM surface and the blt solves it for*/
  91. /* me. Second it saves me from filling D3D textures over and over if the */
  92. /* card needs to be creating and destroying surfaces because of low memory. */
  93. /* The surface in SMEM is expected to work always. When a surface has to be*/
  94. /* created in VMEM then we put it in a loop that tries to create the surface.*/
  95. /* If we create the surface ok then we brake from the loop. If we fail then */
  96. /* we will call 'FreeTextureMemory' that will return TRUE/FALSE as to whether*/
  97. /* memory was freed. If memory was freed then we can try again. If no memory*/
  98. /* was freed then it just can't fit. */
  99. /* 'FreeTextureMemory' will find the end of the list and start freeing VMEM */
  100. /* (never SMEM) surfaces that are not locked. */
  101. /* BIND - when we bind and there is a texture struct with a texture surface */
  102. /* in VMEM then we just make it current. If we have a struct and a surface */
  103. /* in SMEM but no VMEM surface then we create the surface in VMEM and blt */
  104. /* from the SMEM surface. If we have nothing its just like a creation... */
  105. /*===========================================================================*/
  106. /* RETURN: TRUE, FALSE. */
  107. /*===========================================================================*/
  108. extern "C" BOOL CreateTMgrHAL( PMESAD3DSHARED pShared, DWORD dwName, int level, DWORD dwRequestFlags,
  109. RECT *rectDirty, DWORD dwWidth, DWORD dwHeight, DWORD dwAction, void *pPixels )
  110. {
  111. PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
  112. PTM_OBJECT pTMObj,
  113. pTemp;
  114. DDSURFACEDESC2 ddsd2;
  115. HRESULT rc;
  116. DPF(( DBG_FUNC, "CreateTMgrHAL();" ));
  117. DPF(( DBG_TXT_INFO, "Texture:" ));
  118. DPF(( DBG_TXT_INFO, "cx: %d cy: %d", dwWidth, dwHeight ));
  119. DPF(( DBG_TXT_INFO, "Rect:" ));
  120. if ( rectDirty )
  121. {
  122. DPF(( DBG_TXT_INFO, "x0: %d y0: %d", rectDirty->left, rectDirty->top ));
  123. DPF(( DBG_TXT_INFO, "x1: %d y1: %d", rectDirty->right, rectDirty->bottom ));
  124. }
  125. /* Check too see that we have a valid context. */
  126. if ( (pHAL == NULL) && (pHAL->lpD3DDevice != NULL) )
  127. {
  128. DPF(( DBG_TXT_WARN, "Null HAL/Direct3D Device!" ));
  129. return FALSE;
  130. }
  131. /*=================================================*/
  132. /* See if we can find this texture object by name. */
  133. /*=================================================*/
  134. for( pTMObj = pHAL->pTMList; pTMObj && (pTMObj->dwName != dwName); pTMObj = pTMObj->next );
  135. /*=========================================================*/
  136. /* Allocate a new object if we didn't get a matching name. */
  137. /*=========================================================*/
  138. if ( pTMObj == NULL )
  139. {
  140. pTMObj = (PTM_OBJECT)ALLOC( sizeof(TM_OBJECT) );
  141. if ( pTMObj == NULL )
  142. return FALSE;
  143. memset( pTMObj, 0, sizeof(TM_OBJECT) );
  144. /* Put the object at the beginning of the list. */
  145. pTMObj->next = pHAL->pTMList;
  146. if ( pTMObj->next )
  147. {
  148. pTemp = pTMObj->next;
  149. pTemp->prev = pTMObj;
  150. }
  151. pHAL->pTMList = pTMObj;
  152. }
  153. else
  154. {
  155. /*===============================================================*/
  156. /* Make some caching happen by pulling this object to the front. */
  157. /*===============================================================*/
  158. if ( pHAL->pTMList != pTMObj )
  159. {
  160. /* Pull the object out of the list. */
  161. if ( pTMObj->prev )
  162. {
  163. pTemp = pTMObj->prev;
  164. pTemp->next = pTMObj->next;
  165. }
  166. if ( pTMObj->next )
  167. {
  168. pTemp = pTMObj->next;
  169. pTemp->prev = pTMObj->prev;
  170. }
  171. pTMObj->prev = NULL;
  172. pTMObj->next = NULL;
  173. /* Put the object at the front of the list. */
  174. pTMObj->next = pHAL->pTMList;
  175. if ( pTMObj->next )
  176. {
  177. pTemp = pTMObj->next;
  178. pTemp->prev = pTMObj;
  179. }
  180. pHAL->pTMList = pTMObj;
  181. }
  182. }
  183. /*========================================================*/
  184. /* If we are doing BIND and the texture is in VID memory. */
  185. /*========================================================*/
  186. if ( (dwAction == TM_ACTION_BIND) && pTMObj->lpDDS_Video )
  187. {
  188. DPF(( DBG_TXT_PROFILE, "Cache HIT (%d)", dwName ));
  189. /* Make this the current texture. */
  190. rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
  191. if ( FAILED(rc) )
  192. {
  193. DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
  194. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  195. return FALSE;
  196. }
  197. return TRUE;
  198. }
  199. /*=================================================================*/
  200. /* If we are doing BIND and the texture is at least in SYS memory. */
  201. /*=================================================================*/
  202. if ( (dwAction == TM_ACTION_BIND) && pTMObj->lpDDS_System )
  203. {
  204. DPF(( DBG_TXT_PROFILE, "Cache MISS (%d)", dwName ));
  205. /* Create the texture on the card. */
  206. rc = LoadTextureInVideo( pHAL, pTMObj );
  207. if ( rc == FALSE )
  208. return FALSE;
  209. /* Make this the current texture. */
  210. rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
  211. if ( FAILED(rc) )
  212. {
  213. DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
  214. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  215. return FALSE;
  216. }
  217. return TRUE;
  218. }
  219. /*=========================================================*/
  220. /* If we are doing UPDATE then try in VID first for speed. */
  221. /*=========================================================*/
  222. if ( (dwAction == TM_ACTION_UPDATE) && pTMObj->lpDDS_Video &&
  223. !(pHAL->D3DHWDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) )
  224. {
  225. DPF(( DBG_TXT_INFO, "Fix the SubTexture update Leigh!" ));
  226. /* Update the texture on the card. */
  227. UpdateTexture( pTMObj, TRUE, rectDirty, (UCHAR *)pPixels );
  228. /* We updated the texture in VID so kill the SYS so we know its dirty. */
  229. if ( pTMObj->lpDDS_System )
  230. {
  231. DPF(( DBG_TXT_INFO, "Release texture (SYS)" ));
  232. DX_RESTORE( pTMObj->lpDDS_System );
  233. pTMObj->lpDDS_System->Release();
  234. pTMObj->lpDDS_System = NULL;
  235. }
  236. /* Make this the current texture. */
  237. rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
  238. if ( FAILED(rc) )
  239. {
  240. DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
  241. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  242. return FALSE;
  243. }
  244. return TRUE;
  245. }
  246. /*===========================================================*/
  247. /* If we are doing UPDATE then try in SYS still gives speed. */
  248. /*===========================================================*/
  249. if ( (dwAction == TM_ACTION_UPDATE) && pTMObj->lpDDS_System )
  250. {
  251. DPF(( DBG_TXT_INFO, "Fix the SubTexture update Leigh!" ));
  252. /* Update the texture in SYS. */
  253. UpdateTexture( pTMObj, FALSE, NULL, (UCHAR *)pPixels );
  254. /* We updated the SYS texture only so now blt to the VID. */
  255. rc = LoadTextureInVideo( pHAL, pTMObj );
  256. if ( rc == FALSE )
  257. return FALSE;
  258. /* Make this the current texture. */
  259. rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
  260. if ( FAILED(rc) )
  261. {
  262. DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
  263. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  264. return FALSE;
  265. }
  266. return TRUE;
  267. }
  268. /* At this point we have a valid Texture Manager Object with updated */
  269. /* links. We now need to create or update a texture surface that is */
  270. /* in system memory. Every texture has a copy in system so we can use*/
  271. /* blt to solve problems with textures allocated on the card (square */
  272. /* only textures, pixelformats...). */
  273. // TODO: make support for update also. Dirty rectangle basicly...
  274. /* Kill the interface if we have one no matter what. */
  275. if ( pTMObj->lpD3DTexture2 )
  276. {
  277. DPF(( DBG_TXT_INFO, "Release Texture2" ));
  278. pTMObj->lpD3DTexture2->Release();
  279. pTMObj->lpD3DTexture2 = NULL;
  280. }
  281. /* Kill the system surface. TODO: should try to get the SubIMage going again */
  282. if ( pTMObj->lpDDS_System )
  283. {
  284. DPF(( DBG_TXT_INFO, "Release texture (SYS)" ));
  285. DX_RESTORE( pTMObj->lpDDS_System );
  286. pTMObj->lpDDS_System->Release();
  287. pTMObj->lpDDS_System = NULL;
  288. }
  289. /* Kill the Video surface. TODO: need some reuse system... */
  290. if ( pTMObj->lpDDS_Video )
  291. {
  292. DPF(( DBG_TXT_INFO, "Release texture (VID)" ));
  293. DX_RESTORE( pTMObj->lpDDS_Video );
  294. pTMObj->lpDDS_Video->Release();
  295. pTMObj->lpDDS_Video = NULL;
  296. }
  297. /*================================================================*/
  298. /* Translate the the Mesa/OpenGL pixel channels to the D3D flags. */
  299. /*================================================================*/
  300. switch( dwRequestFlags )
  301. {
  302. case GL_ALPHA:
  303. dwRequestFlags = DDPF_ALPHA;
  304. DPF(( DBG_TXT_WARN, "GL_ALPHA not supported!)" ));
  305. return FALSE;
  306. case GL_INTENSITY:
  307. case GL_LUMINANCE:
  308. DPF(( DBG_TXT_WARN, "GL_INTENSITY/GL_LUMINANCE not supported!)" ));
  309. dwRequestFlags = DDPF_LUMINANCE;
  310. return FALSE;
  311. case GL_LUMINANCE_ALPHA:
  312. DPF(( DBG_TXT_WARN, "GL_LUMINANCE_ALPHA not supported!)" ));
  313. dwRequestFlags = DDPF_LUMINANCE | DDPF_ALPHAPIXELS;
  314. return FALSE;
  315. case GL_RGB:
  316. DPF(( DBG_TXT_INFO, "Texture -> GL_RGB" ));
  317. dwRequestFlags = DDPF_RGB;
  318. break;
  319. case GL_RGBA:
  320. DPF(( DBG_TXT_INFO, "Texture -> GL_RGBA" ));
  321. dwRequestFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
  322. break;
  323. }
  324. /*==============================*/
  325. /* Populate the texture object. */
  326. /*==============================*/
  327. pTMObj->dwName = dwName;
  328. pTMObj->lpD3DDevice = pHAL->lpD3DDevice;
  329. pTMObj->dwFlags = dwRequestFlags;
  330. if ( pHAL->D3DHWDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
  331. {
  332. DPF(( DBG_TXT_INFO, "Convert to Square..." ));
  333. pTMObj->dwSHeight = dwHeight;
  334. pTMObj->dwSWidth = dwWidth;
  335. /* Shrink non-square textures. */
  336. pTMObj->dwVHeight = (dwHeight > dwWidth) ? dwWidth : dwHeight;
  337. pTMObj->dwVWidth = (dwHeight > dwWidth) ? dwWidth : dwHeight;
  338. }
  339. else
  340. {
  341. pTMObj->dwSHeight = dwHeight;
  342. pTMObj->dwSWidth = dwWidth;
  343. pTMObj->dwVHeight = dwHeight;
  344. pTMObj->dwVWidth = dwWidth;
  345. }
  346. /*========================*/
  347. /* Create SYSTEM surface. */
  348. /*========================*/
  349. /* Request a surface in system memory. */
  350. memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
  351. ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
  352. ddsd2.dwWidth = pTMObj->dwSWidth;
  353. ddsd2.dwHeight = pTMObj->dwSHeight;
  354. ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
  355. ddsd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
  356. ddsd2.ddsCaps.dwCaps2 = 0L;
  357. memset( &ddsd2.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT) );
  358. ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
  359. ddsd2.ddpfPixelFormat.dwFlags = dwRequestFlags;
  360. rc = pHAL->lpD3DDevice->EnumTextureFormats( EnumPFHook, &ddsd2.ddpfPixelFormat );
  361. if ( FAILED(rc) )
  362. {
  363. RIP( pHAL, "EnumerTextureFormats (SYSTEM)->", ErrorStringD3D(rc) );
  364. return FALSE;
  365. }
  366. /* Create the surface using the enumerated pixelformat. */
  367. rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pTMObj->lpDDS_System, NULL );
  368. if ( FAILED(rc) )
  369. {
  370. RIP( pHAL, "CreateSurface (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) );
  371. return FALSE;
  372. }
  373. /* Solve the pixel mapping info using the surface pixelformat. */
  374. Solve8BitChannelPixelFormat( &ddsd2.ddpfPixelFormat, &pTMObj->pixel );
  375. /*===================================================================*/
  376. /* Fill the texture using the PixelInfo structure to do the mapping. */
  377. /*===================================================================*/
  378. UpdateTexture( pTMObj, FALSE, NULL, (UCHAR *)pPixels );
  379. /*=======================*/
  380. /* Create VIDEO surface. */
  381. /*=======================*/
  382. rc = LoadTextureInVideo( pHAL, pTMObj );
  383. if ( rc == FALSE )
  384. return FALSE;
  385. /* Make this the current texture. */
  386. rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
  387. if ( FAILED(rc) )
  388. {
  389. DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
  390. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  391. return FALSE;
  392. }
  393. return TRUE;
  394. }
  395. /*===========================================================================*/
  396. /* This function will handle the creation and destruction of the texture */
  397. /* surfaces on the card. Using the dw'V'Width/Height dimensions the call */
  398. /* try and create the texture on the card and keep using FreeTextureMemory */
  399. /* until the surace can be created. Once the surface is created we get the */
  400. /* interface that we will use to make it the current texture. I didn't put */
  401. /* the code to make the texture current in this function as BIND needs to */
  402. /* use the same code and this function doesn't always get called when we do a*/
  403. /* bind. */
  404. /*===========================================================================*/
  405. /* RETURN: TRUE, FALSE. */
  406. /*===========================================================================*/
  407. static BOOL LoadTextureInVideo( PMESAD3DHAL pHAL, PTM_OBJECT pTMObj )
  408. {
  409. DDSURFACEDESC2 ddsd2;
  410. HRESULT rc;
  411. DPF(( DBG_FUNC, "LoadTextureInVideo();" ));
  412. /* Kill the interface if we have one no matter what. */
  413. if ( pTMObj->lpD3DTexture2 )
  414. {
  415. DPF(( DBG_TXT_INFO, "Release Texture2" ));
  416. pTMObj->lpD3DTexture2->Release();
  417. pTMObj->lpD3DTexture2 = NULL;
  418. }
  419. /* Kill the Video surface. TODO: need some reuse system... */
  420. if ( pTMObj->lpDDS_Video )
  421. {
  422. DPF(( DBG_TXT_INFO, "Release texture (VID)" ));
  423. DX_RESTORE( pTMObj->lpDDS_Video );
  424. pTMObj->lpDDS_Video->Release();
  425. pTMObj->lpDDS_Video = NULL;
  426. }
  427. /* Request a surface in Video memory. */
  428. memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
  429. ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
  430. ddsd2.dwWidth = pTMObj->dwVWidth;
  431. ddsd2.dwHeight = pTMObj->dwVHeight;
  432. ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
  433. ddsd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
  434. ddsd2.ddsCaps.dwCaps2 = 0L;
  435. memset( &ddsd2.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT) );
  436. ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
  437. ddsd2.ddpfPixelFormat.dwFlags = pTMObj->dwFlags;
  438. rc = pHAL->lpD3DDevice->EnumTextureFormats( EnumPFHook, &ddsd2.ddpfPixelFormat );
  439. if ( FAILED(rc) )
  440. {
  441. RIP( pHAL, "EnumerTextureFormats ->", ErrorStringD3D(rc) );
  442. return FALSE;
  443. }
  444. /* Make sure we lock so we don't nuke this texture trying to free memory for it. */
  445. pTMObj->bLock = TRUE;
  446. /* Start a loop that will free all textures until we have created the texture */
  447. /* surface or we can't free up more memory. */
  448. do
  449. {
  450. /* Try to create the texture surface. */
  451. rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pTMObj->lpDDS_Video, NULL );
  452. if ( !FAILED(rc) )
  453. break;
  454. DPF(( DBG_TXT_INFO, "Free Texture Memory" ));
  455. /* DestroyTexture will return TRUE if a surface was freed. */
  456. } while( FreeTextureMemory(pHAL,NULL) );
  457. /* Make sure we unlock or we won't be able to nuke the TMO later. */
  458. pTMObj->bLock = FALSE;
  459. /* Did we create a valid texture surface? */
  460. if ( FAILED(rc) )
  461. {
  462. DPF(( DBG_TXT_WARN, "Failed to load texture" ));
  463. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  464. return FALSE;
  465. }
  466. DX_RESTORE( pTMObj->lpDDS_System );
  467. DX_RESTORE( pTMObj->lpDDS_Video );
  468. DPF(( DBG_TXT_INFO, "Texture Blt SYSTEM -> VID" ));
  469. /* Now blt the texture in system memory to the card. */
  470. rc = pTMObj->lpDDS_Video->Blt( NULL, pTMObj->lpDDS_System, NULL, DDBLT_WAIT, NULL );
  471. if ( FAILED(rc) )
  472. {
  473. RIP( pHAL, "Blt (TEXTURE) ->", ErrorStringD3D(rc) );
  474. return FALSE;
  475. }
  476. /* Get the Texture interface that is used to render with. */
  477. pTMObj->lpDDS_Video->QueryInterface( IID_IDirect3DTexture2, (void **)&pTMObj->lpD3DTexture2 );
  478. if ( pTMObj->lpD3DTexture2 == NULL )
  479. {
  480. DPF(( DBG_TXT_WARN, "Failed QueryTextureInterface" ));
  481. pHAL->lpD3DDevice->SetTexture( 0, NULL );
  482. return FALSE;
  483. }
  484. return TRUE;
  485. }
  486. /*===========================================================================*/
  487. /* If this function gets a texture object struc then we will try and free */
  488. /* it. If we get a NULL then we will search from the bottom up and free one */
  489. /* VMEM surface. I can only free when the surface isn't locked and of course*/
  490. /* there must be a VMEM surface. We never free SMEM surfaces as that isn't */
  491. /* the point. */
  492. /* TODO: should have a pointer to the bottom of the stack really. */
  493. /*===========================================================================*/
  494. /* RETURN: */
  495. /*===========================================================================*/
  496. static BOOL FreeTextureMemory( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject )
  497. {
  498. PTM_OBJECT pCurrent;
  499. BOOL bFreed = FALSE;
  500. DPF(( DBG_FUNC, "FreeTextureMemory();" ));
  501. DPF(( DBG_TXT_WARN, "FREE TEXTURE!" ));
  502. /* Just to be safe. */
  503. if ( !pHAL || !pHAL->pTMList )
  504. {
  505. DPF(( DBG_TXT_WARN, "FreeTextureMemory() -> NULL pHAL/pHAL->pTMList" ));
  506. return FALSE;
  507. }
  508. /* Free the last texture in the list. */
  509. if ( pTMObject == NULL )
  510. {
  511. DPF(( DBG_TXT_INFO, "Free Last texture in cache" ));
  512. /* Find the last texture object. */
  513. for( pCurrent = pHAL->pTMList; pCurrent->next; pCurrent = pCurrent->next );
  514. /* Now backup until we find a texture on the card. */
  515. while( pCurrent && (pCurrent->lpDDS_Video == NULL) && (pCurrent->bLock == FALSE) )
  516. pCurrent = pCurrent->prev;
  517. /* Didn't find anything. */
  518. if ( pCurrent == NULL )
  519. {
  520. DPF(( DBG_TXT_INFO, "No texture memory freed" ));
  521. return FALSE;
  522. }
  523. }
  524. else
  525. {
  526. /* See if we can find this texture object. */
  527. for( pCurrent = pHAL->pTMList; pCurrent && (pCurrent != pTMObject); pCurrent = pCurrent->next );
  528. /* Didn't find anything. */
  529. if ( pCurrent == NULL )
  530. {
  531. DPF(( DBG_TXT_INFO, "Requested texture to be freed NOT FOUND" ));
  532. return FALSE;
  533. }
  534. }
  535. /* Can't free this baby. */
  536. if ( pCurrent->bLock == TRUE )
  537. {
  538. DPF(( DBG_TXT_WARN, "Requested texture LOCKED" ));
  539. return FALSE;
  540. }
  541. /* Free the texture memory. */
  542. if ( pCurrent->lpD3DTexture2 )
  543. {
  544. DPF(( DBG_TXT_INFO, "Release Texture2" ));
  545. pCurrent->lpD3DTexture2->Release();
  546. pCurrent->lpD3DTexture2 = NULL;
  547. bFreed = TRUE;
  548. }
  549. if ( pCurrent->lpDDS_Video )
  550. {
  551. DPF(( DBG_TXT_INFO, "Release texture (VID):" ));
  552. DPF(( DBG_TXT_INFO, "dwName: %d", pCurrent->dwName ));
  553. DPF(( DBG_TXT_INFO, "cx: %d, cy: %d", pCurrent->dwVWidth, pCurrent->dwVHeight ));
  554. pCurrent->lpDDS_Video->Release();
  555. pCurrent->lpDDS_Video = NULL;
  556. bFreed = TRUE;
  557. }
  558. return bFreed;
  559. }
  560. /*===========================================================================*/
  561. /* This function searches the linked list of texture objects in the supplied*/
  562. /* D3Dwrapper structure. If it finds a match it will free it and pull it out*/
  563. /* of the linked list. The function works on the bases of a matching pointer*/
  564. /* to the object (not matching content). */
  565. /* If the function gets passed a NULL then we want to free the last texture */
  566. /* object in the list. Used in a loop to destory all. */
  567. /*===========================================================================*/
  568. /* RETURN: TRUE, FALSE. */
  569. /*===========================================================================*/
  570. static BOOL DestroyTextureObject( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject )
  571. {
  572. PTM_OBJECT pCurrent;
  573. DPF(( DBG_FUNC, "DestoryTextureObject();" ));
  574. /* Just to be safe. */
  575. if ( !pHAL || !pHAL->pTMList )
  576. {
  577. DPF(( DBG_TXT_WARN, "DestroyTextureObject() -> NULL pHAL/pHAL->pTMList" ));
  578. return FALSE;
  579. }
  580. /* Free the last texture in the list. */
  581. if ( pTMObject == NULL )
  582. {
  583. /* Find the last texture object. */
  584. for( pCurrent = pHAL->pTMList; pCurrent->next; pCurrent = pCurrent->next );
  585. }
  586. else
  587. {
  588. /* See if we can find this texture object. */
  589. for( pCurrent = pHAL->pTMList; pCurrent && (pCurrent != pTMObject); pCurrent = pCurrent->next );
  590. /* Didn't find anything. */
  591. if ( pCurrent == NULL )
  592. {
  593. DPF(( DBG_TXT_WARN, "No textures to be freed" ));
  594. return FALSE;
  595. }
  596. }
  597. /* Can't free this baby. */
  598. if ( pCurrent->bLock == TRUE )
  599. {
  600. DPF(( DBG_TXT_WARN, "Requested texture to be freed LOCKED" ));
  601. return FALSE;
  602. }
  603. /* Free the texture memory. */
  604. if ( pCurrent->lpD3DTexture2 )
  605. {
  606. DPF(( DBG_TXT_INFO, "Release Texture2" ));
  607. pCurrent->lpD3DTexture2->Release();
  608. pCurrent->lpD3DTexture2 = NULL;
  609. }
  610. if ( pCurrent->lpDDS_Video )
  611. {
  612. DPF(( DBG_TXT_INFO, "Release texture (VID):" ));
  613. pCurrent->lpDDS_Video->Release();
  614. pCurrent->lpDDS_Video = NULL;
  615. }
  616. if ( pCurrent->lpDDS_System )
  617. {
  618. DPF(( DBG_TXT_INFO, "Release texture (SYS):" ));
  619. pCurrent->lpDDS_System->Release();
  620. pCurrent->lpDDS_System = NULL;
  621. }
  622. /* Pull this texture out of the list. */
  623. if ( pCurrent == pHAL->pTMList )
  624. pHAL->pTMList = NULL;
  625. if ( pCurrent->prev )
  626. (pCurrent->prev)->next = pCurrent->next;
  627. if ( pCurrent->next )
  628. (pCurrent->next)->prev = pCurrent->prev;
  629. FREE( pCurrent );
  630. return TRUE;
  631. }
  632. /*===========================================================================*/
  633. /* This function is the callback function that gets called when we are doing*/
  634. /* an enumeration of the texture formats supported by this device. The choice*/
  635. /* is made by checking to see if we have a match with the supplied D3D pixel-*/
  636. /* format. So the enumeration has to pass a desired D3D PF as the user var. */
  637. /*===========================================================================*/
  638. /* RETURN: D3DENUMRET_OK, D3DENUMRET_CANCEL. */
  639. /*===========================================================================*/
  640. static void UpdateTexture( PTM_OBJECT pTMObj, BOOL bVideo, RECT *pRect, UCHAR *pixels )
  641. {
  642. LPDIRECTDRAWSURFACE4 lpDDS;
  643. DDSURFACEDESC2 ddsd2;
  644. DWORD srcPitch,
  645. dwHeight,
  646. dwWidth,
  647. dwCol,
  648. dwColor;
  649. UCHAR *pSrc,
  650. *pSrcRow,
  651. *pDest,
  652. *pDestRow;
  653. int rc;
  654. // TODO: Do I need to pass the h/w when its in the object!
  655. DPF(( DBG_FUNC, "UpdateTexture();" ));
  656. /* Get the surface pointer we are looking for. */
  657. lpDDS = (bVideo) ? pTMObj->lpDDS_Video : pTMObj->lpDDS_System;
  658. /*===================================================================*/
  659. /* Fill the texture using the PixelInfo structure to do the mapping. */
  660. /*===================================================================*/
  661. /* Get the surface pointer. */
  662. memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
  663. ddsd2.dwSize = sizeof(DDSURFACEDESC2);
  664. rc = lpDDS->Lock( NULL, &ddsd2, DDLOCK_WAIT, NULL );
  665. if ( FAILED(rc) )
  666. {
  667. RIP( NULL, "Lock (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) );
  668. return;
  669. }
  670. /* For now we are only updating the system surface so use its dimensions. */
  671. dwWidth = (bVideo) ? pTMObj->dwVWidth : pTMObj->dwSWidth;
  672. dwHeight = (bVideo) ? pTMObj->dwVHeight : pTMObj->dwSHeight;
  673. /* If we are updating the whole surface then the pDest/pSrc will */
  674. /* always be the same. */
  675. if ( pRect == NULL )
  676. {
  677. pDest = (UCHAR *)ddsd2.lpSurface;
  678. pSrc = pixels;
  679. }
  680. /* Fill the texture surface based on the pixelformat flags. */
  681. if ( pTMObj->dwFlags == (DDPF_RGB | DDPF_ALPHAPIXELS) )
  682. {
  683. srcPitch = dwWidth * 4;
  684. if ( pRect )
  685. {
  686. pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
  687. pSrc = pixels + (pRect->top * dwWidth * 4) + (pRect->left * 4);
  688. dwHeight = (pRect->bottom - pRect->top);
  689. dwWidth = (pRect->right - pRect->left);
  690. }
  691. for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
  692. {
  693. for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
  694. {
  695. dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
  696. dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.gScale)) << pTMObj->pixel.gShift );
  697. dwColor |= ( ((DWORD)(*(pSrc+2) * pTMObj->pixel.bScale)) << pTMObj->pixel.bShift );
  698. if ( pTMObj->pixel.aScale == -1.0 )
  699. dwColor |= ( (*(pSrc+3) & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 );
  700. else
  701. dwColor |= ( ((DWORD)(*(pSrc+3) * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift );
  702. memcpy( pDest, &dwColor, pTMObj->pixel.cb );
  703. pDest += pTMObj->pixel.cb;
  704. pSrc += 4;
  705. }
  706. }
  707. }
  708. else if ( pTMObj->dwFlags == DDPF_RGB )
  709. {
  710. srcPitch = dwWidth * 3;
  711. if ( pRect )
  712. {
  713. pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
  714. pSrc = pixels + (pRect->top * dwWidth * 3) + (pRect->left * 3);
  715. dwHeight = (pRect->bottom - pRect->top);
  716. dwWidth = (pRect->right - pRect->left);
  717. }
  718. for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
  719. {
  720. for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
  721. {
  722. dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
  723. dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.gScale)) << pTMObj->pixel.gShift );
  724. dwColor |= ( ((DWORD)(*(pSrc+2) * pTMObj->pixel.bScale)) << pTMObj->pixel.bShift );
  725. memcpy( pDest, &dwColor, pTMObj->pixel.cb );
  726. pDest += pTMObj->pixel.cb;
  727. pSrc += 3;
  728. }
  729. }
  730. }
  731. else if ( pTMObj->dwFlags == (DDPF_LUMINANCE | DDPF_ALPHAPIXELS) )
  732. {
  733. srcPitch = dwWidth * 2;
  734. if ( pRect )
  735. {
  736. pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
  737. pSrc = pixels + (pRect->top * dwWidth * 2) + (pRect->left * 2);
  738. dwHeight = (pRect->bottom - pRect->top);
  739. dwWidth = (pRect->right - pRect->left);
  740. }
  741. for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
  742. {
  743. for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
  744. {
  745. dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
  746. if ( pTMObj->pixel.aScale == -1.0 )
  747. dwColor |= ( (*(pSrc+1) & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 );
  748. else
  749. dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift );
  750. memcpy( pDest, &dwColor, pTMObj->pixel.cb );
  751. pDest += pTMObj->pixel.cb;
  752. pSrc += 2;
  753. }
  754. }
  755. }
  756. else if ( pTMObj->dwFlags == DDPF_LUMINANCE )
  757. {
  758. srcPitch = dwWidth;
  759. if ( pRect )
  760. {
  761. pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
  762. pSrc = pixels + (pRect->top * dwWidth) + (pRect->left);
  763. dwHeight = (pRect->bottom - pRect->top);
  764. dwWidth = (pRect->right - pRect->left);
  765. }
  766. for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
  767. {
  768. for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
  769. {
  770. dwColor = ( ((DWORD)(*pSrc * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
  771. memcpy( pDest, &dwColor, pTMObj->pixel.cb );
  772. pDest += pTMObj->pixel.cb;
  773. pSrc++;
  774. }
  775. }
  776. }
  777. else if ( pTMObj->dwFlags == DDPF_ALPHAPIXELS )
  778. {
  779. srcPitch = dwWidth;
  780. if ( pRect )
  781. {
  782. pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
  783. pSrc = pixels + (pRect->top * dwWidth) + (pRect->left);
  784. dwHeight = (pRect->bottom - pRect->top);
  785. dwWidth = (pRect->right - pRect->left);
  786. }
  787. for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
  788. {
  789. for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
  790. {
  791. if ( pTMObj->pixel.aScale == -1.0 )
  792. dwColor = ( (*pSrc & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 );
  793. else
  794. dwColor = ( ((DWORD)(*pSrc * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift );
  795. memcpy( pDest, &dwColor, pTMObj->pixel.cb );
  796. pDest += pTMObj->pixel.cb;
  797. pSrc++;
  798. }
  799. }
  800. }
  801. /* Unlock the surface. */
  802. rc = lpDDS->Unlock( NULL );
  803. if ( FAILED(rc) )
  804. {
  805. RIP( NULL, "Unlock (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) );
  806. }
  807. }
  808. /*===========================================================================*/
  809. /* This function is the callback function that gets called when we are doing*/
  810. /* an enumeration of the texture formats supported by this device. The choice*/
  811. /* is made by checking to see if we have a match with the supplied D3D pixel-*/
  812. /* format. So the enumeration has to pass a desired D3D PF as the user var. */
  813. /*===========================================================================*/
  814. /* RETURN: D3DENUMRET_OK, D3DENUMRET_CANCEL. */
  815. /*===========================================================================*/
  816. HRESULT CALLBACK EnumPFHook( LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext )
  817. {
  818. LPDDPIXELFORMAT lpDDPixFmtRequest = (LPDDPIXELFORMAT)lpContext;
  819. PIXELINFO pixel;
  820. DPF(( DBG_FUNC, "EnumPFHook();" ));
  821. if ( lpDDPixFmt->dwFlags == lpDDPixFmtRequest->dwFlags )
  822. {
  823. /* Are we looking for an alpha channel? */
  824. if ( lpDDPixFmtRequest->dwFlags & DDPF_ALPHAPIXELS )
  825. {
  826. /* Try for something that has more then 1bits of Alpha. */
  827. Solve8BitChannelPixelFormat( lpDDPixFmt, &pixel );
  828. if ( pixel.aScale == -1.0 )
  829. {
  830. /* Save this format no matter what as its a match of sorts. */
  831. memcpy( lpDDPixFmtRequest, lpDDPixFmt, sizeof(DDPIXELFORMAT) );
  832. return D3DENUMRET_OK;
  833. }
  834. }
  835. /* Save this format as its a good match. */
  836. memcpy( lpDDPixFmtRequest, lpDDPixFmt, sizeof(DDPIXELFORMAT) );
  837. /* We are happy at this point so lets leave. */
  838. return D3DENUMRET_CANCEL;
  839. }
  840. return D3DENUMRET_OK;
  841. }