mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-22 22:46:41 +00:00
Extract out shader caching from D3D to common code
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "os/os_specific.h"
|
||||
|
||||
template<typename ResultType, typename ShaderCallbacks>
|
||||
bool LoadShaderCache(const char *filename,
|
||||
const uint32_t magicNumber, const uint32_t versionNumber,
|
||||
std::map<uint32_t,ResultType> &resultCache,
|
||||
const ShaderCallbacks &callbacks)
|
||||
{
|
||||
string shadercache = FileIO::GetAppFolderFilename(filename);
|
||||
|
||||
FILE *f = FileIO::fopen(shadercache.c_str(), "rb");
|
||||
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
FileIO::fseek64(f, 0, SEEK_END);
|
||||
uint64_t cachelen = FileIO::ftell64(f);
|
||||
FileIO::fseek64(f, 0, SEEK_SET);
|
||||
|
||||
bool ret = true;
|
||||
|
||||
// header: magic number, file version, number of entries
|
||||
if(cachelen < sizeof(uint32_t)*3)
|
||||
{
|
||||
RDCERR("Invalid shader cache");
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte *cache = new byte[(size_t)cachelen];
|
||||
FileIO::fread(cache, 1, (size_t)cachelen, f);
|
||||
|
||||
uint32_t *header = (uint32_t *)cache;
|
||||
|
||||
uint32_t fileMagic = header[0];
|
||||
uint32_t fileVer = header[1];
|
||||
|
||||
if(fileMagic != magicNumber || fileVer != versionNumber)
|
||||
{
|
||||
RDCDEBUG("Out of date or invalid shader cache magic: %d version: %d", fileMagic, fileVer);
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t numentries = header[2];
|
||||
|
||||
byte *ptr = cache+sizeof(uint32_t)*3;
|
||||
|
||||
int64_t bufsize = (int64_t)cachelen-sizeof(uint32_t)*3;
|
||||
|
||||
for(uint32_t i=0; i < numentries; i++)
|
||||
{
|
||||
if(bufsize < sizeof(uint32_t))
|
||||
{
|
||||
RDCERR("Invalid shader cache - truncated, not enough data for shader hash");
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t hash = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t);
|
||||
|
||||
if(bufsize < sizeof(uint32_t))
|
||||
{
|
||||
RDCERR("Invalid shader cache - truncated, not enough data for shader length");
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t len = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t);
|
||||
|
||||
if(bufsize < len)
|
||||
{
|
||||
RDCERR("Invalid shader cache - truncated, not enough data for shader buffer");
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
byte *data = ptr; ptr += len; bufsize -= len;
|
||||
|
||||
ResultType result;
|
||||
bool created = callbacks.Create(len, data, &result);
|
||||
|
||||
if(!created)
|
||||
{
|
||||
RDCERR("Couldn't create blob of size %u from shadercache", len);
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
resultCache[hash] = result;
|
||||
}
|
||||
|
||||
if(ret == true && bufsize != 0)
|
||||
{
|
||||
RDCERR("Invalid shader cache - trailing data");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
RDCDEBUG("Successfully loaded %d shaders from shader cache", resultCache.size());
|
||||
}
|
||||
|
||||
delete[] cache;
|
||||
}
|
||||
|
||||
FileIO::fclose(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename ResultType, typename ShaderCallbacks>
|
||||
void SaveShaderCache(const char *filename,
|
||||
uint32_t magicNumber, uint32_t versionNumber,
|
||||
const std::map<uint32_t,ResultType> &cache,
|
||||
const ShaderCallbacks &callbacks)
|
||||
{
|
||||
string shadercache = FileIO::GetAppFolderFilename(filename);
|
||||
|
||||
FILE *f = FileIO::fopen(shadercache.c_str(), "wb");
|
||||
|
||||
if(!f)
|
||||
{
|
||||
RDCERR("Error opening shader cache for write");
|
||||
return;
|
||||
}
|
||||
|
||||
FileIO::fwrite(&magicNumber, 1, sizeof(magicNumber), f);
|
||||
FileIO::fwrite(&versionNumber, 1, sizeof(versionNumber), f);
|
||||
uint32_t numentries = (uint32_t)cache.size();
|
||||
FileIO::fwrite(&numentries, 1, sizeof(numentries), f);
|
||||
|
||||
auto it = cache.begin();
|
||||
for(auto it = cache.begin(); it != cache.end(); ++it)
|
||||
{
|
||||
uint32_t hash = it->first;
|
||||
uint32_t len = callbacks.GetSize(it->second);
|
||||
byte *data = callbacks.GetData(it->second);
|
||||
FileIO::fwrite(&hash, 1, sizeof(hash), f);
|
||||
FileIO::fwrite(&len, 1, sizeof(len), f);
|
||||
FileIO::fwrite(data, 1, len, f);
|
||||
|
||||
callbacks.Destroy(it->second);
|
||||
}
|
||||
|
||||
FileIO::fclose(f);
|
||||
|
||||
RDCDEBUG("Successfully wrote %u shaders to shader cache", numentries);
|
||||
}
|
||||
@@ -33,6 +33,8 @@
|
||||
#include "serialise/string_utils.h"
|
||||
#include "maths/formatpacking.h"
|
||||
|
||||
#include "common/shader_cache.h"
|
||||
|
||||
#include "driver/d3d11/d3d11_resources.h"
|
||||
|
||||
#include "d3d11_renderstate.h"
|
||||
@@ -95,6 +97,59 @@ DXGI_FORMAT GetTypedFormatUIntPreferred(DXGI_FORMAT f)
|
||||
return f;
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T Size, ID3DBlob** ppBlob);
|
||||
|
||||
struct D3DBlobShaderCallbacks
|
||||
{
|
||||
D3DBlobShaderCallbacks()
|
||||
{
|
||||
HMODULE d3dcompiler = GetD3DCompiler();
|
||||
|
||||
if(d3dcompiler == NULL)
|
||||
RDCFATAL("Can't get handle to d3dcompiler_??.dll");
|
||||
|
||||
m_BlobCreate = (pD3DCreateBlob)GetProcAddress(d3dcompiler, "D3DCreateBlob");
|
||||
|
||||
if(m_BlobCreate == NULL)
|
||||
RDCFATAL("d3dcompiler.dll doesn't contain D3DCreateBlob");
|
||||
}
|
||||
|
||||
bool Create(uint32_t size, byte *data, ID3DBlob **ret) const
|
||||
{
|
||||
RDCASSERT(ret);
|
||||
|
||||
*ret = NULL;
|
||||
HRESULT hr = m_BlobCreate((SIZE_T)size, ret);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create blob of size %u from shadercache: %08x", size, hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy((*ret)->GetBufferPointer(), data, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Destroy(ID3DBlob *blob) const
|
||||
{
|
||||
blob->Release();
|
||||
}
|
||||
|
||||
uint32_t GetSize(ID3DBlob *blob) const
|
||||
{
|
||||
return (uint32_t)blob->GetBufferSize();
|
||||
}
|
||||
|
||||
byte *GetData(ID3DBlob *blob) const
|
||||
{
|
||||
return (byte *)blob->GetBufferPointer();
|
||||
}
|
||||
|
||||
pD3DCreateBlob m_BlobCreate;
|
||||
} ShaderCacheCallbacks;
|
||||
|
||||
D3D11DebugManager::D3D11DebugManager(WrappedID3D11Device *wrapper)
|
||||
{
|
||||
if(RenderDoc::Inst().GetCrashHandler())
|
||||
@@ -152,119 +207,10 @@ D3D11DebugManager::D3D11DebugManager(WrappedID3D11Device *wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
string shadercache = FileIO::GetAppFolderFilename("shaders.cache");
|
||||
bool success = LoadShaderCache("d3dshaders.cache", m_ShaderCacheMagic, m_ShaderCacheVersion, m_ShaderCache, ShaderCacheCallbacks);
|
||||
|
||||
m_ShaderCacheDirty = true;
|
||||
|
||||
FILE *f = FileIO::fopen(shadercache.c_str(), "rb");
|
||||
if(f)
|
||||
{
|
||||
FileIO::fseek64(f, 0, SEEK_END);
|
||||
uint64_t cachelen = FileIO::ftell64(f);
|
||||
FileIO::fseek64(f, 0, SEEK_SET);
|
||||
|
||||
if(cachelen < 8)
|
||||
{
|
||||
RDCERR("Invalid shader cache");
|
||||
m_ShaderCacheDirty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte *cache = new byte[(size_t)cachelen];
|
||||
FileIO::fread(cache, 1, (size_t)cachelen, f);
|
||||
|
||||
uint32_t *header = (uint32_t *)cache;
|
||||
|
||||
uint32_t version = header[0];
|
||||
|
||||
if(version != m_ShaderCacheVersion)
|
||||
{
|
||||
RDCDEBUG("Out of date or invalid shader cache version: %d", version);
|
||||
m_ShaderCacheDirty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t numentries = header[1];
|
||||
|
||||
byte *ptr = cache+sizeof(uint32_t)*2;
|
||||
|
||||
int64_t bufsize = (int64_t)cachelen-sizeof(uint32_t)*2;
|
||||
|
||||
HMODULE d3dcompiler = GetD3DCompiler();
|
||||
|
||||
if(d3dcompiler == NULL)
|
||||
{
|
||||
RDCFATAL("Can't get handle to d3dcompiler_??.dll");
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *pD3DCreateBlob)(SIZE_T Size, ID3DBlob** ppBlob);
|
||||
|
||||
pD3DCreateBlob blobCreate = (pD3DCreateBlob)GetProcAddress(d3dcompiler, "D3DCreateBlob");
|
||||
|
||||
if(blobCreate == NULL)
|
||||
{
|
||||
RDCFATAL("Can't get D3DCreateBlob from d3dcompiler_??.dll");
|
||||
}
|
||||
|
||||
m_ShaderCacheDirty = false;
|
||||
|
||||
for(uint32_t i=0; i < numentries; i++)
|
||||
{
|
||||
if(bufsize < sizeof(uint32_t))
|
||||
{
|
||||
RDCERR("Invalid shader cache");
|
||||
m_ShaderCacheDirty = true;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t hash = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t);
|
||||
|
||||
if(bufsize < sizeof(uint32_t))
|
||||
{
|
||||
RDCERR("Invalid shader cache");
|
||||
m_ShaderCacheDirty = true;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t len = *(uint32_t *)ptr; ptr += sizeof(uint32_t); bufsize -= sizeof(uint32_t);
|
||||
|
||||
if(bufsize < len)
|
||||
{
|
||||
RDCERR("Invalid shader cache");
|
||||
m_ShaderCacheDirty = true;
|
||||
break;
|
||||
}
|
||||
|
||||
byte *data = ptr; ptr += len; bufsize -= len;
|
||||
|
||||
ID3DBlob *blob = NULL;
|
||||
hr = blobCreate((SIZE_T)len, &blob);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create blob of size %d from shadercache: %08x", len, hr);
|
||||
m_ShaderCacheDirty = true;
|
||||
}
|
||||
|
||||
memcpy(blob->GetBufferPointer(), data, len);
|
||||
|
||||
m_ShaderCache[hash] = blob;
|
||||
}
|
||||
|
||||
if(bufsize != 0)
|
||||
{
|
||||
RDCERR("Invalid shader cache");
|
||||
m_ShaderCacheDirty = true;
|
||||
}
|
||||
|
||||
RDCDEBUG("Successfully loaded %d shaders from shader cache", m_ShaderCache.size());
|
||||
}
|
||||
|
||||
delete[] cache;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
// if we failed to load from the cache
|
||||
m_ShaderCacheDirty = !success;
|
||||
|
||||
m_CacheShaders = true;
|
||||
|
||||
@@ -284,39 +230,7 @@ D3D11DebugManager::~D3D11DebugManager()
|
||||
PreDeviceShutdownCounters();
|
||||
|
||||
if(m_ShaderCacheDirty)
|
||||
{
|
||||
string shadercache = FileIO::GetAppFolderFilename("shaders.cache");
|
||||
|
||||
FILE *f = FileIO::fopen(shadercache.c_str(), "wb");
|
||||
if(f)
|
||||
{
|
||||
uint32_t version = m_ShaderCacheVersion;
|
||||
FileIO::fwrite(&version, 1, sizeof(version), f);
|
||||
uint32_t numentries = (uint32_t)m_ShaderCache.size();
|
||||
FileIO::fwrite(&numentries, 1, sizeof(numentries), f);
|
||||
|
||||
auto it = m_ShaderCache.begin();
|
||||
for(uint32_t i=0; i < numentries; i++)
|
||||
{
|
||||
uint32_t hash = it->first;
|
||||
uint32_t len = (uint32_t)it->second->GetBufferSize();
|
||||
FileIO::fwrite(&hash, 1, sizeof(hash), f);
|
||||
FileIO::fwrite(&len, 1, sizeof(len), f);
|
||||
FileIO::fwrite(it->second->GetBufferPointer(), 1, len, f);
|
||||
|
||||
it->second->Release();
|
||||
++it;
|
||||
}
|
||||
|
||||
RDCDEBUG("Successfully wrote %d shaders to shader cache", m_ShaderCache.size());
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Error opening shader cache for write");
|
||||
}
|
||||
}
|
||||
SaveShaderCache("d3dshaders.cache", m_ShaderCacheMagic, m_ShaderCacheVersion, m_ShaderCache, ShaderCacheCallbacks);
|
||||
|
||||
ShutdownFontRendering();
|
||||
ShutdownStreamOut();
|
||||
|
||||
@@ -294,7 +294,9 @@ class D3D11DebugManager
|
||||
uint64_t m_OutputWindowID;
|
||||
map<uint64_t, OutputWindow> m_OutputWindows;
|
||||
|
||||
static const uint32_t m_ShaderCacheVersion = 2;
|
||||
static const uint32_t m_ShaderCacheMagic = 0xf000baba;
|
||||
static const uint32_t m_ShaderCacheVersion = 3;
|
||||
|
||||
bool m_ShaderCacheDirty, m_CacheShaders;
|
||||
map<uint32_t, ID3DBlob*> m_ShaderCache;
|
||||
|
||||
|
||||
@@ -241,6 +241,7 @@
|
||||
<ClInclude Include="common\common.h" />
|
||||
<ClInclude Include="common\dds_readwrite.h" />
|
||||
<ClInclude Include="common\globalconfig.h" />
|
||||
<ClInclude Include="common\shader_cache.h" />
|
||||
<ClInclude Include="common\threading.h" />
|
||||
<ClInclude Include="common\timing.h" />
|
||||
<ClInclude Include="common\wrapped_pool.h" />
|
||||
|
||||
@@ -228,6 +228,9 @@
|
||||
<ClInclude Include="api\replay\vk_pipestate.h">
|
||||
<Filter>API\Replay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="common\shader_cache.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="maths\camera.cpp">
|
||||
|
||||
Reference in New Issue
Block a user