diff --git a/CMakeLists.txt b/CMakeLists.txt
index 44af0f6350..dd5a4822eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1629,6 +1629,7 @@ if(UNITTEST)
unittest/TestArmEmitter.cpp
unittest/TestArm64Emitter.cpp
unittest/TestX64Emitter.cpp
+ unittest/TestVertexJit.cpp
unittest/JitHarness.cpp
Core/MIPS/ARM/ArmRegCache.cpp
Core/MIPS/ARM/ArmRegCacheFPU.cpp
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 6b06e85dda..e1012c2b8f 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -447,6 +447,7 @@ ifeq ($(UNITTEST),1)
$(EXEC_AND_LIB_FILES) \
$(SRC)/Core/MIPS/MIPSAsm.cpp \
$(SRC)/UnitTest/JitHarness.cpp \
+ $(SRC)/UnitTest/TestVertexJit.cpp \
$(TESTARMEMITTER_FILE) \
$(SRC)/UnitTest/UnitTest.cpp
diff --git a/unittest/TestVertexJit.cpp b/unittest/TestVertexJit.cpp
new file mode 100644
index 0000000000..065f8320aa
--- /dev/null
+++ b/unittest/TestVertexJit.cpp
@@ -0,0 +1,170 @@
+// Copyright (c) 2015- 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 "Common/Common.h"
+#include "Core/Config.h"
+#include "GPU/Common/VertexDecoderCommon.h"
+#include "GPU/ge_constants.h"
+#include "unittest/TestVertexJit.h"
+#include "unittest/UnitTest.h"
+
+#pragma optimize("", off)
+
+class VertexDecoderTestHarness {
+ static const int BUFFER_SIZE = 64 * 65536;
+
+public:
+ VertexDecoderTestHarness()
+ : needsReset_(true), dstPos_(0) {
+ src_ = new u8[BUFFER_SIZE];
+ dst_ = new u8[BUFFER_SIZE];
+ cache_ = new VertexDecoderJitCache();
+
+ g_Config.bVertexDecoderJit = true;
+ }
+ ~VertexDecoderTestHarness() {
+ delete src_;
+ delete dst_;
+ delete cache_;
+ }
+
+ void Reset() {
+ memset(src_, 0, BUFFER_SIZE);
+ memset(dst_, 0, BUFFER_SIZE);
+ memset(&options_, 0, sizeof(options_));
+ indexLowerBound_ = 0;
+ indexUpperBound_ = 0;
+ srcPos_ = 0;
+ dstPos_ = 0;
+ needsReset_ = false;
+ }
+
+ void SetOptions(const VertexDecoderOptions &opts) {
+ if (needsReset_) {
+ Reset();
+ }
+ memcpy(&options_, &opts, sizeof(options_));
+ }
+
+ void SetIndexLowerBound(const int lower) {
+ if (needsReset_) {
+ Reset();
+ }
+ indexLowerBound_ = lower;
+ }
+
+ void Execute(int vtype, int indexUpperBound, bool useJit) {
+ if (needsReset_) {
+ Reset();
+ }
+
+ VertexDecoder *dec = new VertexDecoder();
+ dec->SetVertexType(vtype, options_, useJit ? cache_ : nullptr);
+ dec->DecodeVerts(dst_, src_, indexLowerBound_, indexUpperBound);
+ delete dec;
+
+ needsReset_ = true;
+ }
+
+ void Add8(u8 x) {
+ if (needsReset_) {
+ Reset();
+ }
+ memcpy(src_ + srcPos_, &x, sizeof(x));
+ srcPos_ += sizeof(x);
+ }
+ void Add8(u8 x, u8 y) {
+ Add8(x);
+ Add8(y);
+ }
+ void Add8(u8 x, u8 y, u8 z) {
+ Add8(x);
+ Add8(y);
+ Add8(z);
+ }
+
+ void Add16(u16_le x) {
+ if (needsReset_) {
+ Reset();
+ }
+ memcpy(src_ + srcPos_, &x, sizeof(x));
+ srcPos_ += sizeof(x);
+ }
+ void Add16(u16_le x, u16_le y) {
+ Add16(x);
+ Add16(y);
+ }
+ void Add16(u16_le x, u16_le y, u16_le z) {
+ Add16(x);
+ Add16(y);
+ Add16(z);
+ }
+
+ void AddFloat(float_le x) {
+ if (needsReset_) {
+ Reset();
+ }
+ memcpy(src_ + srcPos_, &x, sizeof(x));
+ srcPos_ += sizeof(x);
+ }
+ void AddFloat(float_le x, float_le y) {
+ AddFloat(x);
+ AddFloat(y);
+ }
+ void AddFloat(float_le x, float_le y, float_le z) {
+ AddFloat(x);
+ AddFloat(y);
+ AddFloat(z);
+ }
+
+ u8 Get8() {
+ return dst_[dstPos_++];
+ }
+
+ u16 Get16() {
+ u16 result;
+ memcpy(&result, dst_ + dstPos_, sizeof(result));
+ dstPos_ += sizeof(result);
+ return result;
+ }
+
+ float GetFloat() {
+ float result;
+ memcpy(&result, dst_ + dstPos_, sizeof(result));
+ dstPos_ += sizeof(result);
+ return result;
+ }
+
+private:
+ u8 *src_;
+ u8 *dst_;
+ VertexDecoderJitCache *cache_;
+ VertexDecoderOptions options_;
+ int indexLowerBound_;
+ int indexUpperBound_;
+ bool needsReset_;
+ size_t srcPos_;
+ size_t dstPos_;
+};
+
+bool TestVertexJit() {
+ VertexDecoderTestHarness dec;
+ dec.AddFloat(1.0f, 1.0f, 1.0f);
+ dec.Execute(GE_VTYPE_POS_FLOAT, 1, true);
+ printf("Result: %f, %f, %f\n", dec.GetFloat(), dec.GetFloat(), dec.GetFloat());
+ return true;
+}
diff --git a/unittest/TestVertexJit.h b/unittest/TestVertexJit.h
new file mode 100644
index 0000000000..c4ddcf90f0
--- /dev/null
+++ b/unittest/TestVertexJit.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2015- 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/.
+
+#pragma once
+
+bool TestVertexJit();
diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp
index 1d003ac2f1..2b0b4c48ed 100644
--- a/unittest/UnitTest.cpp
+++ b/unittest/UnitTest.cpp
@@ -42,6 +42,7 @@
#include "Core/MIPS/MIPSVFPUUtils.h"
#include "unittest/JitHarness.h"
+#include "unittest/TestVertexJit.h"
#include "unittest/UnitTest.h"
std::string System_GetProperty(SystemProperty prop) { return ""; }
@@ -382,6 +383,7 @@ TestItem availableTests[] = {
#if defined(_M_X64) || defined(_M_IX86)
TEST_ITEM(X64Emitter),
#endif
+ TEST_ITEM(VertexJit),
TEST_ITEM(Asin),
TEST_ITEM(SinCos),
TEST_ITEM(VFPUSinCos),
diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj
index 4333164980..24950005ce 100644
--- a/unittest/UnitTests.vcxproj
+++ b/unittest/UnitTests.vcxproj
@@ -182,6 +182,7 @@
+
@@ -211,6 +212,7 @@
+
diff --git a/unittest/UnitTests.vcxproj.filters b/unittest/UnitTests.vcxproj.filters
index 6f010302f8..e6d19db65c 100644
--- a/unittest/UnitTests.vcxproj.filters
+++ b/unittest/UnitTests.vcxproj.filters
@@ -7,9 +7,11 @@
+
+
\ No newline at end of file