diff --git a/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.cpp b/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.cpp index 66dd8fe0d6..268f30f61d 100644 --- a/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.cpp +++ b/pcsx2/GS/Renderers/SW/GSDrawScanlineCodeGenerator.cpp @@ -16,7 +16,68 @@ #include "PrecompiledHeader.h" #include "GSDrawScanlineCodeGenerator.h" #include "GSDrawScanlineCodeGenerator.all.h" +#include "GSDrawScanline.h" +#include +#include +#include +static std::map s_use_c_draw_scanline; +static std::mutex s_use_c_draw_scanline_mutex; + +static bool shouldUseCDrawScanline(u64 key) +{ + static const char* const fname = getenv("USE_C_DRAW_SCANLINE"); + if (!fname) + return false; + + std::lock_guard l(s_use_c_draw_scanline_mutex); + + if (s_use_c_draw_scanline.empty()) + { + std::ifstream file(fname); + if (file) + { + for (std::string str; std::getline(file, str);) + { + u64 key; + char yn; + if (sscanf(str.c_str(), "%llx %c", &key, &yn) == 2) + { + if (yn != 'Y' && yn != 'N' && yn != 'y' && yn != 'n') + Console.Warning("Failed to parse %s: Not y/n", str.c_str()); + s_use_c_draw_scanline[key] = (yn == 'Y' || yn == 'y') ? true : false; + } + else + { + Console.Warning("Failed to process line %s", str.c_str()); + } + } + } + } + + auto idx = s_use_c_draw_scanline.find(key); + if (idx == s_use_c_draw_scanline.end()) + { + s_use_c_draw_scanline[key] = false; + // Rewrite file + FILE* file = fopen(fname, "w"); + if (file) + { + for (const auto& pair : s_use_c_draw_scanline) + { + fprintf(file, "%016llX %c %s\n", pair.first, pair.second ? 'Y' : 'N', GSScanlineSelector(pair.first).to_string().c_str()); + } + fclose(file); + } + else + { + Console.Warning("Failed to write C draw scanline usage config: %s", strerror(errno)); + } + return false; + } + + return idx->second; +} GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(void* param, u64 key, void* code, size_t maxsize) : GSCodeGenerator(code, maxsize) @@ -28,5 +89,22 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(void* param, u64 key, v if (m_sel.breakpoint) db(0xCC); + if (shouldUseCDrawScanline(key)) + { +#if defined(_WIN32) + mov(r8, reinterpret_cast(&m_local)); + push(ptr[r8 + offsetof(GSScanlineLocalData, gd)]); + push(r8); + sub(rsp, 32); // CC required shadow space + call(reinterpret_cast(GSDrawScanline::CDrawScanline)); + ret(48); +#else + mov(r8, reinterpret_cast(&m_local)); + mov(r9, ptr[r8 + offsetof(GSScanlineLocalData, gd)]); + jmp(reinterpret_cast(GSDrawScanline::CDrawScanline)); +#endif + return; + } + GSDrawScanlineCodeGenerator2(this, CPUInfo(m_cpu), (void*)&m_local, m_sel.key).Generate(); }