Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

820 lines
27 KiB

  1. dnl-----------------------------------------------------------------------------
  2. dnl
  3. dnl This file contains the macro for generating texture addressing routines.
  4. dnl
  5. dnl-----------------------------------------------------------------------------
  6. dnl
  7. dnl
  8. dnl
  9. dnl d_TexAddr
  10. dnl
  11. dnl Generates all the differentiated texture address routines.
  12. dnl
  13. dnl It takes 5 parameters.
  14. dnl
  15. dnl $1 is one of 0 or 1. 0 is single texture, and 1 is the first multi-texture
  16. dnl $2 is one of TexAddrWrapMirror TexAddrAll
  17. dnl $3 is one of NoPersp Persp
  18. dnl $4 is one of Point Bilinear MaybeBilinear
  19. dnl $5 is one of NoMip
  20. dnl
  21. dnl Note that even when we are not mip mapping, we use iLOD to get to the nearest mip map
  22. dnl (so iLOD must be 0 if the texture has no mip levels)
  23. dnl
  24. dnl two different jump counts.
  25. define(`d_WDIVcnt', 0)dnl
  26. define(`d_MaybeBilinearcnt', 0)dnl
  27. define(`d_MaxCLODcnt', 0)dnl
  28. dnl
  29. dnl Variables needed for texturing
  30. dnl
  31. dnl
  32. define(`texaddraVars', `
  33. EXTERN IncHighandLow16:MMWORD
  34. EXTERN UFracVFracMask:MMWORD
  35. EXTERN UV32to15Mask:MMWORD
  36. EXTERN Makelow16one:MMWORD
  37. EXTERN MaskKeepUValues:MMWORD
  38. EXTERN MaskKeepVValues:MMWORD
  39. EXTERN UFrac:MMWORD
  40. EXTERN VFrac:MMWORD
  41. EXTERN Zero:MMWORD
  42. EXTERN memD3DTFG_POINT:MMWORD
  43. EXTERN GiveUp:MMWORD
  44. EXTERN LastW:MMWORD
  45. EXTERN Val0x000a000a:MMWORD
  46. EXTERN Val0xffff:MMWORD
  47. EXTERN Val0x0000002000000020:MMWORD
  48. EXTERN Val0x0000ffff0000ffff:MMWORD
  49. ')
  50. dnl
  51. dnl d_UpdateUoWAndVoW
  52. dnl increments UoW and VoW for either texture 1 or 2 and can be used
  53. dnl in several different files.
  54. dnl
  55. define(`d_UpdateUoWandVoW', `
  56. ;pS->iUoW`'d_TexNum += pP->iDUoW`'$1`'DX;
  57. ;pS->iVoW`'d_TexNum += pP->iDVoW`'$1`'DX;
  58. movq mm5, XpS(iUoW`'$1`')
  59. paddd mm5, XpP(iDUoW`'$1`'DX)
  60. movq XpS(iUoW`'$1`'), mm5
  61. ')
  62. define(`d_UpdateLOD', `
  63. ; Seems like this should be done with something else
  64. ; i.e. group 16 bit adds together.
  65. ;pS->iLOD += pS->iDLOD;
  66. xor eax, eax
  67. mov ax, XpS(iLOD)
  68. add ax, XpS(iDLOD)
  69. mov XpS(iLOD), ax
  70. ')
  71. define(`d_UpdateOoW', `
  72. ;pS->iOoW += pP->iDOoWDX;
  73. mov eax, XpS(iOoW)
  74. add eax, XpP(iDOoWDX)
  75. mov XpS(iOoW), eax
  76. ')
  77. dnl d_UoWVowTimesW is so that I have same code in several different locations.
  78. dnl These four locations are texaddr1.mas, tstfail.mas, Setup Code (Monolithic and regular)
  79. dnl
  80. dnl mm5 is UoW and VoW for either texture 1 or texture two
  81. dnl esi is W
  82. dnl $1 is 1 or 2 depending on result is for texture one or texture 2
  83. dnl
  84. dnl
  85. dnl Does integer W * U or V computation
  86. dnl define(`d_WTimesUVoW', `imul32h_s20(($1), ($2))')dnl
  87. dnl
  88. dnl iW = 1.15.16 << 4 = 1.11.20
  89. dnl UoW = 1.11.20 << 8 = 1.2.28
  90. dnl
  91. dnl 1.11.20 * 1.3.28 == 1.15.48 >> 32 == 1.15.16
  92. dnl inline INT32 imul32h_s20(INT32 x, INT32 y)
  93. dnl {
  94. dnl #ifdef _X86_
  95. dnl _asm
  96. dnl {
  97. dnl mov eax, x
  98. dnl mov edx, y
  99. dnl imul edx
  100. dnl shr eax, 20
  101. dnl shl edx, 12
  102. dnl and eax, 000000fffh
  103. dnl and edx, 0fffff000h
  104. dnl or eax, edx
  105. dnl }
  106. dnl #else
  107. dnl return (INT32)(((LONGLONG)x * y) >> 20);
  108. dnl #endif
  109. dnl }
  110. define(`d_UoWVoWTimesW', `
  111. ;pCtx->SI.iU`'d_TexNum = d_WTimesUVoW(pS->iW,pS->iUoW`'$1`');
  112. ;pCtx->SI.iV`'d_TexNum = d_WTimesUVoW(pS->iW,pS->iVoW`'$1`');
  113. movd eax, mm5
  114. psrlq mm5, 32
  115. imul esi
  116. shrd eax, edx, 20
  117. mov XpCtxSI(iU`'$1`'), eax
  118. movd eax, mm5
  119. imul esi
  120. shrd eax, edx, 20
  121. mov XpCtxSI(iV`'$1`'), eax
  122. ')
  123. define(`d_UpdateNonPersp', `
  124. ;pCtx->SI.iU`'$1`' = pS->iUoW`'$1`'>>TEX_TO_FINAL_SHIFT; // 1.11.20 >> 4 == 1.15.16
  125. ;pCtx->SI.iV`'$1`' = pS->iVoW`'$1`'>>TEX_TO_FINAL_SHIFT;
  126. ; mm5 still contains iUoW and iVoW which are the iU and iV values for
  127. ; non perspective correct.
  128. psrad mm5, TEX_TO_FINAL_SHIFT
  129. movq XpCtxSI(iU`'$1`'), mm5
  130. ')
  131. dnl d_WDivide
  132. dnl
  133. dnl Does incremental W divide calculation
  134. dnl
  135. define(`d_WDivide', `
  136. dnl Increment counter for jump address calc stuff.
  137. define(`d_WDIVcnt', eval(d_WDIVcnt+1))dnl
  138. dnl This was deemed too annoying
  139. dnl #if DBG
  140. dnl if (iOoW <= 0)
  141. dnl {
  142. dnl D3D_WARN(0, "WDivide, iOoW (%d) out of Range!", iOoW);
  143. dnl DDASSERT(0);
  144. dnl }
  145. dnl #endif
  146. dnl Note: iOoW comes in as eax. So it is ready for first multiply
  147. dnl iOoW is actual iOoW value in 1.31 form instead of 1.15 form. good.
  148. dnl In SpecialW case I have to reload it at the end.
  149. ;INT32 iWn0 = pS->iW + pCtx->SI.iDW; // 1.15.16
  150. ; TODO Could do this and OoW Add at same time with MMX.
  151. mov edx, XpS(iW)
  152. mov LastW, edx ; Save iW to calc iDW for next time.
  153. add edx, XpCtxSI(iDW)
  154. ;if (pCtx->SI.iSpecialW < 0)
  155. ;{
  156. xor edi, edi
  157. cmp di, word ptr XpCtxSI(iSpecialW)
  158. jle DontDoSpecialW`'d_WDIVcnt`'
  159. ;DoSpecialW`'d_WDIVcnt`':
  160. ; This label is a left over from when
  161. ;if (iWn0 < 0)
  162. ;{
  163. cmp edx, edi
  164. jl WOutOfRange`'d_WDIVcnt`'
  165. ;iWn0 = pS->iW >> 1; // use iW/2 as a guess, instead
  166. mov edx, LastW
  167. sar edx, 1
  168. ;}
  169. WOutOfRange`'d_WDIVcnt`':
  170. ;VAL32 iWn1;
  171. ;INT16 iWnOld = iWn0 + 0x100; // make sure while fails first time
  172. ; Dont need to make sure it fails. I do a post test which guarentees it will execute once.
  173. ;INT32 iGiveUp = 7;
  174. mov GiveUp, 8 ; Pre decrementing instead of post decrementing.
  175. ;while((abs(iWnOld - iWn0) > 0x20) && (iGiveUp-- > 0))
  176. ;{
  177. SpecW`'d_WDIVcnt`'Loop1:
  178. ; Could move this to bottom of loop and combine results somehow.
  179. ; TBD look at it more.
  180. dec GiveUp
  181. jz ExitSpecWLoop`'d_WDIVcnt`'
  182. ; Shift iOoW by one since imul cannot have sign bit set
  183. ; OoW cannot reach one, only 0x7fffffff
  184. ;shr eax, 1 ; 1.31 >> 1 = 1.30
  185. ; Get ready to do Two minus iOoW*iW
  186. mov esi, (1 SHL 16)
  187. ;iWnOld = iWn0;
  188. mov edi, edx
  189. ; Result should be close to one so we want most of the
  190. ; precision in the low bits. Need to give more bits
  191. ; leaway since these are the bad cases.
  192. ; iWn1 = imul32h(pS->iOoW, iWn0); // 1.31*1.15.16 = 1.16.47 >> 32 = 1.16.15
  193. imul edx
  194. ;iWn1 = (1L<<16) - iWn1; // 2.0 - iWn1
  195. sub esi, edx
  196. ;while(iWn1.i < 0)
  197. ;{
  198. SpecW`'d_WDIVcnt`'Loop2:
  199. test esi, esi
  200. jns SpecW`'d_WDIVcnt`'ExitLoop2 ; This jump should be predicted correctly most of the time.
  201. ;iWn1=(iWn1+(1L<<15))>>1; // iWn1 = (iWn1 + 1.0)/2
  202. add esi, (1 SHL 15)
  203. sar esi, 1
  204. jmp SpecW`'d_WDIVcnt`'Loop2
  205. ;}
  206. SpecW`'d_WDIVcnt`'ExitLoop2:
  207. ;iWn1 <<= 15; // 1.16.15 << 15 = 1.1.30
  208. mov eax, edi
  209. shl eax, 5 ; 1.15.16 << 5 = 1.10.21 TBD Can I shift off upper bits??
  210. shl esi, 12 ; 4.15 << 12 = 4.27 ;
  211. ;iWn0 = imul32h(iWn1, iWn0)<<2; // 1.1.30 * 1.15.16 = 1.17.46 >> 32 = 1.17.14 << 2 = 1.15.16
  212. ; Actually 4.27 * 1.10.21 = 1.14.48 >> 32 = 1.14.16. No need for post shift.
  213. mul esi
  214. ; Have to do (abs(iWnOld - iWn0) > 0x20) code here.
  215. sub edi, edx
  216. ; These four lines are abs code.
  217. mov eax, edi
  218. sar eax, 31
  219. xor edi, eax
  220. sub edi, eax
  221. cmp edi, 020h ;Assuming that loop will only happen once.
  222. jbe ExitSpecWLoop`'d_WDIVcnt`'
  223. ; Reload eax with iOoW.
  224. mov eax, XpS(iOoW)
  225. jmp SpecW`'d_WDIVcnt`'Loop1
  226. ;}
  227. ;else
  228. ;{
  229. DontDoSpecialW`'d_WDIVcnt`':
  230. ; Everything should be positive in Non-SpecialW case.
  231. ;INT32 iWn1;
  232. mov esi, (1 SHL 16)
  233. mov edi, edx
  234. ; This should be close to one so Low bits are most important.
  235. ;iWn1 = (iOoW*iWn0)>>15; // 1.31*0.15.16 == 0.16.47 >> 32 = 0.16.15
  236. mul edx
  237. ;iWn1 = (1L<<16) - iWn1; // 2.0 - iWn1
  238. sub esi, edx
  239. ;iWn1 <<= 15; // 1.16.15 << 15 = 1.1.30
  240. shl esi, 15 ; 0.16.15 << 15 = 0.2.30
  241. mov eax, esi
  242. ;iWn0 = imul32h(iWn1, iWn0)<<2; // 1.1.30 * 1.15.16 = 1.17.46 >> 32 = 1.17.14 << 2 = 1.15.16
  243. mul edi ; 0.2.30 * 1.15.16 = 1.17.46 >> 32 = 1.17.14
  244. shl edx, 2 ; 1.17.14 << 2 = 1.15.16
  245. ;}
  246. ;}
  247. ExitSpecWLoop`'d_WDIVcnt`':
  248. ;pCtx->SI.iDW = iWn0 - (UINT16)pS->iW;
  249. ;pS->iW = iWn0;
  250. mov XpS(iW), edx
  251. mov esi, edx ; Save W for multiplying by UoW and VoW
  252. sub edx, LastW
  253. mov XpCtxSI(iDW), edx
  254. ;pCtx->SI.iSpecialW += 1; // this is supposed to wrap past 0x7fff sometimes
  255. inc word ptr XpCtxSI(iSpecialW)
  256. ')
  257. dnl
  258. define(`d_TexAddr', `
  259. define(`d_TexNum', eval($1+1))dnl
  260. ;---------------------------------------------------------------------------
  261. ;void Tex`'d_TexNum`'Addr_$2_$3_$4_$5(PD3DI_RASTCTX pCtx, PD3DI_RASTPRIM pP,
  262. ; PD3DI_RASTSPAN pS)
  263. ;{
  264. PUBLIC _MMX_Tex`'d_TexNum`'Addr_$2_$3_$4_$5
  265. _MMX_Tex`'d_TexNum`'Addr_$2_$3_$4_$5:
  266. ;PD3DI_SPANTEX pTex = &pCtx->pTexture[$1];
  267. mov esi, XpCtx(pTexture + $1*SIZEOF_PSPANTEX)
  268. ifelse(`$4', `MaybeBilinear', `
  269. ; In maybe bilinear just jump to point or bi-linear depending on iLOD.
  270. define(`d_MaybeBilinearcnt', eval(d_MaybeBilinearcnt+1))dnl
  271. ;if ((((UINT16)pS->iLOD) >> 15) ^ (INT16)(pTex->uMagFilter == D3DTFG_POINT))
  272. ;{
  273. ; TODO check to see if MMX really needed here.
  274. movd mm1, XpTex(uMagFilter)
  275. pcmpeqd mm1, mmword ptr memD3DTFG_POINT
  276. movsx edx, word ptr XpS(iLOD)
  277. movd eax, mm1
  278. sar edx, 15 ; Generates mask based on sign.
  279. xor edx, eax
  280. jz DoPoint`'d_MaybeBilinearcnt
  281. ;// if magnify matches Mag filter, bilinear, else point
  282. ;C_Tex`'d_TexNum`'Addr_$2_$3_Bilinear_$5(pCtx, pP, pS);
  283. jmp _MMX_Tex`'d_TexNum`'Addr_$2_$3_Bilinear_$5
  284. DoPoint`'d_MaybeBilinearcnt`':
  285. jmp _MMX_Tex`'d_TexNum`'Addr_$2_$3_Point_$5
  286. ', `
  287. ifelse(`$5', `LOD', `
  288. ;INT16 iLOD0 = min(max(pS->iLOD >> 11, 0), pTex->cLOD);
  289. movsx eax, word ptr XpS(iLOD)
  290. sar eax, 11
  291. mov edx, eax
  292. sar edx, 31
  293. xor edx, 0ffffffffh
  294. and eax, edx
  295. define(`d_MaxCLODcnt', eval(d_MaxCLODcnt+1))dnl
  296. cmp eax, XpTex(cLOD)
  297. jb NotMax`'d_MaxCLODcnt`'
  298. mov eax, XpTex(cLOD)
  299. NotMax`'d_MaxCLODcnt`':
  300. movd mm3, eax
  301. ')
  302. ; ----------------------------------------
  303. ; Doing UV calculation a little more accurate
  304. ; Exactly like C code.
  305. ; I shift iU and iV to the right not by (TEX_FINAL_SHIFT - iShiftU0) but by
  306. ; (TEX_FINAL_SHIFT - iShiftU0 - 6). iShiftU0 = pTex->iShiftU - iLOD0
  307. ; (TEX_FINAL_SHIFT - (pTex->iShiftU - iLOD0))
  308. ; (TEX_FINAL_SHIFT + iLOD0 - pTex->iShiftU)
  309. ; COMMENT1**
  310. ; If textures have a max of 1024 then shiftU0 would be at most 10 which would
  311. ; make (TEXT_FINAL_SHIFT - iShiftU - 6) at most zero. This is why I choose 6
  312. ; It will also give bi-linear 6 bits of precision I think it was said that
  313. ; only five was needed.
  314. ;INT16 iShiftU0 = pTex->iShiftU - iLOD0;
  315. ;INT16 iShiftV0 = pTex->iShiftV - iLOD0;
  316. movq mm5, MMWORD PTR Val0x000a000a ; This is TEX_FINAL_SHIFT - 6 = 10.
  317. ifelse(`$5', `NoLOD', `
  318. ;iLOD0 is zero so no subtraction needed and LOD doesnt need to be subtracted from U and V.
  319. ', `
  320. punpcklwd mm3, mm3 ; Make two copys of iLOD to subtract U and V
  321. ')dnl
  322. movd mm4, XpTex(iShiftU)
  323. ifelse(`$5', `LOD', `
  324. psubw mm4, mm3
  325. ')dnl
  326. psubw mm5, mm4
  327. movq mm4, mm5
  328. pand mm5, MMWORD PTR Val0xffff
  329. ifelse(`$5', `LOD', `
  330. pand mm3, MMWORD PTR Val0xffff ; Make iLOD back to only one copy
  331. ')
  332. psrld mm4, 16
  333. movd mm1, XpCtxSI(iU`'d_TexNum)
  334. psrad mm1, mm5
  335. movd mm2, XpCtxSI(iV`'d_TexNum)
  336. psrad mm2, mm4
  337. punpckldq mm1, mm2
  338. ifelse(`$4', `Bilinear', `
  339. psubd mm1, MMWORD PTR Val0x0000002000000020
  340. ')
  341. ; Texture Pitch cannot be calculated so it must be looked up in the iShiftPitch table
  342. ; ----------------- Start of hack
  343. ; ATTENTION This is really hacked right now. Just to get it working
  344. ; Pitch would be better for me, instead of shift pitch.
  345. ; With actual pitch, this would be two moves and a shift.
  346. ;shl eax, 1
  347. ifelse(`$5', `LOD', `
  348. movzx edx, word ptr XpTex(iShiftPitch+eax*2)
  349. ', `
  350. movzx edx, word ptr XpTex(iShiftPitch)
  351. ')dnl
  352. add edx, 16
  353. movd mm2, edx
  354. movq mm5, MMWORD ptr Makelow16one
  355. pslld mm5, mm2
  356. ;pslld mm5, 16 ;. Use this after hack.
  357. ; not needed in hacked version since i add to shifted value.
  358. ; ----------------- End of hack
  359. por mm5, MMWORD ptr Makelow16one
  360. ; Make the low 16 bits of dword one
  361. ; This helps in calculating texture address.
  362. ; Gets U and V value into mm1 so that it can be mirrored, wrapped or
  363. ; clamped. This can be done for two values in the point case
  364. ; or four values in the bilinear case.
  365. ifelse(`$4', `Point', `
  366. ;iU00 >>= 6;
  367. ;iV00 >>= 6;
  368. psrad mm1, 6
  369. packssdw mm1, mm1 ; Value needs to be packed since all wrap/mirror
  370. ; operations assume UV in low 32 bits.
  371. ', `
  372. ;INT32 iUFrac = iU00 & 0x03f;
  373. ;INT32 iVFrac = iV00 & 0x03f;
  374. ;iU00 >>= 6;
  375. ;iV00 >>= 6;
  376. movq mm2, mm1
  377. psrad mm1, 6
  378. ;pand mm1, MMWORD PTR Val0x0000ffff0000ffff
  379. pand mm2, dword ptr UFracVFracMask ; UFracVFracMask = 0x0000003f0000003f
  380. ; Going to use only 8 bits for bi-linear so that I can do a pmullw.
  381. ; Currently at 6 bits so shift up by 2.
  382. psllw mm2, 2
  383. movq mm0, mm2
  384. ; Replicate VFrac value for bilinear
  385. punpckhwd mm2, mm2
  386. punpcklwd mm2, mm2
  387. ; Replicate UFrac Value for bilinear
  388. punpcklwd mm0, mm0
  389. punpcklwd mm0, mm0
  390. movq dword ptr VFrac, mm2
  391. movq dword ptr UFrac, mm0
  392. ;INT32 iU01 = iU00 + 1;
  393. ;INT32 iV01 = iV00 + 1;
  394. packssdw mm1, mm1 ; replicate U and V value to upper 16 bit locations
  395. paddw mm1, dword ptr IncHighandLow16
  396. ; This will make texture values be (High word to low word):
  397. ; iV01, iU00, iV00, iU01
  398. ; Need to do this to make texture look up for bilinear easier.
  399. ; I have to combine to get all combinations anyway. It just
  400. ; happens to be better for me to have iV00, iU01 pair first.
  401. ')
  402. ;UINT16 uMaskU0 = pTex->uMaskU >> iLOD0; UINT16 uMaskV0 = pTex->uMaskV >> iLOD0;
  403. ; put mask in mm3 and replicate to match location for wrap/mirror/clamp
  404. movd mm0, XpTex(uMaskU) ; Load U and V mask
  405. ifelse(`$4', `Bilinear', `
  406. ; replicate mask if doing bilinear
  407. punpckldq mm0, mm0
  408. ')
  409. ifelse(`$5', `NoLOD', `
  410. ; iLOD0 is zero so no shift needed.
  411. ' , `
  412. ; iLOD0 shift value left over from above. TBD. Put this in in mip case
  413. ; Could do this one before or after the unpack also.
  414. psrlw mm0, mm3
  415. ')
  416. ifelse(`$2', `TexAddrWrapMirror', `
  417. ;INT16 iFlip;
  418. ; MM1 should contain 16 bit iU and iV for both texture locations
  419. ; End Result is MM1 value wrapped or mirrored
  420. ; in Bilinear Case, four values can be done
  421. ; iU00, iV00, iU01, iV01
  422. ; This code really does alot for the bilinear case and is kinda wasteful
  423. ; in the normal mode.
  424. ;iFlip1 = iU00 & pTex->iFlipMaskU; ;iFlip2 = iV00 & pTex->iFlipMaskV; ;iFlip3 = iU01 & pTex->iFlipMaskU; ;iFlip4 = iV01 & pTex->iFlipMaskV;
  425. movq mm7, mm1
  426. ; Point doesnt need replication
  427. movd mm4, XpTex(iFlipMaskU)
  428. ; if bilinear replicate values together, Point doesnt need this.
  429. ifelse(`$4', `Bilinear', `
  430. punpckldq mm4, mm4
  431. ')
  432. ifelse(`$5', `NoLOD', `
  433. ; iLOD0 is zero so no shift needed.
  434. ' , `
  435. psrlw mm4, mm3 ; Shifts mirror mask to correct bit location
  436. ')
  437. pand mm7, mm4
  438. ;iFlip1 = MMX_cmpeqw(iFlip1, 0); ;iFlip2 = MMX_cmpeqw(iFlip2, 0); ;iFlip3 = MMX_cmpeqw(iFlip3, 0); ;iFlip4 = MMX_cmpeqw(iFlip4, 0);
  439. pcmpeqw mm7, MMWORD PTR Zero
  440. ;iFlip1 = uMaskU0 & ~ iFlip1; ;iFlip2 = uMaskV0 & ~ iFlip2; ;iFlip3 = uMaskU0 & ~ iFlip3; ;iFlip4 = uMaskV0 & ~ iFlip4;
  441. pandn mm7, mm0
  442. ;iU00 &= uMaskU0; ;iV00 &= uMaskV0; ;iU01 &= uMaskU0; ;iV01 &= uMaskV0;
  443. pand mm1, mm0
  444. ;iU00 ^= iFlip1; ;iV00 ^= iFlip2; ;iU01 ^= iFlip3; ;iV01 ^= iFlip4;
  445. pxor mm1, mm7
  446. ; Result in mm4 now since TexAddrAll ends up that way.
  447. ; Still need to look at register useage more.
  448. movq mm4, mm1
  449. ') dnl
  450. ifelse(`$2', `TexAddrAll', `
  451. ;INT16 iFlip, iClamp1, iClamp2, iClampMinT, iClampMaxT;
  452. ;INT16 iUoWAdj = (INT16)(pS->iUoW`'d_TexNum >> 12); // adjust to match W
  453. ;INT16 iVoWAdj = (INT16)(pS->iVoW`'d_TexNum >> 12);
  454. ;movq mm6, XpS(iUoW`'d_TexNum)
  455. ;movq mm6, MMWORD PTR Zero
  456. pxor mm6, mm6
  457. ; TBD Data in SPANTEX needs to be rearange to make life simpler.
  458. ; I have rearranged some of it, but there still needs to be some
  459. ; fixes to it.
  460. ;iFlip1 = iU00 & pTex->iFlipMaskU; ;iFlip2 = iV00 & pTex->iFlipMaskV; ;iFlip3 = iU01 & pTex->iFlipMaskU; ;iFlip4 = iV01 & pTex->iFlipMaskV;
  461. movq mm7, mm1
  462. movd mm4, XpTex(iFlipMaskU) ; This should copy U and V mask at the same time.
  463. ifelse(`$4', `Bilinear', `
  464. dnl Only replicate if U and V if doing bilinear
  465. punpckldq mm4, mm4 ; copy UV
  466. ')
  467. ifelse(`$5', `NoLOD', `
  468. ; iLOD0 is zero so no shift needed.
  469. ' , `
  470. psrlw mm4, mm3 ; Shifts mirror mask to correct bit location
  471. ')
  472. pand mm7, mm4
  473. ;iFlip1 = MMX_cmpeqw(iFlip1, 0); ;iFlip2 = MMX_cmpeqw(iFlip2, 0); ;iFlip3 = MMX_cmpeqw(iFlip3, 0); ;iFlip4 = MMX_cmpeqw(iFlip4, 0);
  474. pcmpeqw mm7, MMWORD PTR Zero
  475. ;iFlip1 = uMaskU0 &~ iFlip1; ;iFlip2 = uMaskV0 &~ iFlip2; ;iFlip3 = uMaskU0 &~ iFlip3; ;iFlip4 = uMaskV0 &~ iFlip4;
  476. pandn mm7, mm0
  477. ;iU00 &= uMaskU0; ;iV00 &= uMaskV0; ;iU01 &= uMaskU0; ;iV01 &= uMaskV0;
  478. pand mm1, mm0
  479. ;iU00 ^= iFlip1; ;iV00 ^= iFlip2; ;iU01 ^= iFlip3; ;iV01 ^= iFlip4;
  480. pxor mm1, mm7
  481. ;iClamp11 = MMX_cmpgtw(0, iUoWAdj); ;iClamp12 = MMX_cmpgtw(0, iVoWAdj);
  482. pcmpgtd mm6, XpS(iUoW`'d_TexNum)
  483. packssdw mm6, mm6
  484. ;iClamp21 = MMX_cmpgtw(iOoWAdj, iUoWAdj); ;iClamp22 = MMX_cmpgtw(iOoWAdj, iVoWAdj);
  485. movd mm7, XpS(iOoW)
  486. punpckldq mm7, mm7 ; Make a copy of OoW to compare both UoW and VoW.
  487. psrld mm7, 11 ; Make OoWs Precision Match UoWs.
  488. pcmpgtd mm7, XpS(iUoW`'d_TexNum)
  489. packssdw mm7, mm7
  490. ;iClampMinT1 = pTex->iClampMinU & iClamp11; ;iClampMinT2 = pTex->iClampMinV & iClamp12; ;iClampMinT3 = pTex->iClampMinU & iClamp13; ;iClampMinT4 = pTex->iClampMinV & iClamp14;
  491. movd mm0, XpTex(iClampMinU)
  492. ifelse(`$4', `Bilinear', `
  493. punpckldq mm0, mm0
  494. ')
  495. pand mm0, mm6
  496. ; Save clamp2 because pandn will destory value.
  497. movq mm4, mm7
  498. ;iClampMaxT1 = pTex->iClampMaxU &~ iClamp21; ;iClampMaxT2 = pTex->iClampMaxV &~ iClamp22; ;iClampMaxT3 = pTex->iClampMaxU &~ iClamp23; ;iClampMaxT4 = pTex->iClampMaxV &~ iClamp24;
  499. movd mm2, XpTex(iClampMaxU)
  500. ifelse(`$4', `Bilinear', `
  501. punpckldq mm2, mm2
  502. ')
  503. ifelse(`$5', `NoLOD', `
  504. ; iLOD0 is zero so no shift needed.
  505. ' , `
  506. psraw mm2, mm3 ; Shifts clamp max to correct bit location
  507. ')
  508. pandn mm7, mm2 ; Since iClamp2 is already negated, I can just do an AND.
  509. ;iClamp21 &= ~iClamp11; ;iClamp22 &= ~iClamp12; ;iClamp23 &= ~iClamp13; ;iClamp24 &= ~iClamp14;
  510. pandn mm6, mm4
  511. ;iClamp21 = pTex->iClampEnU &~ iClamp21; ;iClamp22 = pTex->iClampEnU &~ iClamp22; ;iClamp23 = pTex->iClampEnU &~ iClamp23; ;iClamp24 = pTex->iClampEnU &~ iClamp24;
  512. movd mm2, XpTex(iClampEnU)
  513. ifelse(`$4', `Bilinear', `
  514. punpckldq mm2, mm2
  515. ')
  516. pandn mm6, mm2
  517. ;iU00 &= ~iClamp21; ;iV00 &= ~iClamp22; ;iU01 &= ~iClamp23; ;iV01 &= ~iClamp24;
  518. pandn mm6, mm1
  519. ;iU00 |= iClampMinT1; ;iV00 |= iClampMinT2; ;iU01 |= iClampMinT3; ;iV01 |= iClampMinT4;
  520. por mm6, mm0
  521. ;iU00 |= iClampMaxT1; ;iV00 |= iClampMaxT2; ;iU01 |= iClampMaxT3; ;iV01 |= iClampMaxT4;
  522. por mm6, mm7
  523. movq mm4, mm6
  524. ') dnl
  525. ; Making other two cases for texture addressing has to be simplier than
  526. ; this and not use so many registers. Puts U1 V0 U0 V1 into mm3.
  527. ; TBD Make this better.
  528. ; values are still stored as iV01, iU00, iV00, iU01
  529. ifelse(`$4', `Bilinear', `
  530. movq mm2, mm4
  531. movq mm3, mm4
  532. ') dnl Bilinear
  533. dnl ifelse(`$2', `TexAddrAll', `
  534. movq mm0, mm4
  535. dnl ') dnl border code
  536. pmaddwd mm4, mm5 ; Throw in first address calculation.
  537. ; Just to get it started. Calculate
  538. ; iU0+iV1*iShiftU0 and iU1+iV0*iShiftU0
  539. ifelse(`$4', `Bilinear', `
  540. ; values are being changed to iV01, iU01, iV00, iU00
  541. ; seven instructions for this seems excessive.
  542. pand mm2, MMWORD ptr MaskKeepUValues
  543. pand mm3, MMWORD ptr MaskKeepVValues
  544. movq mm1, mm2
  545. psllq mm2, 32
  546. psrlq mm1, 32
  547. por mm3, mm2
  548. por mm3, mm1
  549. ') dnl Bilinear
  550. ; From here until mov edi is code that is needed for border.
  551. ; all sign bits are stored in bytes so that border code can tell if uv went below zero.
  552. dnl ifelse(`$2', `TexAddrAll', `
  553. ifelse(`$4', `Point', `
  554. ; Point needs to be in same format as bilinear for border
  555. packsswb mm0, mm0
  556. ') dnl point
  557. ifelse(`$4', `Bilinear', `
  558. ; mm0 = iV01, iU00, iV00, iU01
  559. ; mm3 = iV01, iU01, iV00, iU00
  560. ; Need to rearrange values to be like so v1 u0 v1 u1 v0 u0 v0 u1 in bytes
  561. ; This is really bad. Just doing whatever to get it to work.
  562. movq mm1, mm0
  563. punpckldq mm1, mm3 ; This will make mm1 = v0 u0 v0 u1
  564. movq mm2, mm3
  565. punpckhdq mm2, mm0 ; This will make mm0 = v1 u0 v1 u1
  566. packsswb mm1, mm2
  567. movq mm0, mm1
  568. ') dnl Bilinear
  569. dnl ') dnl TexAddrAll
  570. ifelse(`$4', `Bilinear', `
  571. pmaddwd mm3, mm5 ; Calculates iU1+iV0*iShiftU0 and iU0+iV1*iShiftU0
  572. ') dnl Bilinear
  573. dnl ; Load pTex->pBits[iLOD0] into esi. It will be needed.
  574. dnl ; Convient that eax is still around as iLOD0. TBD make sure eax positive.
  575. ifelse(`$5', `NoLOD', `
  576. mov edi, XpTex(pBits)
  577. ',`
  578. mov edi, XpTex(pBits+eax*4)
  579. ')dnl
  580. ; was esi. Cant change to esi because it is the pointer to pTex
  581. ; which is used by Border and ColorKey. Use edi for now and
  582. ; call routines through memory. Figure out if this is bad.
  583. ; load the read texture routine address into a register early
  584. ;mov edi, XpCtx(pfnTexRead + $1*SIZEOF_PFNTEXREAD)
  585. ifelse(`$4', `Bilinear', `
  586. ; iV0 iU1 address should be done by now.
  587. movd eax, mm4
  588. ;UINT32 uTex00 = pCtx->pfnTexRead[$1](iU00, iV00, pTex->iShiftU,
  589. ; pTex->pBits[iLOD0], &pCtx->Texture[$1]);
  590. ; Combine U and V values before making call.
  591. ;call edi
  592. call dword ptr XpCtx(pfnTexRead + $1*SIZEOF_PFNTEXREAD)
  593. movd eax, mm3
  594. movq mm7, mm1 ; Put TColor[iU0, uV0] in mm7
  595. ;UINT32 uTex10 = pCtx->pfnTexRead[$1](iU01, iV00, pTex->iShiftU,
  596. ; pTex->pBits[iLOD0], &pCtx->Texture[$1]);
  597. ;call edi
  598. call dword ptr XpCtx(pfnTexRead + $1*SIZEOF_PFNTEXREAD)
  599. psrlq mm3, 32
  600. psubw mm7, mm1
  601. psllw mm1, 8
  602. pmullw mm7, dword ptr UFrac
  603. paddw mm7, mm1 ; Should I copy mm1 to another variable and do shift/add later?
  604. movd eax, mm3
  605. ;UINT32 uTex01 = pCtx->pfnTexRead[$1](iU00, iV01, pTex->iShiftU,
  606. ; pTex->pBits[iLOD0], &pCtx->Texture[$1]);
  607. ;call edi
  608. call dword ptr XpCtx(pfnTexRead + $1*SIZEOF_PFNTEXREAD)
  609. psrlq mm4, 32
  610. movq mm6, mm1
  611. movd eax, mm4
  612. ;UINT32 uTex11 = pCtx->pfnTexRead[$1](iU01, iV01, pTex->iShiftU,
  613. ; pTex->pBits[iLOD0], &pCtx->Texture[$1]);
  614. ;call edi
  615. call dword ptr XpCtx(pfnTexRead + $1*SIZEOF_PFNTEXREAD)
  616. ;TexFiltBilinear(&pCtx->SI.TexCol[$1], iUFrac, iVFrac, uTex00, uTex10, uTex01, uTex11);
  617. ; The amount of shifting instructions for this makes the other approach
  618. ; look pretty good.
  619. psubw mm6, mm1
  620. psllw mm1, 8
  621. pmullw mm6, dword ptr UFrac ; TBD explain this code better.
  622. movq mm4, mm7
  623. paddw mm6, mm1
  624. psrlw mm6, 8
  625. psrlw mm7, 8
  626. psubw mm6, mm7
  627. pmullw mm6, dword ptr VFrac
  628. paddw mm4, mm6
  629. psrlw mm4, 8
  630. ; TBD shouldnt have to pack and then unpack later. Should keep in a register
  631. packuswb mm4, mm4
  632. movd XpCtxSI(TexCol+$1*4), mm4
  633. ') dnl
  634. ifelse(`$4', `Point', `
  635. ; iV0 iU1 address should be done by now.
  636. movd eax, mm4
  637. ;pCtx->SI.TexCol[$1] = pCtx->pfnTexRead[$1](iU00, iV00, pTex->iShiftU,
  638. ; pTex->pBits[iLOD0], &pCtx->Texture[$1]);
  639. ;call edi
  640. call dword ptr XpCtx(pfnTexRead + $1*SIZEOF_PFNTEXREAD)
  641. ; TBD Currently have to pack and then unpack later. Should be able
  642. ; to leave the value in some register for a while. I would think.
  643. packuswb mm1, mm1
  644. movd XpCtxSI(TexCol+$1*4), mm1
  645. ') dnl
  646. dnl only do update code in non-monolithic case. Monolithic code updates are done
  647. dnl by tstfail routine.
  648. d_UpdateUoWandVoW(d_TexNum)
  649. ifelse(`$5', `LOD', `
  650. ifelse(d_TexNum, 1, `
  651. d_UpdateLOD()
  652. ')
  653. ')
  654. ifelse(`$3', `Persp', `
  655. ifelse(d_TexNum, 1, `
  656. d_UpdateOoW()
  657. ;pS->iW = 0x00800000/(pS->iOoW>>16); // 9.23/1.15 = 8.8
  658. d_WDivide()
  659. ', `
  660. ; In Texaddr1, W is calculated and result is in esi. I need to get the W value back into esi for the multiply.
  661. mov esi, XpS(iW)
  662. ')
  663. d_UoWVoWTimesW(d_TexNum)
  664. ', `
  665. d_UpdateNonPersp(d_TexNum)
  666. ')
  667. ; load the next bead address into a register early. Not early anymore
  668. ; since so much regular non-mmx code being done for WDIV
  669. mov eax, XpCtx(pfnTex`'d_TexNum`'AddrEnd)
  670. ; pCtx->pfnTex`'d_TexNum`'AddrEnd(pCtx, pP, pS);
  671. jmp eax
  672. ')')
  673. dnl
  674. dnl
  675. dnl d_TexAddrHdr
  676. dnl
  677. dnl Generates headers with the same format as d_TexAddr
  678. dnl
  679. define(`d_TexAddrHdr', `
  680. void MMX_Tex`'eval($1+1)`'Addr_$2_$3_$4_$5(PD3DI_RASTCTX pCtx, PD3DI_RASTPRIM pP,
  681. PD3DI_RASTSPAN pS);')dnl
  682. dnl