Permalink
Browse files

TexCache: Fix texture alignment in GLES.

We must align to 4 bytes, and we aren't always aligned to 16 anymore, so
we must check when dealing with swizzle.
  • Loading branch information...
unknownbrackets committed Sep 9, 2018
1 parent 959a999 commit 97773d3dd55fdd5541a51553e57a6815dad1380b
Showing with 55 additions and 58 deletions.
  1. +44 −41 GPU/Common/TextureDecoder.cpp
  2. +1 −1 GPU/Common/TextureDecoder.h
  3. +1 −1 GPU/D3D11/TextureCacheD3D11.cpp
  4. +9 −15 GPU/GLES/TextureCacheGLES.cpp
@@ -203,59 +203,62 @@ void DoSwizzleTex16(const u32 *ysrcp, u8 *texptr, int bxc, int byc, u32 pitch) {
// ysrcp is in 32-bits, so this is convenient.
const u32 pitchBy32 = pitch >> 2;
#ifdef _M_SSE
__m128i *dest = (__m128i *)texptr;
// The pitch parameter is in bytes, so shift down for 128-bit.
// Note: it's always aligned to 16 bytes, so this is safe.
const u32 pitchBy128 = pitch >> 4;
for (int by = 0; by < byc; by++) {
const __m128i *xsrc = (const __m128i *)ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const __m128i *src = xsrc;
for (int n = 0; n < 2; n++) {
// Textures are always 16-byte aligned so this is fine.
__m128i temp1 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp2 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp3 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp4 = _mm_load_si128(src);
src += pitchBy128;
_mm_store_si128(dest, temp1);
_mm_store_si128(dest + 1, temp2);
_mm_store_si128(dest + 2, temp3);
_mm_store_si128(dest + 3, temp4);
dest += 4;
if (((uintptr_t)ysrcp & 0xF) == 0 && (pitch & 0xF) == 0) {
__m128i *dest = (__m128i *)texptr;
// The pitch parameter is in bytes, so shift down for 128-bit.
// Note: it's always aligned to 16 bytes, so this is safe.
const u32 pitchBy128 = pitch >> 4;
for (int by = 0; by < byc; by++) {
const __m128i *xsrc = (const __m128i *)ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const __m128i *src = xsrc;
for (int n = 0; n < 2; n++) {
// Textures are always 16-byte aligned so this is fine.
__m128i temp1 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp2 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp3 = _mm_load_si128(src);
src += pitchBy128;
__m128i temp4 = _mm_load_si128(src);
src += pitchBy128;
_mm_store_si128(dest, temp1);
_mm_store_si128(dest + 1, temp2);
_mm_store_si128(dest + 2, temp3);
_mm_store_si128(dest + 3, temp4);
dest += 4;
}
xsrc++;
}
xsrc++;
ysrcp += pitchBy32 * 8;
}
ysrcp += pitchBy32 * 8;
}
#else
u32 *dest = (u32 *)texptr;
for (int by = 0; by < byc; by++) {
const u32 *xsrc = ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const u32 *src = xsrc;
for (int n = 0; n < 8; n++) {
memcpy(dest, src, 16);
src += pitchBy32;
dest += 4;
} else
#endif
{
u32 *dest = (u32 *)texptr;
for (int by = 0; by < byc; by++) {
const u32 *xsrc = ysrcp;
for (int bx = 0; bx < bxc; bx++) {
const u32 *src = xsrc;
for (int n = 0; n < 8; n++) {
memcpy(dest, src, 16);
src += pitchBy32;
dest += 4;
}
xsrc += 4;
}
xsrc += 4;
ysrcp += pitchBy32 * 8;
}
ysrcp += pitchBy32 * 8;
}
#endif
}
void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch) {
// ydestp is in 32-bits, so this is convenient.
const u32 pitchBy32 = pitch >> 2;
#ifdef _M_SSE
if (((uintptr_t)ydestp & 0xF) == 0) {
if (((uintptr_t)ydestp & 0xF) == 0 && (pitch & 0xF) == 0) {
const __m128i *src = (const __m128i *)texptr;
// The pitch parameter is in bytes, so shift down for 128-bit.
// Note: it's always aligned to 16 bytes, so this is safe.
@@ -41,7 +41,7 @@ u32 QuickTexHashSSE2(const void *checkp, u32 size);
#define DoQuickTexHash QuickTexHashSSE2
#define StableQuickTexHash QuickTexHashSSE2
// Pitch must be aligned to 16 bits (as is the case on a PSP)
// Pitch must be aligned to 16 bytes (as is the case on a PSP)
void DoUnswizzleTex16Basic(const u8 *texptr, u32 *ydestp, int bxc, int byc, u32 pitch);
#define DoUnswizzleTex16 DoUnswizzleTex16Basic
@@ -699,7 +699,7 @@ void TextureCacheD3D11::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &
mapData = (u32 *)AllocateAlignedMemory(sizeof(u32) * (w * scaleFactor) * (h * scaleFactor), 16);
mapRowPitch = w * scaleFactor * 4;
} else {
mapRowPitch = std::max(bufw, w) * bpp;
mapRowPitch = std::max(w * bpp, 16);
size_t bufSize = sizeof(u32) * (mapRowPitch / bpp) * h;
mapData = (u32 *)AllocateAlignedMemory(bufSize, 16);
if (!mapData) {
@@ -744,25 +744,21 @@ TexCacheEntry::TexStatus TextureCacheGLES::CheckAlpha(const uint8_t *pixelData,
void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &replaced, int level, int scaleFactor, GLenum dstFmt) {
int w = gstate.getTextureWidth(level);
int h = gstate.getTextureHeight(level);
bool useUnpack = false;
uint8_t *pixelData;
// TODO: only do this once
u32 texByteAlign = 1;
int decPitch = 0;
gpuStats.numTexturesDecoded++;
if (replaced.GetSize(level, w, h)) {
PROFILE_THIS_SCOPE("replacetex");
int bpp = replaced.Format(level) == ReplacedTextureFormat::F_8888 ? 4 : 2;
uint8_t *rearrange = (uint8_t *)AllocateAlignedMemory(w * h * bpp, 16);
replaced.Load(level, rearrange, bpp * w);
decPitch = w * bpp;
uint8_t *rearrange = (uint8_t *)AllocateAlignedMemory(decPitch * h, 16);
replaced.Load(level, rearrange, decPitch);
pixelData = rearrange;
dstFmt = ToGLESFormat(replaced.Format(level));
texByteAlign = bpp;
} else {
PROFILE_THIS_SCOPE("decodetex");
@@ -771,14 +767,15 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
int bufw = GetTextureBufw(level, texaddr, GETextureFormat(entry.format));
int pixelSize = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
int decPitch = w * pixelSize;
// We leave GL_UNPACK_ALIGNMENT at 4, so this must be at least 4.
decPitch = std::max(w * pixelSize, 4);
pixelData = (uint8_t *)AllocateAlignedMemory(decPitch * h * pixelSize, 16);
DecodeTextureLevel(pixelData, decPitch, GETextureFormat(entry.format), clutformat, texaddr, level, bufw, true, false, false);
// We check before scaling since scaling shouldn't invent alpha from a full alpha texture.
if ((entry.status & TexCacheEntry::STATUS_CHANGE_FREQUENT) == 0) {
TexCacheEntry::TexStatus alphaStatus = CheckAlpha(pixelData, dstFmt, useUnpack ? bufw : w, w, h);
TexCacheEntry::TexStatus alphaStatus = CheckAlpha(pixelData, dstFmt, decPitch / pixelSize, w, h);
entry.SetAlphaStatus(alphaStatus, level);
} else {
entry.SetAlphaStatus(TexCacheEntry::STATUS_ALPHA_UNKNOWN);
@@ -789,11 +786,9 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
scaler.ScaleAlways((u32 *)rearrange, (u32 *)pixelData, dstFmt, w, h, scaleFactor);
FreeAlignedMemory(pixelData);
pixelData = rearrange;
decPitch = w * 4;
}
// Textures are always aligned to 16 bytes bufw, so this could safely be 4 always.
texByteAlign = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
if (replacer_.Enabled()) {
ReplacedTextureDecodeInfo replacedInfo;
replacedInfo.cachekey = entry.CacheKey();
@@ -804,8 +799,7 @@ void TextureCacheGLES::LoadTextureLevel(TexCacheEntry &entry, ReplacedTexture &r
replacedInfo.scaleFactor = scaleFactor;
replacedInfo.fmt = FromGLESFormat(dstFmt);
int bpp = dstFmt == GL_UNSIGNED_BYTE ? 4 : 2;
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, (useUnpack ? bufw : w) * bpp, level, w, h);
replacer_.NotifyTextureDecoded(replacedInfo, pixelData, decPitch, level, w, h);
}
}

0 comments on commit 97773d3

Please sign in to comment.