Deprecate and remove offline shader cache.

This commit is contained in:
Dario 2024-08-19 19:48:35 -03:00
parent 6853ac4c35
commit 5749e90548
7 changed files with 34 additions and 316 deletions

View File

@ -395,10 +395,6 @@ namespace RT64 {
state->updateScreen(core.decodeVI(), false);
}
bool Application::loadOfflineShaderCache(std::istream &stream) {
return rasterShaderCache->loadOfflineList(stream);
}
void Application::destroyShaderCache() {
workloadQueue->waitForWorkloadId(state->workloadId);
presentQueue->waitForPresentId(state->presentId);
@ -434,7 +430,6 @@ namespace RT64 {
// Wait for all pipelines of the ubershader to be ready again.
rasterShaderCache->shaderUber->waitForPipelineCreation();
rasterShaderCache->resetOfflineList();
}
#ifdef _WIN32

View File

@ -157,7 +157,6 @@ namespace RT64 {
SetupResult setup(uint32_t threadId);
void processDisplayLists(uint8_t *memory, uint32_t dlStartAddress, uint32_t dlEndAddress, bool isHLE);
void updateScreen();
bool loadOfflineShaderCache(std::istream &stream);
void destroyShaderCache();
void updateMultisampling();
void end();

View File

@ -2127,32 +2127,7 @@ namespace RT64 {
ImGui::Indent();
enhanceConfigChanged = ImGui::Checkbox("Scale LOD", &enhancementConfig.textureLOD.scale) || enhanceConfigChanged;
ImGui::Unindent();
ImGui::Text("Shader cache");
ImGui::Indent();
bool dumpingDisabled = (userConfig.graphicsAPI != UserConfiguration::GraphicsAPI::D3D12);
ImGui::BeginDisabled(dumpingDisabled);
bool offlineDumperActive = ext.rasterShaderCache->isOfflineDumperActive();
bool offlineDumperToggled = ImGui::Button(offlineDumperActive ? "Stop dumping##shaderCache" : "Start dumping##shaderCache");
if (offlineDumperToggled) {
if (offlineDumperActive) {
ext.rasterShaderCache->stopOfflineDumper();
}
else {
std::filesystem::path savePath = FileDialog::getSaveFilename({ FileFilter("BIN Files", "bin") });
if (!savePath.empty()) {
ext.rasterShaderCache->startOfflineDumper(savePath);
shaderCacheChanged = true;
}
}
}
ImGui::EndDisabled();
if (dumpingDisabled) {
ImGui::Text("Shader cache dumping is only available in D3D12.");
}
ImGui::Unindent();
ImGui::EndTabItem();
}
@ -2434,10 +2409,7 @@ namespace RT64 {
}
# endif
ImGui::NewLine();
ImGui::Text("Offline Shaders: %zu", ext.rasterShaderCache->offlineList.entries.size());
ImGui::Text("Specialized Shaders: %u", ext.rasterShaderCache->shaderCount());
ImGui::NewLine();
bool ubershadersOnly = ext.workloadQueue->ubershadersOnly;

View File

@ -76,7 +76,7 @@ namespace RT64 {
// RasterShader
RasterShader::RasterShader(RenderDevice *device, const ShaderDescription &desc, const RenderPipelineLayout *pipelineLayout, RenderShaderFormat shaderFormat, const RenderMultisampling &multisampling,
const ShaderCompiler *shaderCompiler, const OptimizerCacheSPIRV *optimizerCacheSPIRV, std::vector<uint8_t> *vsBytes, std::vector<uint8_t> *psBytes, bool useBytes)
const ShaderCompiler *shaderCompiler, const OptimizerCacheSPIRV *optimizerCacheSPIRV)
{
assert(device != nullptr);
@ -138,56 +138,41 @@ namespace RT64 {
}
else {
# if defined(_WIN32)
if (useBytes) {
vertexShader = device->createShader(vsBytes->data(), vsBytes->size(), "VSMain", shaderFormat);
pixelShader = device->createShader(psBytes->data(), psBytes->size(), "PSMain", shaderFormat);
}
else {
RasterShaderText shaderText = generateShaderText(desc, useMSAA);
RasterShaderText shaderText = generateShaderText(desc, useMSAA);
// Compile both shaders from text with the constants hard-coded in.
static const wchar_t *blobVSLibraryNames[] = { L"RasterVSEntry", L"RasterVSLibrary" };
static const wchar_t *blobPSLibraryNames[] = { L"RasterPSEntry", L"RasterPSLibrary" };
IDxcBlob *blobVSLibraries[] = { nullptr, nullptr };
IDxcBlob *blobPSLibraries[] = { nullptr, nullptr };
shaderCompiler->dxcUtils->CreateBlobFromPinned(RasterVSLibraryBlobDXIL, sizeof(RasterVSLibraryBlobDXIL), DXC_CP_ACP, (IDxcBlobEncoding **)(&blobVSLibraries[1]));
// Compile both shaders from text with the constants hard-coded in.
static const wchar_t *blobVSLibraryNames[] = { L"RasterVSEntry", L"RasterVSLibrary" };
static const wchar_t *blobPSLibraryNames[] = { L"RasterPSEntry", L"RasterPSLibrary" };
IDxcBlob *blobVSLibraries[] = { nullptr, nullptr };
IDxcBlob *blobPSLibraries[] = { nullptr, nullptr };
shaderCompiler->dxcUtils->CreateBlobFromPinned(RasterVSLibraryBlobDXIL, sizeof(RasterVSLibraryBlobDXIL), DXC_CP_ACP, (IDxcBlobEncoding **)(&blobVSLibraries[1]));
const void *PSLibraryBlob = useMSAA ? RasterPSLibraryMSBlobDXIL : RasterPSLibraryBlobDXIL;
uint32_t PSLibraryBlobSize = useMSAA ? sizeof(RasterPSLibraryMSBlobDXIL) : sizeof(RasterPSLibraryBlobDXIL);
shaderCompiler->dxcUtils->CreateBlobFromPinned(PSLibraryBlob, PSLibraryBlobSize, DXC_CP_ACP, (IDxcBlobEncoding **)(&blobPSLibraries[1]));
const void *PSLibraryBlob = useMSAA ? RasterPSLibraryMSBlobDXIL : RasterPSLibraryBlobDXIL;
uint32_t PSLibraryBlobSize = useMSAA ? sizeof(RasterPSLibraryMSBlobDXIL) : sizeof(RasterPSLibraryBlobDXIL);
shaderCompiler->dxcUtils->CreateBlobFromPinned(PSLibraryBlob, PSLibraryBlobSize, DXC_CP_ACP, (IDxcBlobEncoding **)(&blobPSLibraries[1]));
// Compile both the vertex and pixel shader functions as libraries.
const std::wstring VertexShaderName = L"VSMain";
const std::wstring PixelShaderName = L"PSMain";
shaderCompiler->compile(shaderText.vertexShader, VertexShaderName, L"lib_6_3", shaderFormat, &blobVSLibraries[0]);
shaderCompiler->compile(shaderText.pixelShader, PixelShaderName, L"lib_6_3", shaderFormat, &blobPSLibraries[0]);
// Compile both the vertex and pixel shader functions as libraries.
const std::wstring VertexShaderName = L"VSMain";
const std::wstring PixelShaderName = L"PSMain";
shaderCompiler->compile(shaderText.vertexShader, VertexShaderName, L"lib_6_3", shaderFormat, &blobVSLibraries[0]);
shaderCompiler->compile(shaderText.pixelShader, PixelShaderName, L"lib_6_3", shaderFormat, &blobPSLibraries[0]);
// Link the vertex and pixel shaders with the libraries that define their main functions.
IDxcBlob *blobVS = nullptr;
IDxcBlob *blobPS = nullptr;
shaderCompiler->link(VertexShaderName, L"vs_6_3", blobVSLibraries, blobVSLibraryNames, std::size(blobVSLibraries), &blobVS);
shaderCompiler->link(PixelShaderName, L"ps_6_3", blobPSLibraries, blobPSLibraryNames, std::size(blobPSLibraries), &blobPS);
// Link the vertex and pixel shaders with the libraries that define their main functions.
IDxcBlob *blobVS = nullptr;
IDxcBlob *blobPS = nullptr;
shaderCompiler->link(VertexShaderName, L"vs_6_3", blobVSLibraries, blobVSLibraryNames, std::size(blobVSLibraries), &blobVS);
shaderCompiler->link(PixelShaderName, L"ps_6_3", blobPSLibraries, blobPSLibraryNames, std::size(blobPSLibraries), &blobPS);
vertexShader = device->createShader(blobVS->GetBufferPointer(), blobVS->GetBufferSize(), "VSMain", shaderFormat);
pixelShader = device->createShader(blobPS->GetBufferPointer(), blobPS->GetBufferSize(), "PSMain", shaderFormat);
vertexShader = device->createShader(blobVS->GetBufferPointer(), blobVS->GetBufferSize(), "VSMain", shaderFormat);
pixelShader = device->createShader(blobPS->GetBufferPointer(), blobPS->GetBufferSize(), "PSMain", shaderFormat);
// Store the bytes in the auxiliary buffers if specified.
if (vsBytes != nullptr) {
*vsBytes = std::vector<uint8_t>((const uint8_t *)(blobVS->GetBufferPointer()), (const uint8_t *)(blobVS->GetBufferPointer()) + blobVS->GetBufferSize());
}
if (psBytes != nullptr) {
*psBytes = std::vector<uint8_t>((const uint8_t *)(blobPS->GetBufferPointer()), (const uint8_t *)(blobPS->GetBufferPointer()) + blobPS->GetBufferSize());
}
// Blobs can be discarded once the shaders are created.
blobVSLibraries[0]->Release();
blobVSLibraries[1]->Release();
blobPSLibraries[0]->Release();
blobPSLibraries[1]->Release();
blobPS->Release();
blobVS->Release();
}
// Blobs can be discarded once the shaders are created.
blobVSLibraries[0]->Release();
blobVSLibraries[1]->Release();
blobPSLibraries[0]->Release();
blobPSLibraries[1]->Release();
blobPS->Release();
blobVS->Release();
# else
assert(false && "This platform does not support runtime shader compilation.");
# endif

View File

@ -64,7 +64,7 @@ namespace RT64 {
std::unique_ptr<RenderPipeline> pipeline;
RasterShader(RenderDevice *device, const ShaderDescription &desc, const RenderPipelineLayout *pipelineLayout, RenderShaderFormat shaderFormat, const RenderMultisampling &multisampling,
const ShaderCompiler *shaderCompiler, const OptimizerCacheSPIRV *optimizerCacheSPIRV, std::vector<uint8_t> *vsBytes = nullptr, std::vector<uint8_t> *psBytes = nullptr, bool useBytes = false);
const ShaderCompiler *shaderCompiler, const OptimizerCacheSPIRV *optimizerCacheSPIRV);
~RasterShader();
static RasterShaderText generateShaderText(const ShaderDescription &desc, bool multisampling);

View File

@ -9,117 +9,6 @@
#define ENABLE_OPTIMIZED_SHADER_GENERATION
namespace RT64 {
// RasterShaderCache::OfflineList
static const uint32_t OfflineMagic = 0x43535452;
static const uint32_t OfflineVersion = 3;
RasterShaderCache::OfflineList::OfflineList() {
entryIterator = entries.end();
}
bool RasterShaderCache::OfflineList::load(std::istream &stream) {
Entry entry;
while (!stream.eof()) {
uint32_t magic = 0;
uint32_t version = 0;
uint64_t vsHash = 0;
uint64_t psHash = 0;
stream.read(reinterpret_cast<char *>(&magic), sizeof(uint32_t));
stream.read(reinterpret_cast<char *>(&version), sizeof(uint32_t));
stream.read(reinterpret_cast<char *>(&vsHash), sizeof(uint64_t));
stream.read(reinterpret_cast<char *>(&psHash), sizeof(uint64_t));
if (stream.eof()) {
break;
}
if ((magic != OfflineMagic) || (version != OfflineVersion) || (vsHash != RasterShaderUber::RasterVSLibraryHash) || (psHash != RasterShaderUber::RasterPSLibraryHash)) {
return false;
}
stream.read(reinterpret_cast<char *>(&entry.shaderDesc), sizeof(ShaderDescription));
uint32_t vsDxilSize = 0;
stream.read(reinterpret_cast<char *>(&vsDxilSize), sizeof(uint32_t));
entry.vsDxilBytes.resize(vsDxilSize);
stream.read(reinterpret_cast<char *>(entry.vsDxilBytes.data()), vsDxilSize);
if (stream.bad() || entry.vsDxilBytes.empty()) {
return false;
}
uint32_t psDxilSize = 0;
stream.read(reinterpret_cast<char *>(&psDxilSize), sizeof(uint32_t));
entry.psDxilBytes.resize(psDxilSize);
stream.read(reinterpret_cast<char *>(entry.psDxilBytes.data()), psDxilSize);
if (stream.bad() || entry.psDxilBytes.empty()) {
return false;
}
entries.emplace_back(entry);
}
entryIterator = entries.begin();
return true;
}
void RasterShaderCache::OfflineList::reset() {
if (!entries.empty()) {
entryIterator = entries.begin();
}
}
void RasterShaderCache::OfflineList::step(Entry &entry) {
if (entryIterator != entries.end()) {
entry = *entryIterator;
entryIterator++;
}
}
bool RasterShaderCache::OfflineList::atEnd() const {
if (!entries.empty()) {
return entryIterator == entries.end();
}
else {
return true;
}
}
// RasterShaderCache::OfflineDumper
bool RasterShaderCache::OfflineDumper::startDumping(const std::filesystem::path &path) {
assert(!dumpStream.is_open());
dumpStream.open(path, std::ios::binary);
return dumpStream.is_open();
}
bool RasterShaderCache::OfflineDumper::stepDumping(const ShaderDescription &shaderDesc, const std::vector<uint8_t> &vsDxilBytes, const std::vector<uint8_t> &psDxilBytes) {
assert(!vsDxilBytes.empty());
assert(!psDxilBytes.empty());
uint32_t vsDxilSize = uint32_t(vsDxilBytes.size());
uint32_t psDxilSize = uint32_t(psDxilBytes.size());
dumpStream.write(reinterpret_cast<const char *>(&OfflineMagic), sizeof(uint32_t));
dumpStream.write(reinterpret_cast<const char *>(&OfflineVersion), sizeof(uint32_t));
dumpStream.write(reinterpret_cast<const char *>(&RasterShaderUber::RasterVSLibraryHash), sizeof(uint64_t));
dumpStream.write(reinterpret_cast<const char *>(&RasterShaderUber::RasterPSLibraryHash), sizeof(uint64_t));
dumpStream.write(reinterpret_cast<const char *>(&shaderDesc), sizeof(ShaderDescription));
dumpStream.write(reinterpret_cast<const char *>(&vsDxilSize), sizeof(uint32_t));
dumpStream.write(reinterpret_cast<const char *>(vsDxilBytes.data()), vsDxilSize);
dumpStream.write(reinterpret_cast<const char *>(&psDxilSize), sizeof(uint32_t));
dumpStream.write(reinterpret_cast<const char *>(psDxilBytes.data()), psDxilSize);
return dumpStream.bad();
}
bool RasterShaderCache::OfflineDumper::stopDumping() {
assert(dumpStream.is_open());
dumpStream.close();
return dumpStream.bad();
}
bool RasterShaderCache::OfflineDumper::isDumping() const {
return dumpStream.is_open();
}
// RasterShaderCache::CompilationThread
RasterShaderCache::CompilationThread::CompilationThread(RasterShaderCache *shaderCache) {
@ -146,20 +35,16 @@ namespace RT64 {
threadRunning = true;
OfflineList::Entry offlineListEntry;
std::vector<uint8_t> dumperVsBytes;
std::vector<uint8_t> dumperPsBytes;
while (threadRunning) {
ShaderDescription shaderDesc;
bool fromPriorityQueue = false;
bool fromOfflineList = false;
// Check the top of the queue or wait if it's empty.
{
std::unique_lock<std::mutex> queueLock(shaderCache->descQueueMutex);
shaderCache->descQueueActiveCount--;
shaderCache->descQueueChanged.wait(queueLock, [this]() {
return !threadRunning || !shaderCache->descQueue.empty() || !shaderCache->offlineList.atEnd();
return !threadRunning || !shaderCache->descQueue.empty();
});
shaderCache->descQueueActiveCount++;
@ -168,62 +53,14 @@ namespace RT64 {
shaderCache->descQueue.pop();
fromPriorityQueue = true;
}
else if (!shaderCache->offlineList.atEnd()) {
std::unique_lock<std::mutex> queueLock(shaderCache->submissionMutex);
while (!shaderCache->offlineList.atEnd() && !fromOfflineList) {
shaderCache->offlineList.step(offlineListEntry);
// Make sure the hash hasn't been submitted yet by the game. If it hasn't, mark it as such and use this entry of the list.
// Also make sure the internal color format used by the shader is compatible.
uint64_t shaderHash = offlineListEntry.shaderDesc.hash();
const bool matchesColorFormat = (offlineListEntry.shaderDesc.flags.usesHDR == shaderCache->usesHDR);
const bool hashMissing = (shaderCache->shaderHashes.find(shaderHash) == shaderCache->shaderHashes.end());
if (matchesColorFormat && hashMissing) {
shaderDesc = offlineListEntry.shaderDesc;
shaderCache->shaderHashes[shaderHash] = true;
fromOfflineList = true;
}
}
}
}
// Compile the shader at the top of the queue.
if (fromPriorityQueue || fromOfflineList) {
// Check if the shader dumper is active. Specify the shader's bytes should be stored in the thread's vectors.
std::vector<uint8_t> *shaderVsBytes = nullptr;
std::vector<uint8_t> *shaderPsBytes = nullptr;
bool useShaderBytes = false;
if (fromPriorityQueue) {
const std::unique_lock<std::mutex> lock(shaderCache->offlineDumperMutex);
if (shaderCache->offlineDumper.isDumping()) {
shaderVsBytes = &dumperVsBytes;
shaderPsBytes = &dumperPsBytes;
}
}
else {
shaderVsBytes = &offlineListEntry.vsDxilBytes;
shaderPsBytes = &offlineListEntry.psDxilBytes;
useShaderBytes = true;
}
if (fromPriorityQueue) {
assert((shaderCache->shaderUber != nullptr) && "Ubershader should've been created by the time a new shader is submitted to the cache.");
const RenderPipelineLayout *uberPipelineLayout = shaderCache->shaderUber->pipelineLayout.get();
const RenderMultisampling multisampling = shaderCache->multisampling;
std::unique_ptr<RasterShader> newShader = std::make_unique<RasterShader>(shaderCache->device, shaderDesc, uberPipelineLayout, shaderCache->shaderFormat, multisampling, shaderCache->shaderCompiler.get(), &shaderCache->optimizerCacheSPIRV, shaderVsBytes, shaderPsBytes, useShaderBytes);
// Dump the bytes of the shader if requested.
if (!useShaderBytes && (shaderVsBytes != nullptr) && (shaderPsBytes != nullptr)) {
const std::unique_lock<std::mutex> lock(shaderCache->offlineDumperMutex);
if (shaderCache->offlineDumper.isDumping()) {
shaderCache->offlineDumper.stepDumping(shaderDesc, dumperVsBytes, dumperPsBytes);
// Toggle the use of HDR and compile another shader.
ShaderDescription shaderDescAlt = shaderDesc;
shaderDescAlt.flags.usesHDR = (shaderDescAlt.flags.usesHDR == 0);
std::unique_ptr<RasterShader> altShader = std::make_unique<RasterShader>(shaderCache->device, shaderDescAlt, uberPipelineLayout, shaderCache->shaderFormat, multisampling, shaderCache->shaderCompiler.get(), &shaderCache->optimizerCacheSPIRV, shaderVsBytes, shaderPsBytes, useShaderBytes);
shaderCache->offlineDumper.stepDumping(shaderDescAlt, dumperVsBytes, dumperPsBytes);
}
}
std::unique_ptr<RasterShader> newShader = std::make_unique<RasterShader>(shaderCache->device, shaderDesc, uberPipelineLayout, shaderCache->shaderFormat, multisampling, shaderCache->shaderCompiler.get(), &shaderCache->optimizerCacheSPIRV);
{
const std::unique_lock<std::mutex> lock(shaderCache->GPUShadersMutex);
@ -338,42 +175,6 @@ namespace RT64 {
return shaderUber.get();
}
bool RasterShaderCache::isOfflineDumperActive() {
const std::unique_lock<std::mutex> lock(offlineDumperMutex);
return offlineDumper.isDumping();
}
bool RasterShaderCache::startOfflineDumper(const std::filesystem::path &path) {
const std::unique_lock<std::mutex> lock(offlineDumperMutex);
return offlineDumper.startDumping(path);
}
bool RasterShaderCache::stopOfflineDumper() {
const std::unique_lock<std::mutex> lock(offlineDumperMutex);
return offlineDumper.stopDumping();
}
bool RasterShaderCache::loadOfflineList(std::istream &stream) {
bool result = false;
{
std::unique_lock<std::mutex> queueLock(descQueueMutex);
result = offlineList.load(stream);
}
descQueueChanged.notify_all();
return result;
}
void RasterShaderCache::resetOfflineList() {
{
std::unique_lock<std::mutex> queueLock(descQueueMutex);
offlineList.reset();
}
descQueueChanged.notify_all();
}
uint32_t RasterShaderCache::shaderCount() {
std::unique_lock<std::mutex> lock(GPUShadersMutex);
return GPUShaders.size();

View File

@ -17,32 +17,6 @@
namespace RT64 {
struct RasterShaderCache {
struct OfflineList {
struct Entry {
ShaderDescription shaderDesc;
std::vector<uint8_t> vsDxilBytes;
std::vector<uint8_t> psDxilBytes;
};
std::list<Entry> entries;
std::list<Entry>::iterator entryIterator;
OfflineList();
bool load(std::istream &stream);
void reset();
void step(Entry &entry);
bool atEnd() const;
};
struct OfflineDumper {
std::ofstream dumpStream;
bool startDumping(const std::filesystem::path &path);
bool stepDumping(const ShaderDescription &shaderDesc, const std::vector<uint8_t> &vsDxilBytes, const std::vector<uint8_t> &psDxilBytes);
bool stopDumping();
bool isDumping() const;
};
struct CompilationThread {
RasterShaderCache *shaderCache;
std::unique_ptr<std::thread> thread;
@ -70,9 +44,6 @@ namespace RT64 {
RenderShaderFormat shaderFormat;
std::unique_ptr<ShaderCompiler> shaderCompiler;
RenderMultisampling multisampling;
OfflineList offlineList;
OfflineDumper offlineDumper;
std::mutex offlineDumperMutex;
bool usesHDR = false;
RasterShaderCache(uint32_t threadCount, uint32_t ubershaderThreadCount);
@ -83,11 +54,6 @@ namespace RT64 {
void destroyAll();
RasterShader *getGPUShader(const ShaderDescription &desc);
RasterShaderUber *getGPUShaderUber() const;
bool isOfflineDumperActive();
bool startOfflineDumper(const std::filesystem::path &path);
bool stopOfflineDumper();
bool loadOfflineList(std::istream &stream);
void resetOfflineList();
uint32_t shaderCount();
};
};