diff --git a/GPU/Software/FuncId.cpp b/GPU/Software/FuncId.cpp index 8fa53b4db1..3c522d7e20 100644 --- a/GPU/Software/FuncId.cpp +++ b/GPU/Software/FuncId.cpp @@ -425,6 +425,7 @@ void ComputeSamplerID(SamplerID *id_out) { id.cached.sizes[i].w = w; id.cached.sizes[i].h = h; } + // TODO: What specifically happens if these are above 11? id.width0Shift = gstate.texsize[0] & 0xF; id.height0Shift = (gstate.texsize[0] >> 8) & 0xF; id.hasAnyMips = maxLevel != 0; @@ -470,6 +471,7 @@ std::string DescribeSamplerID(const SamplerID &id) { case GE_TFMT_DXT1: name = "DXT1"; break; case GE_TFMT_DXT3: name = "DXT3"; break; case GE_TFMT_DXT5: name = "DXT5"; break; + default: name = "INVALID"; break; } switch (id.ClutFmt()) { case GE_CMODE_16BIT_BGR5650: @@ -549,6 +551,8 @@ std::string DescribeSamplerID(const SamplerID &id) { break; } name += StringFromFormat(":W%dH%d", 1 << id.width0Shift, 1 << id.height0Shift); + if (id.width0Shift > 10 || id.height0Shift > 10) + name = "INVALID:" + name; return name; } diff --git a/unittest/TestSoftwareGPUJit.cpp b/unittest/TestSoftwareGPUJit.cpp index 5608b3e1e4..23292ed214 100644 --- a/unittest/TestSoftwareGPUJit.cpp +++ b/unittest/TestSoftwareGPUJit.cpp @@ -22,6 +22,90 @@ #include "GPU/Software/Sampler.h" #include "GPU/Software/SoftGpu.h" +static bool TestSamplerJit() { + using namespace Sampler; + SamplerJitCache *cache = new SamplerJitCache(); + + auto GetLinear = [&](SamplerID &id) { + id.linear = true; + id.fetch = false; + return cache->GetLinear(id); + }; + auto GetNearest = [&](SamplerID &id) { + id.linear = false; + id.fetch = false; + return cache->GetNearest(id); + }; + auto GetFetch = [&](SamplerID &id) { + id.linear = false; + id.fetch = true; + return cache->GetFetch(id); + }; + + GMRng rng; + int successes = 0; + int count = 3000; + bool header = false; + + u8 **tptr = new u8 *[8]; + int *bufw = new int[8]; + u8 *clut = new u8[1024]; + for (int i = 0; i < 8; ++i) { + tptr[i] = new u8[1024 * 1024 * 4]; + memset(tptr[i], 0, 1024 * 1024 * 4); + bufw[i] = 1; + } + + for (int i = 0; i < count; ) { + SamplerID id; + memset(&id, 0, sizeof(id)); + id.fullKey = rng.R32(); + id.cached.clut = clut; + + for (int i = 0; i < 8; ++i) { + id.cached.sizes[i].w = 1; + id.cached.sizes[i].h = 1; + } + + std::string desc = DescribeSamplerID(id); + if (startsWith(desc, "INVALID")) + continue; + i++; + + LinearFunc linearFunc = GetLinear(id); + NearestFunc nearestFunc = GetNearest(id); + FetchFunc fetchFunc = GetFetch(id); + if (linearFunc != nullptr && nearestFunc != nullptr && fetchFunc != nullptr) { + successes++; + } else { + if (!header) + printf("Failed sampler funcs:\n"); + header = true; + printf(" * %s (L:%d, N:%d, F:%d)\n", desc.c_str(), linearFunc != nullptr, nearestFunc != nullptr, fetchFunc != nullptr); + continue; + } + + // Try running each to make sure they don't trivially crash. + const auto primArg = Rasterizer::ToVec4IntArg(Math3D::Vec4(127, 127, 127, 127)); + linearFunc(0.0f, 0.0f, 0, 0, primArg, tptr, bufw, 1, 7, id); + nearestFunc(0.0f, 0.0f, 0, 0, primArg, tptr, bufw, 1, 7, id); + fetchFunc(0, 0, tptr[0], bufw[0], 1, id); + } + + if (successes < count) + printf("SamplerFunc success: %d / %d\n", successes, count); + + for (int i = 0; i < 8; ++i) { + delete [] tptr[i]; + } + delete [] tptr; + delete [] bufw; + delete [] clut; + + delete cache; + return successes == count && !HitAnyAsserts(); +} + static bool TestPixelJit() { using namespace Rasterizer; PixelJitCache *cache = new PixelJitCache(); @@ -52,7 +136,7 @@ static bool TestPixelJit() { successes++; } else { if (!header) - printf("Failed funcs:\n"); + printf("Failed pixel funcs:\n"); header = true; printf(" * %s\n", desc.c_str()); } @@ -74,6 +158,10 @@ bool TestSoftwareGPUJit() { g_Config.bSoftwareRenderingJit = true; ResetHitAnyAsserts(); + if (!TestSamplerJit()) { + return false; + } + if (!TestPixelJit()) { return false; }