Gfx_OpenGL_Textures.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. #include <Engine/Graphics/GfxLibrary.h>
  14. #include <Engine/Base/Statistics_internal.h>
  15. #include <Engine/Math/Functions.h>
  16. #include <Engine/Graphics/Color.h>
  17. #include <Engine/Graphics/Texture.h>
  18. #include <Engine/Graphics/GfxProfile.h>
  19. #include <Engine/Base/ListIterator.inl>
  20. // asm shortcuts
  21. #define O offset
  22. #define Q qword ptr
  23. #define D dword ptr
  24. #define W word ptr
  25. #define B byte ptr
  26. // we need array for OpenGL mipmaps that are lower than N*1 or 1*N
  27. static ULONG _aulLastMipmaps[(INDEX)(1024*1.334)];
  28. static CTexParams *_tpCurrent;
  29. extern INDEX GFX_iActiveTexUnit;
  30. // unpacks texture filering from one INDEX to two GLenums (and eventually re-adjust input INDEX)
  31. static void UnpackFilter_OGL( INDEX iFilter, GLenum &eMagFilter, GLenum &eMinFilter)
  32. {
  33. switch( iFilter) {
  34. case 110: case 10: eMagFilter=GL_NEAREST; eMinFilter=GL_NEAREST; break;
  35. case 111: case 11: eMagFilter=GL_NEAREST; eMinFilter=GL_NEAREST_MIPMAP_NEAREST; break;
  36. case 112: case 12: eMagFilter=GL_NEAREST; eMinFilter=GL_NEAREST_MIPMAP_LINEAR; break;
  37. case 220: case 20: eMagFilter=GL_LINEAR; eMinFilter=GL_LINEAR; break;
  38. case 221: case 21: eMagFilter=GL_LINEAR; eMinFilter=GL_LINEAR_MIPMAP_NEAREST; break;
  39. case 222: case 22: eMagFilter=GL_LINEAR; eMinFilter=GL_LINEAR_MIPMAP_LINEAR; break;
  40. case 120: eMagFilter=GL_NEAREST; eMinFilter=GL_LINEAR; break;
  41. case 121: eMagFilter=GL_NEAREST; eMinFilter=GL_LINEAR_MIPMAP_NEAREST; break;
  42. case 122: eMagFilter=GL_NEAREST; eMinFilter=GL_LINEAR_MIPMAP_LINEAR; break;
  43. case 210: eMagFilter=GL_LINEAR; eMinFilter=GL_NEAREST; break;
  44. case 211: eMagFilter=GL_LINEAR; eMinFilter=GL_NEAREST_MIPMAP_NEAREST; break;
  45. case 212: eMagFilter=GL_LINEAR; eMinFilter=GL_NEAREST_MIPMAP_LINEAR; break;
  46. default: ASSERTALWAYS( "Illegal OpenGL texture filtering mode."); break;
  47. }
  48. }
  49. // change texture filtering mode if needed
  50. extern void MimicTexParams_OGL( CTexParams &tpLocal)
  51. {
  52. ASSERT( &tpLocal!=NULL);
  53. _pfGfxProfile.StartTimer( CGfxProfile::PTI_TEXTUREPARAMS);
  54. // set texture filtering mode if required
  55. if( tpLocal.tp_iFilter != _tpGlobal[0].tp_iFilter)
  56. { // update OpenGL texture filters
  57. GLenum eMagFilter, eMinFilter;
  58. UnpackFilter_OGL( _tpGlobal[0].tp_iFilter, eMagFilter, eMinFilter);
  59. // adjust minimize filter in case of a single mipmap
  60. if( tpLocal.tp_bSingleMipmap) {
  61. if( eMinFilter==GL_NEAREST_MIPMAP_NEAREST || eMinFilter==GL_NEAREST_MIPMAP_LINEAR) eMinFilter = GL_NEAREST;
  62. else if( eMinFilter==GL_LINEAR_MIPMAP_NEAREST || eMinFilter==GL_LINEAR_MIPMAP_LINEAR) eMinFilter = GL_LINEAR;
  63. }
  64. // update texture filter
  65. pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, eMagFilter);
  66. pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, eMinFilter);
  67. tpLocal.tp_iFilter = _tpGlobal[0].tp_iFilter;
  68. OGL_CHECKERROR;
  69. }
  70. // set texture anisotropy degree if required and supported
  71. if( tpLocal.tp_iAnisotropy != _tpGlobal[0].tp_iAnisotropy) {
  72. tpLocal.tp_iAnisotropy = _tpGlobal[0].tp_iAnisotropy;
  73. if( _pGfx->gl_iMaxTextureAnisotropy>=2) { // only if allowed
  74. pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, tpLocal.tp_iAnisotropy);
  75. }
  76. }
  77. // set texture clamping modes if changed
  78. if( tpLocal.tp_eWrapU!=_tpGlobal[GFX_iActiveTexUnit].tp_eWrapU
  79. || tpLocal.tp_eWrapV!=_tpGlobal[GFX_iActiveTexUnit].tp_eWrapV)
  80. { // prepare temp vars
  81. GLuint eWrapU = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU==GFX_REPEAT ? GL_REPEAT : GL_CLAMP;
  82. GLuint eWrapV = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV==GFX_REPEAT ? GL_REPEAT : GL_CLAMP;
  83. // eventually re-adjust clamping params in case of clamp_to_edge extension
  84. if( _pGfx->gl_ulFlags&GLF_EXT_EDGECLAMP) {
  85. if( eWrapU == GL_CLAMP) eWrapU = GL_CLAMP_TO_EDGE;
  86. if( eWrapV == GL_CLAMP) eWrapV = GL_CLAMP_TO_EDGE;
  87. }
  88. // set clamping params and update local texture clamping modes
  89. pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, eWrapU);
  90. pglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, eWrapV);
  91. tpLocal.tp_eWrapU = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU;
  92. tpLocal.tp_eWrapV = _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV;
  93. OGL_CHECKERROR;
  94. }
  95. // keep last texture params (for tex upload and stuff)
  96. _tpCurrent = &tpLocal;
  97. _pfGfxProfile.StopTimer( CGfxProfile::PTI_TEXTUREPARAMS);
  98. }
  99. // upload context for current texture to accelerator's memory
  100. // (returns format in which texture was really uploaded)
  101. extern void UploadTexture_OGL( ULONG *pulTexture, PIX pixSizeU, PIX pixSizeV,
  102. GLenum eInternalFormat, BOOL bUseSubImage)
  103. {
  104. // safeties
  105. ASSERT( pulTexture!=NULL);
  106. ASSERT( pixSizeU>0 && pixSizeV>0);
  107. _sfStats.StartTimer( CStatForm::STI_BINDTEXTURE);
  108. _pfGfxProfile.StartTimer( CGfxProfile::PTI_TEXTUREUPLOADING);
  109. // upload each original mip-map
  110. INDEX iMip=0;
  111. PIX pixOffset=0;
  112. while( pixSizeU>0 && pixSizeV>0)
  113. {
  114. // check that memory is readable
  115. ASSERT( pulTexture[pixOffset +pixSizeU*pixSizeV -1] != 0xDEADBEEF);
  116. // upload mipmap as fast as possible
  117. if( bUseSubImage) {
  118. pglTexSubImage2D( GL_TEXTURE_2D, iMip, 0, 0, pixSizeU, pixSizeV,
  119. GL_RGBA, GL_UNSIGNED_BYTE, pulTexture+pixOffset);
  120. } else {
  121. pglTexImage2D( GL_TEXTURE_2D, iMip, eInternalFormat, pixSizeU, pixSizeV, 0,
  122. GL_RGBA, GL_UNSIGNED_BYTE, pulTexture+pixOffset);
  123. } OGL_CHECKERROR;
  124. // advance to next mip-map
  125. pixOffset += pixSizeU*pixSizeV;
  126. pixSizeU >>=1;
  127. pixSizeV >>=1;
  128. iMip++;
  129. // end here if there is only one mip-map to upload
  130. if( _tpCurrent->tp_bSingleMipmap) break;
  131. }
  132. // see if we need to generate and upload additional mipmaps (those under 1*N or N*1)
  133. if( !_tpCurrent->tp_bSingleMipmap && pixSizeU!=pixSizeV)
  134. { // prepare variables
  135. PIX pixSize = Max(pixSizeU,pixSizeV);
  136. ASSERT( pixSize<=2048);
  137. ULONG *pulSrc = pulTexture+pixOffset-pixSize*2;
  138. ULONG *pulDst = _aulLastMipmaps;
  139. // loop thru mipmaps
  140. while( pixSizeU>0 || pixSizeV>0)
  141. { // make next mipmap
  142. if( pixSizeU==0) pixSizeU=1;
  143. if( pixSizeV==0) pixSizeV=1;
  144. pixSize = pixSizeU*pixSizeV;
  145. __asm {
  146. pxor mm0,mm0
  147. mov esi,D [pulSrc]
  148. mov edi,D [pulDst]
  149. mov ecx,D [pixSize]
  150. pixLoop:
  151. movd mm1,D [esi+0]
  152. movd mm2,D [esi+4]
  153. punpcklbw mm1,mm0
  154. punpcklbw mm2,mm0
  155. paddw mm1,mm2
  156. psrlw mm1,1
  157. packuswb mm1,mm0
  158. movd D [edi],mm1
  159. add esi,4*2
  160. add edi,4
  161. dec ecx
  162. jnz pixLoop
  163. emms
  164. }
  165. // upload mipmap
  166. if( bUseSubImage) {
  167. pglTexSubImage2D( GL_TEXTURE_2D, iMip, 0, 0, pixSizeU, pixSizeV,
  168. GL_RGBA, GL_UNSIGNED_BYTE, pulDst);
  169. } else {
  170. pglTexImage2D( GL_TEXTURE_2D, iMip, eInternalFormat, pixSizeU, pixSizeV, 0,
  171. GL_RGBA, GL_UNSIGNED_BYTE, pulDst);
  172. } OGL_CHECKERROR;
  173. // advance to next mip-map
  174. pulSrc = pulDst;
  175. pulDst += pixSize;
  176. pixOffset += pixSize;
  177. pixSizeU >>=1;
  178. pixSizeV >>=1;
  179. iMip++;
  180. }
  181. }
  182. // all done
  183. _pfGfxProfile.IncrementCounter( CGfxProfile::PCI_TEXTUREUPLOADS, 1);
  184. _pfGfxProfile.IncrementCounter( CGfxProfile::PCI_TEXTUREUPLOADBYTES, pixOffset*4);
  185. _sfStats.IncrementCounter( CStatForm::SCI_TEXTUREUPLOADS, 1);
  186. _sfStats.IncrementCounter( CStatForm::SCI_TEXTUREUPLOADBYTES, pixOffset*4);
  187. _pfGfxProfile.StopTimer( CGfxProfile::PTI_TEXTUREUPLOADING);
  188. _sfStats.StopTimer( CStatForm::STI_BINDTEXTURE);
  189. }
  190. // returns bytes/pixels ratio for uploaded texture
  191. extern INDEX GetFormatPixRatio_OGL( GLenum eFormat)
  192. {
  193. switch( eFormat) {
  194. case GL_RGBA:
  195. case GL_RGBA8:
  196. return 4;
  197. case GL_RGB:
  198. case GL_RGB8:
  199. return 3;
  200. case GL_RGB5:
  201. case GL_RGB5_A1:
  202. case GL_RGB4:
  203. case GL_RGBA4:
  204. case GL_LUMINANCE_ALPHA:
  205. case GL_LUMINANCE8_ALPHA8:
  206. return 2;
  207. // compressed formats and single-channel formats
  208. default:
  209. return 1;
  210. }
  211. }
  212. // returns bytes/pixels ratio for uploaded texture
  213. extern INDEX GetTexturePixRatio_OGL( GLuint uiBindNo)
  214. {
  215. GLenum eInternalFormat;
  216. pglBindTexture( GL_TEXTURE_2D, uiBindNo);
  217. pglGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&eInternalFormat);
  218. OGL_CHECKERROR;
  219. return GetFormatPixRatio_OGL( eInternalFormat);
  220. }
  221. // return allowed dithering method
  222. extern INDEX AdjustDitheringType_OGL( GLenum eFormat, INDEX iDitheringType)
  223. {
  224. switch( eFormat) {
  225. // these formats don't need dithering
  226. case GL_RGB8:
  227. case GL_RGBA8:
  228. case GL_LUMINANCE8:
  229. case GL_LUMINANCE8_ALPHA8:
  230. return NONE;
  231. // these formats need reduced dithering
  232. case GL_RGB5:
  233. case GL_RGB5_A1:
  234. if( iDitheringType>7) return iDitheringType-3;
  235. // other formats need dithering as it is
  236. default:
  237. return iDitheringType;
  238. }
  239. }