| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2009 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:29:41 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "VideoBackends/Software/TextureSampler.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-02 22:47:04 -04:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2014-02-19 12:14:09 +01:00
										 |  |  | #include <cmath>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 05:16:52 -04:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Core/HW/Memmap.h"
 | 
					
						
							| 
									
										
										
										
											2015-10-09 20:50:36 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "VideoCommon/BPMemory.h"
 | 
					
						
							| 
									
										
										
										
											2016-03-24 02:42:08 +00:00
										 |  |  | #include "VideoCommon/SamplerCommon.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "VideoCommon/TextureDecoder.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define ALLOW_MIPMAP 1
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace TextureSampler | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-02 02:20:46 -04:00
										 |  |  | static inline void WrapCoord(int* coordp, int wrapMode, int imageSize) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int coord = *coordp; | 
					
						
							|  |  |  |   switch (wrapMode) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case 0:  // clamp
 | 
					
						
							|  |  |  |     coord = (coord > imageSize) ? imageSize : (coord < 0) ? 0 : coord; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 1:  // wrap
 | 
					
						
							|  |  |  |     coord = coord % (imageSize + 1); | 
					
						
							|  |  |  |     coord = (coord < 0) ? imageSize + coord : coord; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   case 2:  // mirror
 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int sizePlus1 = imageSize + 1; | 
					
						
							|  |  |  |     int div = coord / sizePlus1; | 
					
						
							|  |  |  |     coord = coord - (div * sizePlus1); | 
					
						
							|  |  |  |     coord = (coord < 0) ? -coord : coord; | 
					
						
							|  |  |  |     coord = (div & 1) ? imageSize - coord : coord; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   *coordp = coord; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static inline void SetTexel(u8* inTexel, u32* outTexel, u32 fract) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   outTexel[0] = inTexel[0] * fract; | 
					
						
							|  |  |  |   outTexel[1] = inTexel[1] * fract; | 
					
						
							|  |  |  |   outTexel[2] = inTexel[2] * fract; | 
					
						
							|  |  |  |   outTexel[3] = inTexel[3] * fract; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static inline void AddTexel(u8* inTexel, u32* outTexel, u32 fract) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   outTexel[0] += inTexel[0] * fract; | 
					
						
							|  |  |  |   outTexel[1] += inTexel[1] * fract; | 
					
						
							|  |  |  |   outTexel[2] += inTexel[2] * fract; | 
					
						
							|  |  |  |   outTexel[3] += inTexel[3] * fract; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8* sample) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int baseMip = 0; | 
					
						
							|  |  |  |   bool mipLinear = false; | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if (ALLOW_MIPMAP)
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; | 
					
						
							|  |  |  |   TexMode0& tm0 = texUnit.texMode0[texmap & 3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   s32 lodFract = lod & 0xf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (lod > 0 && SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // use mipmap
 | 
					
						
							|  |  |  |     baseMip = lod >> 4; | 
					
						
							|  |  |  |     mipLinear = (lodFract && tm0.min_filter & TexMode0::TEXF_LINEAR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // if using nearest mip filter and lodFract >= 0.5 round up to next mip
 | 
					
						
							|  |  |  |     baseMip += (lodFract >> 3) & (tm0.min_filter & TexMode0::TEXF_POINT); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mipLinear) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u8 sampledTex[4]; | 
					
						
							|  |  |  |     u32 texel[4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SampleMip(s, t, baseMip, linear, texmap, sampledTex); | 
					
						
							|  |  |  |     SetTexel(sampledTex, texel, (16 - lodFract)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SampleMip(s, t, baseMip + 1, linear, texmap, sampledTex); | 
					
						
							|  |  |  |     AddTexel(sampledTex, texel, lodFract); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sample[0] = (u8)(texel[0] >> 4); | 
					
						
							|  |  |  |     sample[1] = (u8)(texel[1] >> 4); | 
					
						
							|  |  |  |     sample[2] = (u8)(texel[2] >> 4); | 
					
						
							|  |  |  |     sample[3] = (u8)(texel[3] >> 4); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |     SampleMip(s, t, baseMip, linear, texmap, sample); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8* sample) | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1]; | 
					
						
							|  |  |  |   u8 subTexmap = texmap & 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   TexMode0& tm0 = texUnit.texMode0[subTexmap]; | 
					
						
							|  |  |  |   TexImage0& ti0 = texUnit.texImage0[subTexmap]; | 
					
						
							|  |  |  |   TexTLUT& texTlut = texUnit.texTlut[subTexmap]; | 
					
						
							|  |  |  |   TlutFormat tlutfmt = (TlutFormat)texTlut.tlut_format; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   u8 *imageSrc, *imageSrcOdd = nullptr; | 
					
						
							|  |  |  |   if (texUnit.texImage1[subTexmap].image_type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     imageSrc = &texMem[texUnit.texImage1[subTexmap].tmem_even * TMEM_LINE_SIZE]; | 
					
						
							|  |  |  |     if (ti0.format == GX_TF_RGBA8) | 
					
						
							|  |  |  |       imageSrcOdd = &texMem[texUnit.texImage2[subTexmap].tmem_odd * TMEM_LINE_SIZE]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     u32 imageBase = texUnit.texImage3[subTexmap].image_base << 5; | 
					
						
							|  |  |  |     imageSrc = Memory::GetPointer(imageBase); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int imageWidth = ti0.width; | 
					
						
							|  |  |  |   int imageHeight = ti0.height; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int tlutAddress = texTlut.tmem_offset << 9; | 
					
						
							|  |  |  |   const u8* tlut = &texMem[tlutAddress]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // reduce sample location and texture size to mip level
 | 
					
						
							|  |  |  |   // move texture pointer to mip location
 | 
					
						
							|  |  |  |   if (mip) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     int mipWidth = imageWidth + 1; | 
					
						
							|  |  |  |     int mipHeight = imageHeight + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int fmtWidth = TexDecoder_GetBlockWidthInTexels(ti0.format); | 
					
						
							|  |  |  |     int fmtHeight = TexDecoder_GetBlockHeightInTexels(ti0.format); | 
					
						
							|  |  |  |     int fmtDepth = TexDecoder_GetTexelSizeInNibbles(ti0.format); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     imageWidth >>= mip; | 
					
						
							|  |  |  |     imageHeight >>= mip; | 
					
						
							|  |  |  |     s >>= mip; | 
					
						
							|  |  |  |     t >>= mip; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (mip) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       mipWidth = std::max(mipWidth, fmtWidth); | 
					
						
							|  |  |  |       mipHeight = std::max(mipHeight, fmtHeight); | 
					
						
							|  |  |  |       u32 size = (mipWidth * mipHeight * fmtDepth) >> 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       imageSrc += size; | 
					
						
							|  |  |  |       mipWidth >>= 1; | 
					
						
							|  |  |  |       mipHeight >>= 1; | 
					
						
							|  |  |  |       mip--; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (linear) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // offset linear sampling
 | 
					
						
							|  |  |  |     s -= 64; | 
					
						
							|  |  |  |     t -= 64; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // integer part of sample location
 | 
					
						
							|  |  |  |     int imageS = s >> 7; | 
					
						
							|  |  |  |     int imageT = t >> 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // linear sampling
 | 
					
						
							|  |  |  |     int imageSPlus1 = imageS + 1; | 
					
						
							|  |  |  |     int fractS = s & 0x7f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int imageTPlus1 = imageT + 1; | 
					
						
							|  |  |  |     int fractT = t & 0x7f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u8 sampledTex[4]; | 
					
						
							|  |  |  |     u32 texel[4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     WrapCoord(&imageS, tm0.wrap_s, imageWidth); | 
					
						
							|  |  |  |     WrapCoord(&imageT, tm0.wrap_t, imageHeight); | 
					
						
							|  |  |  |     WrapCoord(&imageSPlus1, tm0.wrap_s, imageWidth); | 
					
						
							|  |  |  |     WrapCoord(&imageTPlus1, tm0.wrap_t, imageHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, | 
					
						
							|  |  |  |                              tlutfmt); | 
					
						
							|  |  |  |       SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageT, imageWidth, ti0.format, | 
					
						
							|  |  |  |                              tlut, tlutfmt); | 
					
						
							|  |  |  |       AddTexel(sampledTex, texel, (fractS) * (128 - fractT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TexDecoder_DecodeTexel(sampledTex, imageSrc, imageS, imageTPlus1, imageWidth, ti0.format, | 
					
						
							|  |  |  |                              tlut, tlutfmt); | 
					
						
							|  |  |  |       AddTexel(sampledTex, texel, (128 - fractS) * (fractT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TexDecoder_DecodeTexel(sampledTex, imageSrc, imageSPlus1, imageTPlus1, imageWidth, ti0.format, | 
					
						
							|  |  |  |                              tlut, tlutfmt); | 
					
						
							|  |  |  |       AddTexel(sampledTex, texel, (fractS) * (fractT)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageT, | 
					
						
							|  |  |  |                                           imageWidth); | 
					
						
							|  |  |  |       SetTexel(sampledTex, texel, (128 - fractS) * (128 - fractT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, imageT, | 
					
						
							|  |  |  |                                           imageWidth); | 
					
						
							|  |  |  |       AddTexel(sampledTex, texel, (fractS) * (128 - fractT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageS, imageTPlus1, | 
					
						
							|  |  |  |                                           imageWidth); | 
					
						
							|  |  |  |       AddTexel(sampledTex, texel, (128 - fractS) * (fractT)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       TexDecoder_DecodeTexelRGBA8FromTmem(sampledTex, imageSrc, imageSrcOdd, imageSPlus1, | 
					
						
							|  |  |  |                                           imageTPlus1, imageWidth); | 
					
						
							|  |  |  |       AddTexel(sampledTex, texel, (fractS) * (fractT)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sample[0] = (u8)(texel[0] >> 14); | 
					
						
							|  |  |  |     sample[1] = (u8)(texel[1] >> 14); | 
					
						
							|  |  |  |     sample[2] = (u8)(texel[2] >> 14); | 
					
						
							|  |  |  |     sample[3] = (u8)(texel[3] >> 14); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // integer part of sample location
 | 
					
						
							|  |  |  |     int imageS = s >> 7; | 
					
						
							|  |  |  |     int imageT = t >> 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // nearest neighbor sampling
 | 
					
						
							|  |  |  |     WrapCoord(&imageS, tm0.wrap_s, imageWidth); | 
					
						
							|  |  |  |     WrapCoord(&imageT, tm0.wrap_t, imageHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!(ti0.format == GX_TF_RGBA8 && texUnit.texImage1[subTexmap].image_type)) | 
					
						
							|  |  |  |       TexDecoder_DecodeTexel(sample, imageSrc, imageS, imageT, imageWidth, ti0.format, tlut, | 
					
						
							|  |  |  |                              tlutfmt); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       TexDecoder_DecodeTexelRGBA8FromTmem(sample, imageSrc, imageSrcOdd, imageS, imageT, | 
					
						
							|  |  |  |                                           imageWidth); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-06-09 01:37:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | } |