From 4d47ccd5dfb613f32b91155206dec9d049ddd8d4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 2 Nov 2013 02:09:54 -0700 Subject: [PATCH] Add a NEON version of the tex hash. Should be used only for NEON devices. Currently only compiled on Android. --- GPU/Common/TextureDecoder.cpp | 52 ++++++++++++++++++++++++++++ GPU/Common/TextureDecoder.h | 4 +++ GPU/Common/TextureDecoderNEON.cpp | 57 +++++++++++++++++++++++++++++++ GPU/Common/TextureDecoderNEON.h | 20 +++++++++++ GPU/GLES/TextureCache.cpp | 34 ++---------------- GPU/GPU.vcxproj | 12 +++++++ GPU/GPU.vcxproj.filters | 8 ++++- android/jni/Android.mk | 1 + 8 files changed, 155 insertions(+), 33 deletions(-) create mode 100644 GPU/Common/TextureDecoderNEON.cpp create mode 100644 GPU/Common/TextureDecoderNEON.h diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 89b8324c3c..acc6d429a2 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -15,10 +15,62 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/CPUDetect.h" #include "GPU/Common/TextureDecoder.h" +#include "GPU/Common/TextureDecoderNEON.h" // TODO: Move some common things into here. +#ifdef _M_SSE +#include +#endif + +static u32 QuickTexHashSSE2(const void *checkp, u32 size) { + u32 check = 0; + +#ifdef _M_SSE + if (((intptr_t)checkp & 0xf) == 0 && (size & 0x3f) == 0) { + __m128i cursor = _mm_set1_epi32(0); + __m128i cursor2 = _mm_set_epi16(0x0001U, 0x0083U, 0x4309U, 0x4d9bU, 0xb651U, 0x4b73U, 0x9bd9U, 0xc00bU); + __m128i update = _mm_set1_epi16(0x2455U); + const __m128i *p = (const __m128i *)checkp; + for (u32 i = 0; i < size / 16; i += 4) { + __m128i chunk = _mm_mullo_epi16(_mm_load_si128(&p[i]), cursor2); + cursor = _mm_add_epi32(cursor, chunk); + cursor = _mm_xor_si128(cursor, _mm_load_si128(&p[i + 1])); + cursor = _mm_add_epi32(cursor, _mm_load_si128(&p[i + 2])); + chunk = _mm_mullo_epi16(_mm_load_si128(&p[i + 3]), cursor2); + cursor = _mm_xor_si128(cursor, chunk); + cursor2 = _mm_add_epi16(cursor2, update); + } + // Add the four parts into the low i32. + cursor = _mm_add_epi32(cursor, _mm_add_epi32(_mm_srli_si128(cursor, 8), cursor2)); + cursor = _mm_add_epi32(cursor, _mm_srli_si128(cursor, 4)); + check = _mm_cvtsi128_si32(cursor); + } else { +#else + { +#endif + const u32 *p = (const u32 *)checkp; + for (u32 i = 0; i < size / 8; ++i) { + check += *p++; + check ^= *p++; + } + } + + return check; +} + +QuickTexHashFunc DoQuickTexHash = &QuickTexHashSSE2; + +void SetupQuickTexHash() { +#ifdef ARM + if (cpu_info.bNEON) { + DoQuickTexHash = &QuickTexHashNEON; + } +#endif +} + static inline u32 makecol(int r, int g, int b, int a) { return (a << 24) | (r << 16) | (g << 8) | b; } diff --git a/GPU/Common/TextureDecoder.h b/GPU/Common/TextureDecoder.h index 96152b461e..dabd952913 100644 --- a/GPU/Common/TextureDecoder.h +++ b/GPU/Common/TextureDecoder.h @@ -22,6 +22,10 @@ #include "GPU/ge_constants.h" #include "GPU/GPUState.h" +void SetupQuickTexHash(); +typedef u32 (*QuickTexHashFunc)(const void *checkp, u32 size); +extern QuickTexHashFunc DoQuickTexHash; + // All these DXT structs are in the reverse order, as compared to PC. // On PC, alpha comes before color, and interpolants are before the tile data. diff --git a/GPU/Common/TextureDecoderNEON.cpp b/GPU/Common/TextureDecoderNEON.cpp new file mode 100644 index 0000000000..34d78c3c8c --- /dev/null +++ b/GPU/Common/TextureDecoderNEON.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include "GPU/Common/TextureDecoder.h" + +#ifndef ARM +#error Should not be compiled on non-ARM. +#endif + +static const u16 MEMORY_ALIGNED16(QuickTexHashInitial[8]) = {0x0001U, 0x0083U, 0x4309U, 0x4d9bU, 0xb651U, 0x4b73U, 0x9bd9U, 0xc00bU}; + +u32 QuickTexHashNEON(const void *checkp, u32 size) { + u32 check = 0; + + if (((intptr_t)checkp & 0xf) == 0 && (size & 0x3f) == 0) { + uint32x4_t cursor = vdupq_n_u32(0); + uint32x4_t cursor2 = vld1q_u32((const u32 *)QuickTexHashInitial); + uint32x4_t update = vdupq_n_u32(0x24552455U); + + const u32 *p = (const u32 *)checkp; + for (u32 i = 0; i < size / 16; i += 4) { + cursor = vmlaq_u32(cursor, vld1q_u32(&p[4 * 0]), cursor2); + cursor = veorq_u32(cursor, vld1q_u32(&p[4 * 1])); + cursor = vaddq_u32(cursor, vld1q_u32(&p[4 * 2])); + cursor = veorq_u32(cursor, vmulq_u32(vld1q_u32(&p[4 * 3]), cursor2)); + cursor2 = vaddq_u32(cursor2, update); + + p += 4 * 4; + } + + cursor = vaddq_u32(cursor, cursor2); + check = vgetq_lane_u32(cursor, 0) + vgetq_lane_u32(cursor, 1) + vgetq_lane_u32(cursor, 2) + vgetq_lane_u32(cursor, 3); + } else { + const u32 *p = (const u32 *)checkp; + for (u32 i = 0; i < size / 8; ++i) { + check += *p++; + check ^= *p++; + } + } + + return check; +} \ No newline at end of file diff --git a/GPU/Common/TextureDecoderNEON.h b/GPU/Common/TextureDecoderNEON.h new file mode 100644 index 0000000000..2001d859b5 --- /dev/null +++ b/GPU/Common/TextureDecoderNEON.h @@ -0,0 +1,20 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "GPU/Common/TextureDecoder.h" + +u32 QuickTexHashNEON(const void *checkp, u32 size); \ No newline at end of file diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index abd8eb0cf2..d4a3f30e69 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -56,6 +56,7 @@ TextureCache::TextureCache() : clearCacheNextFrame_(false), lowMemoryMode_(false clutBufConverted_ = (u32 *)AllocateAlignedMemory(4096 * sizeof(u32), 16); // 16KB clutBufRaw_ = (u32 *)AllocateAlignedMemory(4096 * sizeof(u32), 16); // 16KB glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropyLevel); + SetupQuickTexHash(); } TextureCache::~TextureCache() { @@ -678,39 +679,8 @@ static inline u32 QuickClutHash(const u8 *clut, u32 bytes) { static inline u32 QuickTexHash(u32 addr, int bufw, int w, int h, GETextureFormat format) { const u32 sizeInRAM = (textureBitsPerPixel[format] * bufw * h) / 8; const u32 *checkp = (const u32 *) Memory::GetPointer(addr); - u32 check = 0; -#ifdef _M_SSE - if (((intptr_t)checkp & 0xf) == 0 && (sizeInRAM & 0x3f) == 0) { - __m128i cursor = _mm_set1_epi32(0); - __m128i cursor2 = _mm_set_epi16(0x0001U, 0x0083U, 0x4309U, 0x4d9bU, 0xb651U, 0x4b73U, 0x9bd9U, 0xc00bU); - __m128i update = _mm_set1_epi16(0x2455U); - const __m128i *p = (const __m128i *)checkp; - for (u32 i = 0; i < sizeInRAM / 16; i += 4) { - __m128i chunk = _mm_mullo_epi16(_mm_load_si128(&p[i]), cursor2); - cursor = _mm_add_epi32(cursor, chunk); - cursor = _mm_xor_si128(cursor, _mm_load_si128(&p[i + 1])); - cursor = _mm_add_epi32(cursor, _mm_load_si128(&p[i + 2])); - chunk = _mm_mullo_epi16(_mm_load_si128(&p[i + 3]), cursor2); - cursor = _mm_xor_si128(cursor, chunk); - cursor2 = _mm_add_epi16(cursor2, update); - } - // Add the four parts into the low i32. - cursor = _mm_add_epi32(cursor, _mm_add_epi32(_mm_srli_si128(cursor, 8), cursor2)); - cursor = _mm_add_epi32(cursor, _mm_srli_si128(cursor, 4)); - check = _mm_cvtsi128_si32(cursor); - } else { -#else - // TODO: ARM NEON implementation (using CPUDetect to be sure it has NEON.) - { -#endif - for (u32 i = 0; i < sizeInRAM / 8; ++i) { - check += *checkp++; - check ^= *checkp++; - } - } - - return check; + return DoQuickTexHash(checkp, sizeInRAM); } inline bool TextureCache::TexCacheEntry::Matches(u16 dim2, u8 format2, int maxLevel2) { diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index c01a29f51b..24a14aa84f 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -159,6 +159,12 @@ + + true + true + true + true + @@ -204,6 +210,12 @@ + + true + true + true + true + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index f709f70349..bd55b4335e 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -159,6 +159,9 @@ Common + + Common + @@ -287,8 +290,11 @@ Common + + Common + - + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index f0cd2c3505..bdf0dcef9e 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -147,6 +147,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/Common/IndexGenerator.cpp.arm \ $(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \ $(SRC)/GPU/Common/TextureDecoder.cpp \ + $(SRC)/GPU/Common/TextureDecoderNEON.cpp.neon \ $(SRC)/GPU/Common/PostShader.cpp \ $(SRC)/GPU/Debugger/Breakpoints.cpp \ $(SRC)/GPU/Debugger/Stepping.cpp \