mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
Shader Disk Cache implementation for D3D. Saves generated shaders on disk. Eliminates "freeze jerks" in D3D plugin the _second_ and later times you play something.... not much to do about the first time. The D3D shader compiler is just slow.
Also assorted cleanup around the shader code. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4869 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -15,11 +15,15 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "LinearDiskCache.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "Statistics.h"
|
||||
#include "Utils.h"
|
||||
#include "Profiler.h"
|
||||
#include "VideoConfig.h"
|
||||
#include "PixelShaderGen.h"
|
||||
#include "PixelShaderManager.h"
|
||||
@ -29,10 +33,13 @@
|
||||
#include "XFMemory.h"
|
||||
#include "ImageWrite.h"
|
||||
|
||||
#include "debugger/debugger.h"
|
||||
#include "Debugger/Debugger.h"
|
||||
|
||||
PixelShaderCache::PSCache PixelShaderCache::PixelShaders;
|
||||
const PixelShaderCache::PSCacheEntry *PixelShaderCache::last_entry;
|
||||
|
||||
LinearDiskCache g_ps_disk_cache;
|
||||
|
||||
static float lastPSconstants[C_COLORMATRIX+16][4];
|
||||
|
||||
static LPDIRECT3DPIXELSHADER9 s_ColorMatrixProgram = 0;
|
||||
@ -41,7 +48,6 @@ static LPDIRECT3DPIXELSHADER9 s_ClearProgram = 0;
|
||||
static LPDIRECT3DPIXELSHADER9 s_ClearZProgram = 0;
|
||||
static LPDIRECT3DPIXELSHADER9 s_DepthMatrixProgram = 0;
|
||||
|
||||
|
||||
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorMatrixProgram()
|
||||
{
|
||||
return s_ColorMatrixProgram;
|
||||
@ -64,7 +70,7 @@ LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetClearProgram()
|
||||
|
||||
void SetPSConstant4f(int const_number, float f1, float f2, float f3, float f4)
|
||||
{
|
||||
if( lastPSconstants[const_number][0] != f1 || lastPSconstants[const_number][1] != f2 ||
|
||||
if (lastPSconstants[const_number][0] != f1 || lastPSconstants[const_number][1] != f2 ||
|
||||
lastPSconstants[const_number][2] != f3 || lastPSconstants[const_number][3] != f4 )
|
||||
{
|
||||
const float f[4] = {f1, f2, f3, f4};
|
||||
@ -78,7 +84,7 @@ void SetPSConstant4f(int const_number, float f1, float f2, float f3, float f4)
|
||||
|
||||
void SetPSConstant4fv(int const_number, const float *f)
|
||||
{
|
||||
if( lastPSconstants[const_number][0] != f[0] || lastPSconstants[const_number][1] != f[1] ||
|
||||
if (lastPSconstants[const_number][0] != f[0] || lastPSconstants[const_number][1] != f[1] ||
|
||||
lastPSconstants[const_number][2] != f[2] || lastPSconstants[const_number][3] != f[3] )
|
||||
{
|
||||
D3D::dev->SetPixelShaderConstantF(const_number, f, 1);
|
||||
@ -89,25 +95,39 @@ void SetPSConstant4fv(int const_number, const float *f)
|
||||
}
|
||||
}
|
||||
|
||||
class PixelShaderCacheInserter : public LinearDiskCacheReader {
|
||||
public:
|
||||
void Read(const u8 *key, int key_size, const u8 *value, int value_size)
|
||||
{
|
||||
PIXELSHADERUID uid;
|
||||
if (key_size != sizeof(uid)) {
|
||||
ERROR_LOG(VIDEO, "Wrong key size in pixel shader cache");
|
||||
return;
|
||||
}
|
||||
memcpy(&uid, key, key_size);
|
||||
PixelShaderCache::InsertByteCode(uid, value, value_size, false);
|
||||
}
|
||||
};
|
||||
|
||||
void PixelShaderCache::Init()
|
||||
{
|
||||
char pprog[1024];
|
||||
sprintf(pprog,"void main(\n"
|
||||
sprintf(pprog, "void main(\n"
|
||||
"out float4 ocol0 : COLOR0,\n"
|
||||
" in float4 incol0 : COLOR0){\n"
|
||||
"ocol0 = incol0;\n"
|
||||
"}\n");
|
||||
s_ClearProgram = D3D::CompilePixelShader(pprog, (int)strlen(pprog));
|
||||
s_ClearProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
||||
|
||||
sprintf(pprog,"uniform sampler samp0 : register(s0);\n"
|
||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : COLOR0,\n"
|
||||
" in float3 uv0 : TEXCOORD0){\n"
|
||||
"ocol0 = tex2D(samp0,uv0.xy);\n"
|
||||
"}\n");
|
||||
s_ColorCopyProgram = D3D::CompilePixelShader(pprog, (int)strlen(pprog));
|
||||
s_ColorCopyProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
||||
|
||||
sprintf(pprog,"uniform sampler samp0 : register(s0);\n"
|
||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : COLOR0,\n"
|
||||
@ -115,9 +135,9 @@ void PixelShaderCache::Init()
|
||||
"float4 texcol = tex2D(samp0,uv0.xy);\n"
|
||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
||||
"}\n",C_COLORMATRIX);
|
||||
s_ColorMatrixProgram = D3D::CompilePixelShader(pprog, (int)strlen(pprog));
|
||||
s_ColorMatrixProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
||||
|
||||
sprintf(pprog,"uniform sampler samp0 : register(s0);\n"
|
||||
sprintf(pprog, "uniform sampler samp0 : register(s0);\n"
|
||||
"uniform float4 cColMatrix[5] : register(c%d);\n"
|
||||
"void main(\n"
|
||||
"out float4 ocol0 : COLOR0,\n"
|
||||
@ -127,10 +147,19 @@ void PixelShaderCache::Init()
|
||||
"texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
|
||||
"ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
|
||||
"}\n",C_COLORMATRIX);
|
||||
s_DepthMatrixProgram = D3D::CompilePixelShader(pprog, (int)strlen(pprog));
|
||||
s_DepthMatrixProgram = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
|
||||
Clear();
|
||||
|
||||
if (!File::Exists(FULL_SHADERCACHE_DIR))
|
||||
File::CreateDir(FULL_SHADERCACHE_DIR);
|
||||
|
||||
char cache_filename[MAX_PATH];
|
||||
sprintf(cache_filename, "%s%s-ps.cache", FULL_SHADERCACHE_DIR, globals->unique_id);
|
||||
PixelShaderCacheInserter inserter;
|
||||
int read_items = g_ps_disk_cache.OpenAndRead(cache_filename, &inserter);
|
||||
}
|
||||
|
||||
// ONLY to be used during shutdown.
|
||||
void PixelShaderCache::Clear()
|
||||
{
|
||||
PSCache::iterator iter = PixelShaders.begin();
|
||||
@ -139,45 +168,44 @@ void PixelShaderCache::Clear()
|
||||
PixelShaders.clear();
|
||||
|
||||
for (int i = 0; i < (C_COLORMATRIX + 16) * 4; i++)
|
||||
lastPSconstants[i/4][i%4] = -100000000.0f;
|
||||
lastPSconstants[i / 4][i % 4] = -100000000.0f;
|
||||
memset(&last_pixel_shader_uid, 0xFF, sizeof(last_pixel_shader_uid));
|
||||
}
|
||||
|
||||
void PixelShaderCache::Shutdown()
|
||||
{
|
||||
if(s_ColorMatrixProgram)
|
||||
s_ColorMatrixProgram->Release();
|
||||
if (s_ColorMatrixProgram) s_ColorMatrixProgram->Release();
|
||||
s_ColorMatrixProgram = NULL;
|
||||
if(s_ColorCopyProgram)
|
||||
s_ColorCopyProgram->Release();
|
||||
s_ColorCopyProgram=NULL;
|
||||
if(s_DepthMatrixProgram)
|
||||
s_DepthMatrixProgram->Release();
|
||||
if (s_ColorCopyProgram) s_ColorCopyProgram->Release();
|
||||
s_ColorCopyProgram = NULL;
|
||||
if (s_DepthMatrixProgram) s_DepthMatrixProgram->Release();
|
||||
s_DepthMatrixProgram = NULL;
|
||||
if(s_ClearProgram)
|
||||
s_ClearProgram->Release();
|
||||
s_ClearProgram=NULL;
|
||||
if (s_ClearProgram) s_ClearProgram->Release();
|
||||
s_ClearProgram = NULL;
|
||||
|
||||
Clear();
|
||||
g_ps_disk_cache.Sync();
|
||||
g_ps_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool PixelShaderCache::SetShader(bool dstAlpha)
|
||||
{
|
||||
DVSTARTPROFILE();
|
||||
|
||||
PIXELSHADERUID uid;
|
||||
GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), dstAlpha);
|
||||
GetPixelShaderId(&uid, PixelShaderManager::GetTextureMask(), dstAlpha);
|
||||
|
||||
// Is the shader already set?
|
||||
if (uid == last_pixel_shader_uid && PixelShaders[uid].frameCount == frameCount)
|
||||
{
|
||||
PSCache::const_iterator iter = PixelShaders.find(uid);
|
||||
if (iter != PixelShaders.end() && iter->second.shader)
|
||||
return true;
|
||||
return true; // Sure, we're done.
|
||||
else
|
||||
return false;
|
||||
return false; // ?? something is wrong.
|
||||
}
|
||||
|
||||
memcpy(&last_pixel_shader_uid, &uid, sizeof(PIXELSHADERUID));
|
||||
|
||||
// Is the shader already in the cache?
|
||||
PSCache::iterator iter;
|
||||
iter = PixelShaders.find(uid);
|
||||
if (iter != PixelShaders.end())
|
||||
@ -186,7 +214,6 @@ bool PixelShaderCache::SetShader(bool dstAlpha)
|
||||
const PSCacheEntry &entry = iter->second;
|
||||
last_entry = &entry;
|
||||
|
||||
|
||||
DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true);
|
||||
|
||||
if (entry.shader)
|
||||
@ -198,7 +225,8 @@ bool PixelShaderCache::SetShader(bool dstAlpha)
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), dstAlpha, 2);
|
||||
// OK, need to generate and compile it.
|
||||
const char *code = GeneratePixelShaderCode(PixelShaderManager::GetTextureMask(), dstAlpha, 2);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) {
|
||||
static int counter = 0;
|
||||
@ -208,7 +236,29 @@ bool PixelShaderCache::SetShader(bool dstAlpha)
|
||||
SaveData(szTemp, code);
|
||||
}
|
||||
#endif
|
||||
LPDIRECT3DPIXELSHADER9 shader = D3D::CompilePixelShader(code, (int)strlen(code));
|
||||
|
||||
u8 *bytecode = 0;
|
||||
int bytecodelen = 0;
|
||||
if (!D3D::CompilePixelShader(code, (int)strlen(code), &bytecode, &bytecodelen)) {
|
||||
if (g_ActiveConfig.bShowShaderErrors)
|
||||
{
|
||||
PanicAlert("Failed to compile Pixel Shader:\n\n%s", code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here we have the UID and the byte code. Insert it into the disk cache.
|
||||
g_ps_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen);
|
||||
g_ps_disk_cache.Sync();
|
||||
|
||||
// And insert it into the shader cache.
|
||||
bool result = InsertByteCode(uid, bytecode, bytecodelen, true);
|
||||
delete [] bytecode;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) {
|
||||
LPDIRECT3DPIXELSHADER9 shader = D3D::CreatePixelShaderFromByteCode(bytecode, bytecodelen);
|
||||
|
||||
// Make an entry in the table
|
||||
PSCacheEntry newentry;
|
||||
@ -220,44 +270,21 @@ bool PixelShaderCache::SetShader(bool dstAlpha)
|
||||
PixelShaders[uid] = newentry;
|
||||
last_entry = &PixelShaders[uid];
|
||||
|
||||
if (!shader) {
|
||||
// INCSTAT(stats.numPixelShadersFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
INCSTAT(stats.numPixelShadersCreated);
|
||||
SETSTAT(stats.numPixelShadersAlive, (int)PixelShaders.size());
|
||||
if (shader)
|
||||
if (activate)
|
||||
{
|
||||
D3D::SetPixelShader(shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bShowShaderErrors)
|
||||
{
|
||||
PanicAlert("Failed to compile Pixel Shader:\n\n%s", code);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PixelShaderCache::Cleanup()
|
||||
{
|
||||
/*
|
||||
PSCache::iterator iter;
|
||||
iter = PixelShaders.begin();
|
||||
while (iter != PixelShaders.end())
|
||||
{
|
||||
PSCacheEntry &entry = iter->second;
|
||||
if (entry.frameCount < frameCount - 1400)
|
||||
{
|
||||
entry.Destroy();
|
||||
iter = PixelShaders.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
SETSTAT(stats.numPixelShadersAlive, (int)PixelShaders.size());
|
||||
*/
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
std::string PixelShaderCache::GetCurrentShaderCode()
|
||||
{
|
||||
|
Reference in New Issue
Block a user