Gfx_Direct3D_Textures.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #ifdef SE1_D3D
  14. #include <d3dx8tex.h>
  15. #pragma comment(lib, "d3dx8.lib")
  16. #include <Engine/Graphics/GfxLibrary.h>
  17. #include <Engine/Base/Statistics_internal.h>
  18. #include <Engine/Math/Functions.h>
  19. #include <Engine/Graphics/GfxProfile.h>
  20. #include <Engine/Base/ListIterator.inl>
  21. // asm shortcuts
  22. #define O offset
  23. #define Q qword ptr
  24. #define D dword ptr
  25. #define W word ptr
  26. #define B byte ptr
  27. // we need array for Direct3D mipmaps that are lower than N*1 or 1*N
  28. static ULONG _aulLastMipmaps[(INDEX)(1024*1.334)];
  29. static CTexParams *_tpCurrent;
  30. static _D3DTEXTUREFILTERTYPE _eLastMipFilter;
  31. extern INDEX GFX_iActiveTexUnit;
  32. // conversion from OpenGL's RGBA color format to one of D3D color formats
  33. extern void SetInternalFormat_D3D( D3DFORMAT d3dFormat);
  34. extern void UploadMipmap_D3D( ULONG *pulSrc, LPDIRECT3DTEXTURE8 ptexDst, PIX pixWidth, PIX pixHeight, INDEX iMip);
  35. // unpacks texture filtering from one INDEX to two GLenums (and eventually re-adjust input INDEX)
  36. extern void UnpackFilter_D3D( INDEX iFilter, _D3DTEXTUREFILTERTYPE &eMagFilter,
  37. _D3DTEXTUREFILTERTYPE &eMinFilter, _D3DTEXTUREFILTERTYPE &eMipFilter)
  38. {
  39. switch( iFilter) {
  40. case 110: case 10: eMagFilter=D3DTEXF_POINT; eMinFilter=D3DTEXF_POINT; eMipFilter=D3DTEXF_NONE; break;
  41. case 111: case 11: eMagFilter=D3DTEXF_POINT; eMinFilter=D3DTEXF_POINT; eMipFilter=D3DTEXF_POINT; break;
  42. case 112: case 12: eMagFilter=D3DTEXF_POINT; eMinFilter=D3DTEXF_POINT; eMipFilter=D3DTEXF_LINEAR; break;
  43. case 220: case 20: eMagFilter=D3DTEXF_LINEAR; eMinFilter=D3DTEXF_LINEAR; eMipFilter=D3DTEXF_NONE; break;
  44. case 221: case 21: eMagFilter=D3DTEXF_LINEAR; eMinFilter=D3DTEXF_LINEAR; eMipFilter=D3DTEXF_POINT; break;
  45. case 222: case 22: eMagFilter=D3DTEXF_LINEAR; eMinFilter=D3DTEXF_LINEAR; eMipFilter=D3DTEXF_LINEAR; break;
  46. case 120: eMagFilter=D3DTEXF_POINT; eMinFilter=D3DTEXF_LINEAR; eMipFilter=D3DTEXF_NONE; break;
  47. case 121: eMagFilter=D3DTEXF_POINT; eMinFilter=D3DTEXF_LINEAR; eMipFilter=D3DTEXF_POINT; break;
  48. case 122: eMagFilter=D3DTEXF_POINT; eMinFilter=D3DTEXF_LINEAR; eMipFilter=D3DTEXF_LINEAR; break;
  49. case 210: eMagFilter=D3DTEXF_LINEAR; eMinFilter=D3DTEXF_POINT; eMipFilter=D3DTEXF_NONE; break;
  50. case 211: eMagFilter=D3DTEXF_LINEAR; eMinFilter=D3DTEXF_POINT; eMipFilter=D3DTEXF_POINT; break;
  51. case 212: eMagFilter=D3DTEXF_LINEAR; eMinFilter=D3DTEXF_POINT; eMipFilter=D3DTEXF_LINEAR; break;
  52. default: ASSERTALWAYS( "Illegal Direct3D texture filtering mode."); break;
  53. }
  54. }
  55. // change texture filtering mode if needed
  56. extern void MimicTexParams_D3D( CTexParams &tpLocal)
  57. {
  58. ASSERT( &tpLocal!=NULL);
  59. _pfGfxProfile.StartTimer( CGfxProfile::PTI_TEXTUREPARAMS);
  60. // update texture filtering mode if required
  61. if( tpLocal.tp_iFilter != _tpGlobal[0].tp_iFilter) tpLocal.tp_iFilter = _tpGlobal[0].tp_iFilter;
  62. // eventually adjust filtering for textures w/o mipmaps
  63. const INDEX iMipFilter = _tpGlobal[0].tp_iFilter % 10;
  64. if( (!tpLocal.tp_bSingleMipmap != !_tpGlobal[GFX_iActiveTexUnit].tp_bSingleMipmap) && iMipFilter!=0)
  65. {
  66. HRESULT hr;
  67. _D3DTEXTUREFILTERTYPE eMipFilter;
  68. extern INDEX GFX_iActiveTexUnit;
  69. // no mipmaps?
  70. if( tpLocal.tp_bSingleMipmap) {
  71. #ifndef NDEBUG
  72. // paranoid!
  73. hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_MIPFILTER, (ULONG*)&eMipFilter);
  74. D3D_CHECKERROR(hr);
  75. ASSERT( eMipFilter==D3DTEXF_POINT || eMipFilter==D3DTEXF_LINEAR);
  76. #endif // set it
  77. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_MIPFILTER, D3DTEXF_NONE);
  78. }
  79. // yes mipmaps?
  80. else {
  81. switch( iMipFilter) {
  82. case 0: eMipFilter = D3DTEXF_NONE; break;
  83. case 1: eMipFilter = D3DTEXF_POINT; break;
  84. case 2: eMipFilter = D3DTEXF_LINEAR; break;
  85. default: ASSERTALWAYS( "Invalid mipmap filtering mode.");
  86. } // set it
  87. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_MIPFILTER, eMipFilter);
  88. }
  89. // check and update mipmap state
  90. D3D_CHECKERROR(hr);
  91. _tpGlobal[GFX_iActiveTexUnit].tp_bSingleMipmap = tpLocal.tp_bSingleMipmap;
  92. }
  93. // update texture anisotropy degree
  94. if( tpLocal.tp_iAnisotropy != _tpGlobal[0].tp_iAnisotropy) tpLocal.tp_iAnisotropy = _tpGlobal[0].tp_iAnisotropy;
  95. // update texture clamping modes if changed
  96. if( tpLocal.tp_eWrapU!=_tpGlobal[GFX_iActiveTexUnit].tp_eWrapU || tpLocal.tp_eWrapV!=_tpGlobal[GFX_iActiveTexUnit].tp_eWrapV) {
  97. tpLocal.tp_eWrapU = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU;
  98. tpLocal.tp_eWrapV = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV;
  99. }
  100. // keep last texture params (for tex upload and stuff)
  101. _tpCurrent = &tpLocal;
  102. _pfGfxProfile.StopTimer( CGfxProfile::PTI_TEXTUREPARAMS);
  103. }
  104. // upload context for current texture to accelerator's memory
  105. // (returns format in which texture was really uploaded)
  106. extern void UploadTexture_D3D( LPDIRECT3DTEXTURE8 *ppd3dTexture, ULONG *pulTexture,
  107. PIX pixSizeU, PIX pixSizeV, D3DFORMAT eInternalFormat, BOOL bDiscard)
  108. {
  109. // safeties
  110. ASSERT( pulTexture!=NULL);
  111. ASSERT( pixSizeU>0 && pixSizeV>0);
  112. _sfStats.StartTimer( CStatForm::STI_BINDTEXTURE);
  113. _pfGfxProfile.StartTimer( CGfxProfile::PTI_TEXTUREUPLOADING);
  114. // recreate texture if needed
  115. HRESULT hr;
  116. if( bDiscard) {
  117. if( (*ppd3dTexture)!=NULL) D3DRELEASE( (*ppd3dTexture), TRUE);
  118. hr = _pGfx->gl_pd3dDevice->CreateTexture( pixSizeU, pixSizeV, 0, 0, eInternalFormat, D3DPOOL_MANAGED, ppd3dTexture);
  119. D3D_CHECKERROR(hr);
  120. }
  121. // D3D texture must be valid now
  122. LPDIRECT3DTEXTURE8 pd3dTex = (*ppd3dTexture);
  123. ASSERT( pd3dTex!=NULL);
  124. // prepare routine for conversion
  125. SetInternalFormat_D3D(eInternalFormat);
  126. // upload each mipmap
  127. INDEX iMip=0;
  128. PIX pixOffset=0;
  129. while( pixSizeU>0 && pixSizeV>0)
  130. {
  131. // check that memory is readable and upload one mipmap
  132. ASSERT( pulTexture[pixOffset +pixSizeU*pixSizeV -1] != 0xDEADBEEF);
  133. UploadMipmap_D3D( pulTexture+pixOffset, pd3dTex, pixSizeU, pixSizeV, iMip);
  134. // advance to next mip-map
  135. pixOffset += pixSizeU*pixSizeV;
  136. pixSizeU >>=1;
  137. pixSizeV >>=1;
  138. iMip++;
  139. // end here if there is only one mip-map to upload
  140. if( _tpCurrent->tp_bSingleMipmap) break;
  141. }
  142. // see if we need to generate and upload additional mipmaps (those under 1*N or N*1)
  143. if( !_tpCurrent->tp_bSingleMipmap && pixSizeU!=pixSizeV)
  144. { // prepare variables
  145. PIX pixSize = Max(pixSizeU,pixSizeV);
  146. ASSERT( pixSize<=2048);
  147. ULONG *pulSrc = pulTexture+pixOffset-pixSize*2;
  148. ULONG *pulDst = _aulLastMipmaps;
  149. // loop thru mipmaps
  150. while( pixSizeU>0 || pixSizeV>0)
  151. { // make next mipmap
  152. if( pixSizeU==0) pixSizeU=1;
  153. if( pixSizeV==0) pixSizeV=1;
  154. pixSize = pixSizeU*pixSizeV;
  155. __asm {
  156. pxor mm0,mm0
  157. mov esi,D [pulSrc]
  158. mov edi,D [pulDst]
  159. mov ecx,D [pixSize]
  160. pixLoop:
  161. movd mm1,D [esi+0]
  162. movd mm2,D [esi+4]
  163. punpcklbw mm1,mm0
  164. punpcklbw mm2,mm0
  165. paddw mm1,mm2
  166. psrlw mm1,1
  167. packuswb mm1,mm0
  168. movd D [edi],mm1
  169. add esi,4*2
  170. add edi,4
  171. dec ecx
  172. jnz pixLoop
  173. emms
  174. }
  175. // upload mipmap and advance
  176. UploadMipmap_D3D( pulDst, pd3dTex, pixSizeU, pixSizeV, iMip);
  177. pulSrc = pulDst;
  178. pulDst += pixSize;
  179. pixOffset += pixSize;
  180. pixSizeU >>=1;
  181. pixSizeV >>=1;
  182. iMip++;
  183. }
  184. }
  185. // all done
  186. _pfGfxProfile.IncrementCounter( CGfxProfile::PCI_TEXTUREUPLOADS, 1);
  187. _pfGfxProfile.IncrementCounter( CGfxProfile::PCI_TEXTUREUPLOADBYTES, pixOffset*4);
  188. _sfStats.IncrementCounter( CStatForm::SCI_TEXTUREUPLOADS, 1);
  189. _sfStats.IncrementCounter( CStatForm::SCI_TEXTUREUPLOADBYTES, pixOffset*4);
  190. _pfGfxProfile.StopTimer( CGfxProfile::PTI_TEXTUREUPLOADING);
  191. _sfStats.StopTimer( CStatForm::STI_BINDTEXTURE);
  192. }
  193. // returns bytes/pixels ratio for texture format
  194. extern INDEX GetFormatPixRatio_D3D( D3DFORMAT d3dFormat)
  195. {
  196. switch( d3dFormat) {
  197. case D3DFMT_A8R8G8B8:
  198. case D3DFMT_X8R8G8B8:
  199. return 4;
  200. case D3DFMT_R8G8B8:
  201. return 3;
  202. case D3DFMT_R5G6B5:
  203. case D3DFMT_X1R5G5B5:
  204. case D3DFMT_A1R5G5B5:
  205. case D3DFMT_A4R4G4B4:
  206. case D3DFMT_X4R4G4B4:
  207. case D3DFMT_A8L8:
  208. return 2;
  209. // compressed formats and single-channel formats
  210. default:
  211. return 1;
  212. }
  213. }
  214. // returns bytes/pixels ratio for uploaded texture
  215. extern INDEX GetTexturePixRatio_D3D( LPDIRECT3DTEXTURE8 pd3dTexture)
  216. {
  217. D3DSURFACE_DESC d3dSurfDesc;
  218. HRESULT hr = pd3dTexture->GetLevelDesc( 0, &d3dSurfDesc);
  219. D3D_CHECKERROR(hr);
  220. return GetFormatPixRatio_D3D( d3dSurfDesc.Format);
  221. }
  222. // return allowed dithering method
  223. extern INDEX AdjustDitheringType_D3D( D3DFORMAT eFormat, INDEX iDitheringType)
  224. {
  225. switch( eFormat) {
  226. // these formats don't need dithering
  227. case D3DFMT_A8R8G8B8:
  228. case D3DFMT_X8R8G8B8:
  229. case D3DFMT_L8:
  230. case D3DFMT_A8L8:
  231. return NONE;
  232. // these formats need reduced dithering
  233. case D3DFMT_R5G6B5:
  234. case D3DFMT_X1R5G5B5:
  235. case D3DFMT_A1R5G5B5:
  236. if( iDitheringType>7) return iDitheringType-3;
  237. // other formats need dithering as it is
  238. default:
  239. return iDitheringType;
  240. }
  241. }
  242. #endif // SE1_D3D