mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 00:59:44 -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:
@ -112,7 +112,11 @@ struct Resolution
|
||||
|
||||
struct AALevel
|
||||
{
|
||||
AALevel(const char *n, D3DMULTISAMPLE_TYPE m, int q) {strcpy(name, n); ms_setting=m; qual_setting=q;}
|
||||
AALevel(const char *n, D3DMULTISAMPLE_TYPE m, int q) {
|
||||
strcpy(name, n);
|
||||
ms_setting = m;
|
||||
qual_setting = q;
|
||||
}
|
||||
char name[32];
|
||||
D3DMULTISAMPLE_TYPE ms_setting;
|
||||
int qual_setting;
|
||||
|
@ -24,12 +24,22 @@
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
LPDIRECT3DVERTEXSHADER9 CompileVertexShader(const char *code, int len)
|
||||
// Bytecode->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
|
||||
|
@ -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);
|
||||
}
|
@ -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()
|
||||
{
|
||||
|
@ -18,6 +18,8 @@
|
||||
#ifndef _PIXELSHADERCACHE_H
|
||||
#define _PIXELSHADERCACHE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "LinearDiskCache.h"
|
||||
#include "D3DBase.h"
|
||||
|
||||
#include <map>
|
||||
@ -53,12 +55,13 @@ private:
|
||||
static PSCache PixelShaders;
|
||||
static const PSCacheEntry *last_entry;
|
||||
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
static void Cleanup();
|
||||
static void Clear();
|
||||
static void Shutdown();
|
||||
static bool SetShader(bool dstAlpha);
|
||||
static bool InsertByteCode(const PIXELSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate);
|
||||
static LPDIRECT3DPIXELSHADER9 GetColorMatrixProgram();
|
||||
static LPDIRECT3DPIXELSHADER9 GetColorCopyProgram();
|
||||
static LPDIRECT3DPIXELSHADER9 GetDepthMatrixProgram();
|
||||
|
@ -272,7 +272,7 @@ bool Renderer::Init()
|
||||
|
||||
xScale = (float)s_target_width / (float)EFB_WIDTH;
|
||||
yScale = (float)s_target_height / (float)EFB_HEIGHT;
|
||||
if(!D3D::IsATIDevice())
|
||||
if (!D3D::IsATIDevice())
|
||||
{
|
||||
FULL_EFB_WIDTH = 2 * EFB_WIDTH;
|
||||
FULL_EFB_HEIGHT = 2 * EFB_HEIGHT;
|
||||
@ -301,6 +301,7 @@ bool Renderer::Init()
|
||||
|
||||
for (int stage = 0; stage < 8; stage++)
|
||||
D3D::SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, g_ActiveConfig.iMaxAnisotropy);
|
||||
|
||||
D3DVIEWPORT9 vp;
|
||||
vp.X = 0;
|
||||
vp.Y = 0;
|
||||
@ -354,7 +355,7 @@ void dumpMatrix(D3DXMATRIX &mtx)
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
char temp[256];
|
||||
sprintf(temp,"%4.4f %4.4f %4.4f %4.4f",mtx.m[y][0],mtx.m[y][1],mtx.m[y][2],mtx.m[y][3]);
|
||||
sprintf(temp,"%4.4f %4.4f %4.4f %4.4f", mtx.m[y][0], mtx.m[y][1], mtx.m[y][2], mtx.m[y][3]);
|
||||
g_VideoInitialize.pLog(temp, FALSE);
|
||||
}
|
||||
}
|
||||
@ -364,9 +365,9 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
int Xstride = (s_Fulltarget_width - s_target_width) / 2;
|
||||
int Ystride = (s_Fulltarget_height - s_target_height) / 2;
|
||||
TargetRectangle result;
|
||||
result.left = (int)(rc.left * xScale) + Xstride ;
|
||||
result.left = (int)(rc.left * xScale) + Xstride;
|
||||
result.top = (int)(rc.top * yScale) + Ystride;
|
||||
result.right = (int)(rc.right * xScale) + Xstride ;
|
||||
result.right = (int)(rc.right * xScale) + Xstride;
|
||||
result.bottom = (int)(rc.bottom * yScale) + Ystride;
|
||||
return result;
|
||||
}
|
||||
@ -433,14 +434,14 @@ static void EFBTextureToD3DBackBuffer(const EFBRectangle& sourceRc)
|
||||
int Width = dst_rect.right - dst_rect.left;
|
||||
int Height = dst_rect.bottom - dst_rect.top;
|
||||
|
||||
if(X < 0) X = 0;
|
||||
if(Y < 0) Y = 0;
|
||||
if(X > s_backbuffer_width) X = s_backbuffer_width;
|
||||
if(Y > s_backbuffer_height) Y = s_backbuffer_height;
|
||||
if(Width < 0) Width = 0;
|
||||
if(Height < 0) Height = 0;
|
||||
if(Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X;
|
||||
if(Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y;
|
||||
if (X < 0) X = 0;
|
||||
if (Y < 0) Y = 0;
|
||||
if (X > s_backbuffer_width) X = s_backbuffer_width;
|
||||
if (Y > s_backbuffer_height) Y = s_backbuffer_height;
|
||||
if (Width < 0) Width = 0;
|
||||
if (Height < 0) Height = 0;
|
||||
if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X;
|
||||
if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y;
|
||||
vp.X = X;
|
||||
vp.Y = Y;
|
||||
vp.Width = Width;
|
||||
@ -617,13 +618,13 @@ bool Renderer::SetScissorRect()
|
||||
if (rc.bottom < 0) rc.bottom = 0;
|
||||
if (rc.top > s_Fulltarget_height) rc.top = s_Fulltarget_height;
|
||||
if (rc.bottom > s_Fulltarget_height) rc.bottom = s_Fulltarget_height;
|
||||
if(rc.left > rc.right)
|
||||
if (rc.left > rc.right)
|
||||
{
|
||||
int temp = rc.right;
|
||||
rc.right = rc.left;
|
||||
rc.left = temp;
|
||||
}
|
||||
if(rc.top > rc.bottom)
|
||||
if (rc.top > rc.bottom)
|
||||
{
|
||||
int temp = rc.bottom;
|
||||
rc.bottom = rc.top;
|
||||
@ -660,7 +661,7 @@ void Renderer::SetColorMask()
|
||||
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
{
|
||||
if(!g_ActiveConfig.bEFBAccessEnable)
|
||||
if (!g_ActiveConfig.bEFBAccessEnable)
|
||||
return 0;
|
||||
|
||||
//Get the working buffer
|
||||
@ -678,13 +679,13 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
D3DFORMAT ReadBufferFormat = (type == PEEK_Z || type == POKE_Z) ?
|
||||
FBManager::GetEFBDepthReadSurfaceFormat() : BufferFormat;
|
||||
|
||||
if(BufferFormat == D3DFMT_D24X8)
|
||||
if (BufferFormat == D3DFMT_D24X8)
|
||||
return 0;
|
||||
|
||||
D3DLOCKED_RECT drect;
|
||||
|
||||
//Buffer not found alert
|
||||
if(!pBuffer) {
|
||||
if (!pBuffer) {
|
||||
PanicAlert("No %s!", (type == PEEK_Z || type == POKE_Z) ? "Z-Buffer" : "Color EFB");
|
||||
return 0;
|
||||
}
|
||||
@ -706,7 +707,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
RectToLock.left = targetPixelRc.left;
|
||||
RectToLock.right = targetPixelRc.right;
|
||||
RectToLock.top = targetPixelRc.top;
|
||||
if(type == PEEK_Z)
|
||||
if (type == PEEK_Z)
|
||||
{
|
||||
RECT PixelRect;
|
||||
PixelRect.bottom = 4;
|
||||
@ -717,14 +718,14 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
RectToLock.right+=1;
|
||||
RectToLock.top-=1;
|
||||
RectToLock.left-=2;
|
||||
if((RectToLock.bottom - RectToLock.top) > 4)
|
||||
if ((RectToLock.bottom - RectToLock.top) > 4)
|
||||
RectToLock.bottom--;
|
||||
if((RectToLock.right - RectToLock.left) > 4)
|
||||
if ((RectToLock.right - RectToLock.left) > 4)
|
||||
RectToLock.left++;
|
||||
ResetAPIState(); // reset any game specific settings
|
||||
hr =D3D::dev->SetDepthStencilSurface(NULL);
|
||||
hr = D3D::dev->SetRenderTarget(0, RBuffer);
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("unable to set pixel render buffer");
|
||||
return 0;
|
||||
@ -738,7 +739,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
hr = D3D::dev->SetViewport(&vp);
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("unable to set pixel viewport");
|
||||
return 0;
|
||||
@ -774,14 +775,14 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
RectToLock.right = 1;
|
||||
RectToLock.top = 0;
|
||||
}
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Unable to stretch data to buffer");
|
||||
return 0;
|
||||
}
|
||||
//retriebe the pixel data to the local memory buffer
|
||||
D3D::dev->GetRenderTargetData(RBuffer,pOffScreenBuffer);
|
||||
if(FAILED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Unable to copy data to mem buffer");
|
||||
return 0;
|
||||
@ -791,7 +792,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
|
||||
|
||||
//the surface is good.. lock it
|
||||
if((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK)
|
||||
if ((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK)
|
||||
{
|
||||
PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" :
|
||||
hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t");
|
||||
@ -872,12 +873,12 @@ void UpdateViewport()
|
||||
int Y = (int)(ceil(xfregs.rawViewport[4] + xfregs.rawViewport[1] - (scissorYOff)) * MValueY) + Ystride;
|
||||
int Width = (int)ceil((int)(2 * xfregs.rawViewport[0]) * MValueX);
|
||||
int Height = (int)ceil((int)(-2 * xfregs.rawViewport[1]) * MValueY);
|
||||
if(Width < 0)
|
||||
if (Width < 0)
|
||||
{
|
||||
X += Width;
|
||||
Width*=-1;
|
||||
}
|
||||
if(Height < 0)
|
||||
if (Height < 0)
|
||||
{
|
||||
Y += Height;
|
||||
Height *= -1;
|
||||
@ -916,10 +917,10 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||
sirc.right = targetRc.right;
|
||||
sirc.bottom = targetRc.bottom;
|
||||
D3D::dev->SetScissorRect(&sirc);
|
||||
if(zEnable)
|
||||
if (zEnable)
|
||||
D3D::ChangeRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
|
||||
D3D::drawClearQuad(&sirc,color ,(z & 0xFFFFFF) / float(0xFFFFFF),PixelShaderCache::GetClearProgram(),VertexShaderCache::GetSimpleVertexShader());
|
||||
if(zEnable)
|
||||
if (zEnable)
|
||||
D3D::RefreshRenderState(D3DRS_ZFUNC);
|
||||
//D3D::dev->Clear(0, NULL, (colorEnable ? D3DCLEAR_TARGET : 0)| ( zEnable ? D3DCLEAR_ZBUFFER : 0), color | ((alphaEnable)?0:0xFF000000),(z & 0xFFFFFF) / float(0xFFFFFF), 0);
|
||||
UpdateViewport();
|
||||
@ -933,7 +934,7 @@ void Renderer::SetBlendMode(bool forceUpdate)
|
||||
// 2 - reverse subtract enable (else add)
|
||||
// 3-5 - srcRGB function
|
||||
// 6-8 - dstRGB function
|
||||
if(bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
|
||||
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
|
||||
return;
|
||||
u32 newval = bpmem.blendmode.subtract << 2;
|
||||
|
||||
@ -978,8 +979,6 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||
// D3D frame is now over
|
||||
// Clean out old stuff from caches.
|
||||
frameCount++;
|
||||
PixelShaderCache::Cleanup();
|
||||
VertexShaderCache::Cleanup();
|
||||
TextureCache::Cleanup();
|
||||
|
||||
// Make any new configuration settings active.
|
||||
|
@ -75,7 +75,7 @@ void CreateRgbToYuyvProgram()
|
||||
" float3 c01 = (c0 + c1) * 0.5f;\n"
|
||||
" ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n"
|
||||
"}\n";
|
||||
s_rgbToYuyvProgram = D3D::CompilePixelShader(FProgram, (int)strlen(FProgram));
|
||||
s_rgbToYuyvProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram));
|
||||
if (!s_rgbToYuyvProgram) {
|
||||
ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program");
|
||||
}
|
||||
@ -102,7 +102,7 @@ void CreateYuyvToRgbProgram()
|
||||
" yComp + (2.018f * uComp),\n"
|
||||
" 1.0f);\n"
|
||||
"}\n";
|
||||
s_yuyvToRgbProgram = D3D::CompilePixelShader(FProgram, (int)strlen(FProgram));
|
||||
s_yuyvToRgbProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram));
|
||||
if (!s_yuyvToRgbProgram) {
|
||||
ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program");
|
||||
}
|
||||
@ -129,7 +129,7 @@ LPDIRECT3DPIXELSHADER9 GetOrCreateEncodingShader(u32 format)
|
||||
SaveData(szTemp, shader);
|
||||
}
|
||||
#endif
|
||||
s_encodingPrograms[format] = D3D::CompilePixelShader(shader, (int)strlen(shader));
|
||||
s_encodingPrograms[format] = D3D::CompileAndCreatePixelShader(shader, (int)strlen(shader));
|
||||
if (!s_encodingPrograms[format]) {
|
||||
ERROR_LOG(VIDEO, "Failed to create encoding fragment program");
|
||||
}
|
||||
|
@ -17,6 +17,11 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Common.h"
|
||||
#include "FileUtil.h"
|
||||
#include "LinearDiskCache.h"
|
||||
|
||||
#include "Globals.h"
|
||||
#include "D3DBase.h"
|
||||
#include "D3DShader.h"
|
||||
#include "Statistics.h"
|
||||
@ -33,9 +38,10 @@
|
||||
VertexShaderCache::VSCache VertexShaderCache::vshaders;
|
||||
const VertexShaderCache::VSCacheEntry *VertexShaderCache::last_entry;
|
||||
|
||||
static float GC_ALIGNED16(lastVSconstants[C_FOGPARAMS+8][4]);
|
||||
static float GC_ALIGNED16(lastVSconstants[C_FOGPARAMS + 8][4]);
|
||||
|
||||
static LPDIRECT3DVERTEXSHADER9 SimpleVertexShader;
|
||||
LinearDiskCache g_vs_disk_cache;
|
||||
|
||||
LPDIRECT3DVERTEXSHADER9 VertexShaderCache::GetSimpleVertexShader()
|
||||
{
|
||||
@ -126,9 +132,23 @@ void SetMultiVSConstant4fv(int const_number, int count, const float *f)
|
||||
}
|
||||
}
|
||||
|
||||
class VertexShaderCacheInserter : public LinearDiskCacheReader {
|
||||
public:
|
||||
void Read(const u8 *key, int key_size, const u8 *value, int value_size)
|
||||
{
|
||||
VERTEXSHADERUID uid;
|
||||
if (key_size != sizeof(uid)) {
|
||||
ERROR_LOG(VIDEO, "Wrong key size in vertex shader cache");
|
||||
return;
|
||||
}
|
||||
memcpy(&uid, key, key_size);
|
||||
VertexShaderCache::InsertByteCode(uid, value, value_size, false);
|
||||
}
|
||||
};
|
||||
|
||||
void VertexShaderCache::Init()
|
||||
{
|
||||
char vSimpleProg[1024];
|
||||
char *vSimpleProg = new char[2048];
|
||||
sprintf(vSimpleProg,"struct VSOUTPUT\n"
|
||||
"{\n"
|
||||
"float4 vPosition : POSITION;\n"
|
||||
@ -146,8 +166,17 @@ void VertexShaderCache::Init()
|
||||
"return OUT;\n"
|
||||
"}\n");
|
||||
|
||||
SimpleVertexShader = D3D::CompileVertexShader(vSimpleProg, (int)strlen(vSimpleProg));
|
||||
SimpleVertexShader = D3D::CompileAndCreateVertexShader(vSimpleProg, (int)strlen(vSimpleProg));
|
||||
Clear();
|
||||
delete [] vSimpleProg;
|
||||
|
||||
if (!File::Exists(FULL_SHADERCACHE_DIR))
|
||||
File::CreateDir(FULL_SHADERCACHE_DIR);
|
||||
|
||||
char cache_filename[MAX_PATH];
|
||||
sprintf(cache_filename, "%s%s-vs.cache", FULL_SHADERCACHE_DIR, globals->unique_id);
|
||||
VertexShaderCacheInserter inserter;
|
||||
int read_items = g_vs_disk_cache.OpenAndRead(cache_filename, &inserter);
|
||||
}
|
||||
|
||||
void VertexShaderCache::Clear()
|
||||
@ -164,9 +193,11 @@ void VertexShaderCache::Clear()
|
||||
|
||||
void VertexShaderCache::Shutdown()
|
||||
{
|
||||
if(SimpleVertexShader)
|
||||
if (SimpleVertexShader)
|
||||
SimpleVertexShader->Release();
|
||||
Clear();
|
||||
g_vs_disk_cache.Sync();
|
||||
g_vs_disk_cache.Close();
|
||||
}
|
||||
|
||||
bool VertexShaderCache::SetShader(u32 components)
|
||||
@ -174,7 +205,7 @@ bool VertexShaderCache::SetShader(u32 components)
|
||||
DVSTARTPROFILE();
|
||||
|
||||
VERTEXSHADERUID uid;
|
||||
GetVertexShaderId(uid, components);
|
||||
GetVertexShaderId(&uid, components);
|
||||
if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount)
|
||||
{
|
||||
if (vshaders[uid].shader)
|
||||
@ -202,8 +233,27 @@ bool VertexShaderCache::SetShader(u32 components)
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *code = GenerateVertexShader(components, true);
|
||||
LPDIRECT3DVERTEXSHADER9 shader = D3D::CompileVertexShader(code, (int)strlen(code));
|
||||
const char *code = GenerateVertexShaderCode(components, true);
|
||||
u8 *bytecode;
|
||||
int bytecodelen;
|
||||
if (!D3D::CompileVertexShader(code, (int)strlen(code), &bytecode, &bytecodelen))
|
||||
{
|
||||
if (g_ActiveConfig.bShowShaderErrors)
|
||||
{
|
||||
PanicAlert("Failed to compile Vertex Shader:\n\n%s", code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
g_vs_disk_cache.Append((u8 *)&uid, sizeof(uid), bytecode, bytecodelen);
|
||||
g_vs_disk_cache.Sync();
|
||||
|
||||
bool result = InsertByteCode(uid, bytecode, bytecodelen, true);
|
||||
delete [] bytecode;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VertexShaderCache::InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate) {
|
||||
LPDIRECT3DVERTEXSHADER9 shader = D3D::CreateVertexShaderFromByteCode(bytecode, bytecodelen);
|
||||
|
||||
// Make an entry in the table
|
||||
VSCacheEntry entry;
|
||||
@ -214,41 +264,19 @@ bool VertexShaderCache::SetShader(u32 components)
|
||||
#endif
|
||||
vshaders[uid] = entry;
|
||||
last_entry = &vshaders[uid];
|
||||
if (!shader)
|
||||
return false;
|
||||
|
||||
INCSTAT(stats.numVertexShadersCreated);
|
||||
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());
|
||||
if (shader)
|
||||
if (activate)
|
||||
{
|
||||
D3D::SetVertexShader(shader);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bShowShaderErrors)
|
||||
{
|
||||
PanicAlert("Failed to compile Vertex Shader:\n\n%s", code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VertexShaderCache::Cleanup()
|
||||
{
|
||||
/*
|
||||
for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end();)
|
||||
{
|
||||
VSCacheEntry &entry = iter->second;
|
||||
if (entry.frameCount < frameCount - 1400)
|
||||
{
|
||||
entry.Destroy();
|
||||
iter = vshaders.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
SETSTAT(stats.numVertexShadersAlive, (int)vshaders.size());*/
|
||||
|
||||
}
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
std::string VertexShaderCache::GetCurrentShaderCode()
|
||||
{
|
||||
|
@ -53,10 +53,10 @@ private:
|
||||
public:
|
||||
static void Init();
|
||||
static void Clear();
|
||||
static void Cleanup();
|
||||
static void Shutdown();
|
||||
static bool SetShader(u32 components);
|
||||
static LPDIRECT3DVERTEXSHADER9 GetSimpleVertexShader();
|
||||
static bool InsertByteCode(const VERTEXSHADERUID &uid, const u8 *bytecode, int bytecodelen, bool activate);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
static std::string GetCurrentShaderCode();
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user