diff --git a/Source/Core/Common/Common.vcproj b/Source/Core/Common/Common.vcproj
index 4608f8340c..e4e7eece2f 100644
--- a/Source/Core/Common/Common.vcproj
+++ b/Source/Core/Common/Common.vcproj
@@ -720,6 +720,14 @@
RelativePath=".\Src\IniFile.h"
>
+
+
+
+
diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h
index 3250c4fe7f..45f729ea1d 100644
--- a/Source/Core/Common/Src/CommonPaths.h
+++ b/Source/Core/Common/Src/CommonPaths.h
@@ -66,6 +66,7 @@
#define GAMECONFIG_DIR "GameConfig"
#define MAPS_DIR "Maps"
#define CACHE_DIR "Cache"
+#define SHADERCACHE_DIR "ShaderCache"
#define STATESAVES_DIR "StateSaves"
#define SCREENSHOTS_DIR "ScreenShots"
#define DUMP_DIR "Dump"
@@ -128,6 +129,7 @@
#define FULL_CONFIG_DIR FULL_USERDATA_DIR CONFIG_DIR DIR_SEP
#define FULL_CACHE_DIR FULL_USERDATA_DIR CACHE_DIR DIR_SEP
+#define FULL_SHADERCACHE_DIR FULL_USERDATA_DIR SHADERCACHE_DIR DIR_SEP
#define FULL_STATESAVES_DIR FULL_USERDATA_DIR STATESAVES_DIR DIR_SEP
#define FULL_SCREENSHOTS_DIR FULL_USERDATA_DIR SCREENSHOTS_DIR DIR_SEP
#define FULL_FRAMES_DIR FULL_USERDATA_DIR DUMP_DIR DIR_SEP DUMP_FRAMES_DIR
diff --git a/Source/Core/Common/Src/LinearDiskCache.cpp b/Source/Core/Common/Src/LinearDiskCache.cpp
new file mode 100644
index 0000000000..820450bef4
--- /dev/null
+++ b/Source/Core/Common/Src/LinearDiskCache.cpp
@@ -0,0 +1,149 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "LinearDiskCache.h"
+
+static const char ID[4] = {'D', 'C', 'A', 'C'};
+const int version = 1; // TODO: Get from SVN_REV
+
+LinearDiskCache::LinearDiskCache()
+ : file_(NULL), num_entries_(0) {
+}
+
+void LinearDiskCache::WriteHeader() {
+ fwrite(ID, 4, 1, file_);
+ fwrite(&version, 4, 1, file_);
+}
+
+bool LinearDiskCache::ValidateHeader() {
+ char header_id[4];
+ int header_version;
+ fread(&header_id, 4, 1, file_);
+ fread(&header_version, 4, 1, file_);
+ if (memcmp(header_id, ID, 4) != 0)
+ return false;
+ if (header_version != version)
+ return false;
+ return true;
+}
+
+int LinearDiskCache::OpenAndRead(const char *filename, LinearDiskCacheReader *reader) {
+ int items_read_count = 0;
+ file_ = fopen(filename, "rb");
+ int file_size = 0;
+ if (file_) {
+ fseek(file_, 0, SEEK_END);
+ file_size = (int)ftell(file_);
+ }
+
+ bool file_corrupt = false;
+ if (file_size == 0) {
+ if (file_)
+ fclose(file_);
+ // Reopen for writing.
+ file_ = fopen(filename, "wb");
+ // Cache empty, let's initialize a header.
+ WriteHeader();
+ num_entries_ = 0;
+ } else {
+ // file_ must be != 0 here.
+ // Back to the start we go.
+ fseek(file_, 0, SEEK_SET);
+ // Check that the file is valid
+ if (!ValidateHeader()) {
+ // Not valid - delete the file and start over.
+ fclose(file_);
+ unlink(filename);
+
+ PanicAlert("LinearDiskCache file header broken.");
+
+ file_ = fopen(filename, "wb");
+ WriteHeader();
+ num_entries_ = 0;
+ } else {
+ // Valid - blow through it.
+ // We're past the header already thanks to ValidateHeader.
+ while (!feof(file_)) {
+ int key_size, value_size;
+ int key_size_size = fread(&key_size, 1, sizeof(key_size), file_);
+ int value_size_size = fread(&value_size, 1, sizeof(value_size), file_);
+ if (key_size_size == 0 && value_size_size == 0) {
+ // I guess feof isn't doing it's job - we're at the end.
+ break;
+ }
+ if (key_size <= 0 || value_size < 0 || key_size_size != 4 || value_size_size != 4) {
+ PanicAlert("Disk cache file %s corrupted/truncated! ks: %i vs %i kss %i vss %i", filename,
+ key_size, value_size, key_size_size, value_size_size);
+ file_corrupt = true;
+ break;
+ }
+ u8 *key = new u8[key_size];
+ u8 *value = new u8[value_size];
+ int actual_key_size = (int)fread(key, 1, key_size, file_);
+ int actual_value_size = (int)fread(value, 1, value_size, file_);
+ if (actual_key_size != key_size || actual_value_size != value_size) {
+ PanicAlert("Disk cache file %s corrupted/truncated! ks: %i actual ks: %i vs: %i actual vs: %i", filename,
+ key_size, actual_key_size, value_size, actual_value_size);
+ file_corrupt = true;
+ } else {
+ reader->Read(key, key_size, value, value_size);
+ items_read_count++;
+ }
+ delete [] key;
+ delete [] value;
+ }
+ fclose(file_);
+ // Done reading.
+
+ // Reopen file for append.
+ // At this point, ftell() will be at the end of the file,
+ // which happens to be exactly what we want.
+ file_ = fopen(filename, "ab");
+ fseek(file_, 0, SEEK_END);
+ }
+ }
+
+ if (file_corrupt) {
+ // Restore sanity, start over.
+ fclose(file_);
+ unlink(filename);
+
+ file_ = fopen(filename, "wb+");
+ WriteHeader();
+ }
+
+ return items_read_count;
+}
+
+void LinearDiskCache::Append(
+ const u8 *key, int key_size, const u8 *value, int value_size) {
+ // Should do a check that we don't already have "key"?
+ fwrite(&key_size, 1, sizeof(key_size), file_);
+ fwrite(&value_size, 1, sizeof(value_size), file_);
+ fwrite(key, 1, key_size, file_);
+ fwrite(value, 1, value_size, file_);
+}
+
+void LinearDiskCache::Sync() {
+ fflush(file_);
+}
+
+void LinearDiskCache::Close() {
+ fclose(file_);
+ file_ = 0;
+ num_entries_ = 0;
+}
diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h
new file mode 100644
index 0000000000..c2265b26a4
--- /dev/null
+++ b/Source/Core/Common/Src/LinearDiskCache.h
@@ -0,0 +1,67 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _LINEAR_DISKCACHE
+#define _LINEAR_DISKCACHE
+
+#include "Common.h"
+
+#include
+#include
+
+// On disk format:
+// uint32 'DCAC'
+// uint32 version; // svn_rev
+// uint32 key_length;
+// uint32 value_length;
+// .... key;
+// .... value;
+
+class LinearDiskCacheReader {
+public:
+ virtual void Read(const u8 *key, int key_size, const u8 *value, int value_size) = 0;
+};
+
+// Dead simple unsorted key-value store with append functionality.
+// No random read functionality, all reading is done in OpenAndRead.
+// Keys and values can contain any characters, including \0.
+//
+// Suitable for caching generated shader bytecode between executions.
+// Not tuned for extreme performance but should be reasonably fast.
+// Does not support keys or values larger than 2GB, which should be reasonable.
+// Keys must have non-zero length; values can have zero length.
+class LinearDiskCache {
+public:
+ LinearDiskCache();
+
+ // Returns the number of items read from the cache.
+ int OpenAndRead(const char *filename, LinearDiskCacheReader *reader);
+ void Close();
+ void Sync();
+
+ // Appends a key-value pair to the store.
+ void Append(const u8 *key, int key_size, const u8 *value, int value_size);
+
+private:
+ void WriteHeader();
+ bool ValidateHeader();
+
+ FILE *file_;
+ int num_entries_;
+};
+
+#endif // _LINEAR_DISKCACHE
\ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FPUtils.h
index 0f54bd9060..e4fd5f90db 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FPUtils.h
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FPUtils.h
@@ -232,8 +232,8 @@ inline u32 ConvertToSingle(u64 x)
}
else
{
- // this is said to be undefined
- // based on hardware tests
+ // This is said to be undefined.
+ // The code is based on hardware tests.
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
}
diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp
index faf0c97eff..54a433d71c 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp
+++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp
@@ -31,7 +31,7 @@ PIXELSHADERUID last_pixel_shader_uid;
// a unique identifier, basically containing all the bits. Yup, it's a lot ....
// It would likely be a lot more efficient to build this incrementally as the attributes
// are set...
-void GetPixelShaderId(PIXELSHADERUID &uid, u32 texturemask, u32 dstAlphaEnable)
+void GetPixelShaderId(PIXELSHADERUID *uid, u32 texturemask, u32 dstAlphaEnable)
{
u32 projtexcoords = 0;
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; i++)
@@ -43,7 +43,7 @@ void GetPixelShaderId(PIXELSHADERUID &uid, u32 texturemask, u32 dstAlphaEnable)
projtexcoords |= 1 << texcoord;
}
}
- uid.values[0] = (u32)bpmem.genMode.numtevstages |
+ uid->values[0] = (u32)bpmem.genMode.numtevstages |
((u32)bpmem.genMode.numindstages << 4) |
((u32)bpmem.genMode.numtexgens << 7) |
((u32)dstAlphaEnable << 11) |
@@ -51,21 +51,21 @@ void GetPixelShaderId(PIXELSHADERUID &uid, u32 texturemask, u32 dstAlphaEnable)
(projtexcoords << 20) |
((u32)bpmem.ztex2.op << 28);
- uid.values[0] = (uid.values[0] & ~0x0ff00000) | (projtexcoords << 20);
+ uid->values[0] = (uid->values[0] & ~0x0ff00000) | (projtexcoords << 20);
// swap table
for (int i = 0; i < 8; i += 2)
- ((u8*)&uid.values[1])[i / 2] = (bpmem.tevksel[i].hex & 0xf) | ((bpmem.tevksel[i + 1].hex & 0xf) << 4);
+ ((u8*)&uid->values[1])[i / 2] = (bpmem.tevksel[i].hex & 0xf) | ((bpmem.tevksel[i + 1].hex & 0xf) << 4);
- uid.values[2] = texturemask;
+ uid->values[2] = texturemask;
u32 enableZTexture = (!bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable)?1:0;
- uid.values[3] = (u32)bpmem.fog.c_proj_fsel.fsel |
+ uid->values[3] = (u32)bpmem.fog.c_proj_fsel.fsel |
((u32)bpmem.fog.c_proj_fsel.proj << 3) |
((u32)enableZTexture << 4);
int hdr = 4;
- u32* pcurvalue = &uid.values[hdr];
+ u32 *pcurvalue = &uid->values[hdr];
for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; ++i)
{
TevStageCombiner::ColorCombiner &cc = bpmem.combiners[i].colorC;
@@ -119,7 +119,7 @@ void GetPixelShaderId(PIXELSHADERUID &uid, u32 texturemask, u32 dstAlphaEnable)
if ((bpmem.genMode.numtevstages % 3) != 2)
++pcurvalue;
- uid.tevstages = (u32)(pcurvalue - &uid.values[0] - hdr);
+ uid->tevstages = (u32)(pcurvalue - &uid->values[0] - hdr);
for (u32 i = 0; i < bpmem.genMode.numindstages; ++i)
{
@@ -134,7 +134,7 @@ void GetPixelShaderId(PIXELSHADERUID &uid, u32 texturemask, u32 dstAlphaEnable)
}
// yeah, well ....
- uid.indstages = (u32)(pcurvalue - &uid.values[0] - (hdr - 1) - uid.tevstages);
+ uid->indstages = (u32)(pcurvalue - &uid->values[0] - (hdr - 1) - uid->tevstages);
}
// old tev->pixelshader notes
@@ -385,7 +385,7 @@ static void BuildSwapModeTable()
}
}
-const char *GeneratePixelShader(u32 texture_mask, bool dstAlphaEnable, u32 HLSL)
+const char *GeneratePixelShaderCode(u32 texture_mask, bool dstAlphaEnable, u32 HLSL)
{
setlocale(LC_NUMERIC, "C"); // Reset locale for compilation
text[sizeof(text) - 1] = 0x7C; // canary
diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h
index 995ea55b00..37bcdc0d9e 100644
--- a/Source/Core/VideoCommon/Src/PixelShaderGen.h
+++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h
@@ -42,6 +42,7 @@
#define C_COLORMATRIX (C_FOG + 2)
#define PIXELSHADERUID_MAX_VALUES (5 + 32 + 6 + 11)
+// DO NOT make anything in this class virtual.
class PIXELSHADERUID
{
public:
@@ -100,8 +101,9 @@ public:
}
};
-const char *GeneratePixelShader(u32 texture_mask, bool dstAlphaEnable, u32 HLSL = 0);
-void GetPixelShaderId(PIXELSHADERUID &, u32 texturemask, u32 dstAlphaEnable);
+const char *GeneratePixelShaderCode(u32 texture_mask, bool dstAlphaEnable, u32 HLSL = 0);
+void GetPixelShaderId(PIXELSHADERUID *uid, u32 texturemask, u32 dstAlphaEnable);
+
extern PIXELSHADERUID last_pixel_shader_uid;
#endif // GCOGL_PIXELSHADER_H
diff --git a/Source/Core/VideoCommon/Src/TextureConversionShader.h b/Source/Core/VideoCommon/Src/TextureConversionShader.h
index 7e81c4cc4f..e49f2a24ef 100644
--- a/Source/Core/VideoCommon/Src/TextureConversionShader.h
+++ b/Source/Core/VideoCommon/Src/TextureConversionShader.h
@@ -25,7 +25,7 @@ namespace TextureConversionShader
{
u16 GetEncodedSampleCount(u32 format);
-const char *GenerateEncodingShader(u32 format,bool HLSL = false);
+const char *GenerateEncodingShader(u32 format, bool HLSL = false);
void SetShaderParameters(float width, float height, float offsetX, float offsetY, float widthStride, float heightStride,float buffW = 0.0f,float buffH = 0.0f);
diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
index ad8d227813..934990a9f6 100644
--- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
+++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp
@@ -29,27 +29,27 @@ VERTEXSHADERUID last_vertex_shader_uid;
// Mash together all the inputs that contribute to the code of a generated vertex shader into
// a unique identifier, basically containing all the bits. Yup, it's a lot ....
-void GetVertexShaderId(VERTEXSHADERUID& vid, u32 components)
+void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components)
{
- vid.values[0] = components |
+ uid->values[0] = components |
(xfregs.numTexGens << 23) |
(xfregs.nNumChans << 27) |
((u32)xfregs.bEnableDualTexTransform << 29);
for (int i = 0; i < 2; ++i) {
- vid.values[1+i] = xfregs.colChans[i].color.enablelighting ?
+ uid->values[1+i] = xfregs.colChans[i].color.enablelighting ?
(u32)xfregs.colChans[i].color.hex :
(u32)xfregs.colChans[i].color.matsource;
- vid.values[1+i] |= (xfregs.colChans[i].alpha.enablelighting ?
+ uid->values[1+i] |= (xfregs.colChans[i].alpha.enablelighting ?
(u32)xfregs.colChans[i].alpha.hex :
(u32)xfregs.colChans[i].alpha.matsource) << 15;
}
// fog
- vid.values[1] |= (((u32)bpmem.fog.c_proj_fsel.fsel & 3) << 30);
- vid.values[2] |= (((u32)bpmem.fog.c_proj_fsel.fsel >> 2) << 30);
+ uid->values[1] |= (((u32)bpmem.fog.c_proj_fsel.fsel & 3) << 30);
+ uid->values[2] |= (((u32)bpmem.fog.c_proj_fsel.fsel >> 2) << 30);
- u32* pcurvalue = &vid.values[3];
+ u32 *pcurvalue = &uid->values[3];
for (int i = 0; i < xfregs.numTexGens; ++i) {
TexMtxInfo tinfo = xfregs.texcoords[i].texmtxinfo;
if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP)
@@ -78,16 +78,16 @@ static char text[16384];
#define LIGHTS_POS ""
-char *GenerateLightShader(char* p, int index, const LitChannel& chan, const char* dest, int coloralpha);
+char *GenerateLightShader(char *p, int index, const LitChannel& chan, const char *dest, int coloralpha);
-const char *GenerateVertexShader(u32 components, bool D3D)
+const char *GenerateVertexShaderCode(u32 components, bool D3D)
{
setlocale(LC_NUMERIC, "C"); // Reset locale for compilation
text[sizeof(text) - 1] = 0x7C; // canary
DVSTARTPROFILE();
- _assert_( bpmem.genMode.numtexgens == xfregs.numTexGens);
- _assert_( bpmem.genMode.numcolchans == xfregs.nNumChans);
+ _assert_(bpmem.genMode.numtexgens == xfregs.numTexGens);
+ _assert_(bpmem.genMode.numcolchans == xfregs.nNumChans);
u32 lightMask = 0;
if (xfregs.nNumChans > 0)
@@ -125,9 +125,8 @@ const char *GenerateVertexShader(u32 components, bool D3D)
WRITE(p, "};\n");
// uniforms
- // bool bTexMtx = ((components & VB_HAS_TEXMTXIDXALL)<shader.
+LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len)
+{
+ LPDIRECT3DVERTEXSHADER9 v_shader;
+ HRESULT hr = D3D::dev->CreateVertexShader((DWORD *)bytecode, &v_shader);
+ if (FAILED(hr))
+ v_shader = 0;
+ return v_shader;
+}
+
+// Code->bytecode.
+bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen)
{
//try to compile
LPD3DXBUFFER shaderBuffer = 0;
LPD3DXBUFFER errorBuffer = 0;
- LPDIRECT3DVERTEXSHADER9 vShader = 0;
HRESULT hr = D3DXCompileShader(code, len, 0, 0, "main", D3D::VertexShaderVersionString(),
0, &shaderBuffer, &errorBuffer, 0);
if (FAILED(hr))
@@ -39,20 +49,16 @@ LPDIRECT3DVERTEXSHADER9 CompileVertexShader(const char *code, int len)
std::string hello = (char*)errorBuffer->GetBufferPointer();
hello += "\n\n";
hello += code;
- MessageBoxA(0, hello.c_str(), "Error assembling vertex shader", MB_ICONERROR);
+ MessageBoxA(0, hello.c_str(), "Error compiling vertex shader", MB_ICONERROR);
}
- vShader = 0;
+ *bytecode = 0;
+ *bytecodelen = 0;
}
else if (SUCCEEDED(hr))
{
- //create it
- HRESULT hr = E_FAIL;
- if (shaderBuffer)
- hr = D3D::dev->CreateVertexShader((DWORD *)shaderBuffer->GetBufferPointer(), &vShader);
- if ((FAILED(hr) || vShader == 0) && g_ActiveConfig.bShowShaderErrors)
- {
- MessageBoxA(0, code, (char*)errorBuffer->GetBufferPointer(), MB_ICONERROR);
- }
+ *bytecodelen = shaderBuffer->GetBufferSize();
+ *bytecode = new u8[*bytecodelen];
+ memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen);
}
//cleanup
@@ -60,14 +66,25 @@ LPDIRECT3DVERTEXSHADER9 CompileVertexShader(const char *code, int len)
shaderBuffer->Release();
if (errorBuffer)
errorBuffer->Release();
- return vShader;
+ return SUCCEEDED(hr) ? true : false;
}
-LPDIRECT3DPIXELSHADER9 CompilePixelShader(const char *code, int len)
+
+// Bytecode->shader.
+LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len)
+{
+ LPDIRECT3DPIXELSHADER9 p_shader;
+ HRESULT hr = D3D::dev->CreatePixelShader((DWORD *)bytecode, &p_shader);
+ if (FAILED(hr))
+ p_shader = 0;
+ return p_shader;
+}
+
+
+bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen)
{
LPD3DXBUFFER shaderBuffer = 0;
LPD3DXBUFFER errorBuffer = 0;
- LPDIRECT3DPIXELSHADER9 pShader = 0;
// Someone:
// For some reason, I had this kind of errors : "Shader uses texture addressing operations
@@ -81,18 +98,16 @@ LPDIRECT3DPIXELSHADER9 CompilePixelShader(const char *code, int len)
std::string hello = (char*)errorBuffer->GetBufferPointer();
hello += "\n\n";
hello += code;
- MessageBoxA(0, hello.c_str(), "Error assembling pixel shader", MB_ICONERROR);
+ MessageBoxA(0, hello.c_str(), "Error compiling pixel shader", MB_ICONERROR);
}
- pShader = 0;
+ *bytecode = 0;
+ *bytecodelen = 0;
}
- else
+ else if (SUCCEEDED(hr))
{
- //create it
- HRESULT hr = D3D::dev->CreatePixelShader((DWORD *)shaderBuffer->GetBufferPointer(), &pShader);
- if ((FAILED(hr) || pShader == 0) && g_ActiveConfig.bShowShaderErrors)
- {
- MessageBoxA(0, "damn", "error creating pixelshader", MB_ICONERROR);
- }
+ *bytecodelen = shaderBuffer->GetBufferSize();
+ *bytecode = new u8[*bytecodelen];
+ memcpy(*bytecode, shaderBuffer->GetBufferPointer(), *bytecodelen);
}
//cleanup
@@ -100,7 +115,31 @@ LPDIRECT3DPIXELSHADER9 CompilePixelShader(const char *code, int len)
shaderBuffer->Release();
if (errorBuffer)
errorBuffer->Release();
- return pShader;
+ return SUCCEEDED(hr) ? true : false;
+}
+
+LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len) {
+ u8 *bytecode;
+ int bytecodelen;
+ if (CompileVertexShader(code, len, &bytecode, &bytecodelen)) {
+ LPDIRECT3DVERTEXSHADER9 v_shader = CreateVertexShaderFromByteCode(bytecode, len);
+ delete [] bytecode;
+ return v_shader;
+ } else {
+ return 0;
+ }
+}
+
+LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len) {
+ u8 *bytecode;
+ int bytecodelen;
+ if (CompilePixelShader(code, len, &bytecode, &bytecodelen)) {
+ LPDIRECT3DPIXELSHADER9 p_shader = CreatePixelShaderFromByteCode(bytecode, len);
+ delete [] bytecode;
+ return p_shader;
+ } else {
+ return 0;
+ }
}
} // namespace
diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DShader.h b/Source/Plugins/Plugin_VideoDX9/Src/D3DShader.h
index 21cfb55cc1..4354f0965c 100644
--- a/Source/Plugins/Plugin_VideoDX9/Src/D3DShader.h
+++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DShader.h
@@ -21,6 +21,14 @@
namespace D3D
{
- LPDIRECT3DVERTEXSHADER9 CompileVertexShader(const char *code, int len);
- LPDIRECT3DPIXELSHADER9 CompilePixelShader(const char *code, int len);
+ LPDIRECT3DVERTEXSHADER9 CreateVertexShaderFromByteCode(const u8 *bytecode, int len);
+ LPDIRECT3DPIXELSHADER9 CreatePixelShaderFromByteCode(const u8 *bytecode, int len);
+
+ // The returned bytecode buffers should be delete[]-d.
+ bool CompileVertexShader(const char *code, int len, u8 **bytecode, int *bytecodelen);
+ bool CompilePixelShader(const char *code, int len, u8 **bytecode, int *bytecodelen);
+
+ // Utility functions
+ LPDIRECT3DVERTEXSHADER9 CompileAndCreateVertexShader(const char *code, int len);
+ LPDIRECT3DPIXELSHADER9 CompileAndCreatePixelShader(const char *code, int len);
}
\ No newline at end of file
diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp
index 145eb6e11e..d696033e33 100644
--- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp
+++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp
@@ -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()
{
diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h
index 2deeeacc64..8b4ab8d8fb 100644
--- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h
+++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.h
@@ -18,6 +18,8 @@
#ifndef _PIXELSHADERCACHE_H
#define _PIXELSHADERCACHE_H
+#include "Common.h"
+#include "LinearDiskCache.h"
#include "D3DBase.h"
#include