mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 22:09:19 -07:00
6e774f1b64
This is good hygiene, and also happens to be required to build Dolphin using Clang modules. (Under this setup, each header file becomes a module, and each #include is automatically translated to a module import. Recursive includes still leak through (by default), but modules are compiled independently, and can't depend on defines or types having previously been set up. The main reason to retrofit it onto Dolphin is compilation performance - no more textual includes whatsoever, rather than putting a few blessed common headers into a PCH. Unfortunately, I found multiple Clang bugs while trying to build Dolphin this way, so it's not ready yet, but I can start with this prerequisite.)
239 lines
6.5 KiB
C++
239 lines
6.5 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
#include "Common/Common.h"
|
|
#include "Core/HW/Memmap.h"
|
|
#include "VideoBackends/Software/BPMemLoader.h"
|
|
#include "VideoBackends/Software/TextureSampler.h"
|
|
#include "VideoCommon/TextureDecoder.h"
|
|
|
|
#define ALLOW_MIPMAP 1
|
|
|
|
namespace TextureSampler
|
|
{
|
|
|
|
static inline void WrapCoord(int* coordp, int wrapMode, int imageSize)
|
|
{
|
|
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;
|
|
}
|
|
|
|
static inline void SetTexel(u8 *inTexel, u32 *outTexel, u32 fract)
|
|
{
|
|
outTexel[0] = inTexel[0] * fract;
|
|
outTexel[1] = inTexel[1] * fract;
|
|
outTexel[2] = inTexel[2] * fract;
|
|
outTexel[3] = inTexel[3] * fract;
|
|
}
|
|
|
|
static inline void AddTexel(u8 *inTexel, u32 *outTexel, u32 fract)
|
|
{
|
|
outTexel[0] += inTexel[0] * fract;
|
|
outTexel[1] += inTexel[1] * fract;
|
|
outTexel[2] += inTexel[2] * fract;
|
|
outTexel[3] += inTexel[3] * fract;
|
|
}
|
|
|
|
void Sample(s32 s, s32 t, s32 lod, bool linear, u8 texmap, u8 *sample)
|
|
{
|
|
int baseMip = 0;
|
|
bool mipLinear = false;
|
|
|
|
#if (ALLOW_MIPMAP)
|
|
FourTexUnits& texUnit = bpmem.tex[(texmap >> 2) & 1];
|
|
TexMode0& tm0 = texUnit.texMode0[texmap & 3];
|
|
|
|
s32 lodFract = lod & 0xf;
|
|
|
|
if (lod > 0 && tm0.min_filter & 3)
|
|
{
|
|
// use mipmap
|
|
baseMip = lod >> 4;
|
|
mipLinear = (lodFract && tm0.min_filter & 2);
|
|
|
|
// if using nearest mip filter and lodFract >= 0.5 round up to next mip
|
|
baseMip += (lodFract >> 3) & (tm0.min_filter & 1);
|
|
}
|
|
|
|
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
|
|
#endif
|
|
{
|
|
SampleMip(s, t, baseMip, linear, texmap, sample);
|
|
}
|
|
}
|
|
|
|
void SampleMip(s32 s, s32 t, s32 mip, bool linear, u8 texmap, u8 *sample)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|