1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
20 #include "LinearDiskCache.h"
24 #include "D3Dcompiler.h"
25 #include "D3DShader.h"
26 #include "Statistics.h"
27 #include "VideoConfig.h"
28 #include "PixelShaderGen.h"
29 #include "PixelShaderManager.h"
30 #include "PixelShaderCache.h"
31 #include "VertexLoader.h"
34 #include "ImageWrite.h"
36 extern int frameCount
;
38 PixelShaderCache::PSCache
PixelShaderCache::PixelShaders
;
39 const PixelShaderCache::PSCacheEntry
* PixelShaderCache::last_entry
;
41 LinearDiskCache g_ps_disk_cache
;
43 ID3D11PixelShader
* s_ColorMatrixProgram
= NULL
;
44 ID3D11PixelShader
* s_ColorCopyProgram
= NULL
;
45 ID3D11PixelShader
* s_DepthMatrixProgram
= NULL
;
46 ID3D11PixelShader
* s_ClearProgram
= NULL
;
48 const char clear_program_code
[] = {
50 "out float4 ocol0 : SV_Target,\n"
51 "in float4 pos : SV_Position,\n"
52 "in float4 incol0 : COLOR0){\n"
57 const char color_copy_program_code
[] = {
58 "sampler samp0 : register(s0);\n"
59 "Texture2D Tex0 : register(t0);\n"
61 "out float4 ocol0 : SV_Target,\n"
62 "in float4 pos : SV_Position,\n"
63 "in float2 uv0 : TEXCOORD0){\n"
64 "ocol0 = Tex0.Sample(samp0,uv0);\n"
68 const char color_matrix_program_code
[] = {
69 "sampler samp0 : register(s0);\n"
70 "Texture2D Tex0 : register(t0);\n"
71 "uniform float4 cColMatrix[5] : register(c0);\n"
73 "out float4 ocol0 : SV_Target,\n"
74 "in float4 pos : SV_Position,\n"
75 " in float2 uv0 : TEXCOORD0){\n"
76 "float4 texcol = Tex0.Sample(samp0,uv0);\n"
77 "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
81 const char depth_matrix_program
[] = {
82 "sampler samp0 : register(s0);\n"
83 "Texture2D Tex0 : register(t0);\n"
84 "uniform float4 cColMatrix[5] : register(c0);\n"
86 "out float4 ocol0 : SV_Target,\n"
87 " in float4 pos : SV_Position,\n"
88 " in float2 uv0 : TEXCOORD0){\n"
89 "float4 texcol = Tex0.Sample(samp0,uv0);\n"
90 "float4 EncodedDepth = frac((texcol.r * (16777215.0f/16777216.0f)) * float4(1.0f,255.0f,255.0f*255.0f,255.0f*255.0f*255.0f));\n"
91 "texcol = float4((EncodedDepth.rgb * (16777216.0f/16777215.0f)),1.0f);\n"
92 "ocol0 = float4(dot(texcol,cColMatrix[0]),dot(texcol,cColMatrix[1]),dot(texcol,cColMatrix[2]),dot(texcol,cColMatrix[3])) + cColMatrix[4];\n"
96 ID3D11PixelShader
* PixelShaderCache::GetColorMatrixProgram()
98 return s_ColorMatrixProgram
;
101 ID3D11PixelShader
* PixelShaderCache::GetDepthMatrixProgram()
103 return s_DepthMatrixProgram
;
106 ID3D11PixelShader
* PixelShaderCache::GetColorCopyProgram()
108 return s_ColorCopyProgram
;
111 ID3D11PixelShader
* PixelShaderCache::GetClearProgram()
113 return s_ClearProgram
;
116 // HACK to avoid some invasive VideoCommon changes
117 // these values are hardcoded, they depend on internal D3DCompile behavior; TODO: Solve this with D3DReflect or something
118 // offset given in floats, table index is float4
119 unsigned int ps_constant_offset_table
[] = {
120 0, 4, 8, 12, // C_COLORS, 16
121 16, 20, 24, 28, // C_KCOLORS, 16
123 36, 40, 44, 48, 52, 56, 60, 64, // C_TEXDIMS, 32
124 68, 72, // C_ZBIAS, 8
125 76, 80, // C_INDTEXSCALE, 8
126 84, 88, 92, 96, 100, 104, // C_INDTEXMTX, 24
127 108, 112, // C_FOG, 8
129 void SetPSConstant4f(unsigned int const_number
, float f1
, float f2
, float f3
, float f4
)
131 D3D::gfxstate
->psconstants
[ps_constant_offset_table
[const_number
] ] = f1
;
132 D3D::gfxstate
->psconstants
[ps_constant_offset_table
[const_number
]+1] = f2
;
133 D3D::gfxstate
->psconstants
[ps_constant_offset_table
[const_number
]+2] = f3
;
134 D3D::gfxstate
->psconstants
[ps_constant_offset_table
[const_number
]+3] = f4
;
135 D3D::gfxstate
->pscbufchanged
= true;
138 void SetPSConstant4fv(unsigned int const_number
, const float* f
)
140 memcpy(&D3D::gfxstate
->psconstants
[ps_constant_offset_table
[const_number
]], f
, sizeof(float)*4);
141 D3D::gfxstate
->pscbufchanged
= true;
144 void SetMultiPSConstant4fv(unsigned int const_number
, unsigned int count
, const float* f
)
146 memcpy(&D3D::gfxstate
->psconstants
[ps_constant_offset_table
[const_number
]], f
, sizeof(float)*4*count
);
147 D3D::gfxstate
->pscbufchanged
= true;
150 // this class will load the precompiled shaders into our cache
151 class PixelShaderCacheInserter
: public LinearDiskCacheReader
{
153 void Read(const u8
* key
, int key_size
, const u8
* value
, int value_size
)
156 if (key_size
!= sizeof(uid
)) {
157 ERROR_LOG(VIDEO
, "Wrong key size in pixel shader cache");
160 memcpy(&uid
, key
, key_size
);
161 PixelShaderCache::InsertByteCode(uid
, (void*)value
, value_size
);
165 void PixelShaderCache::Init()
167 // used when drawing clear quads
168 s_ClearProgram
= D3D::CompileAndCreatePixelShader(clear_program_code
, sizeof(clear_program_code
));
169 CHECK(s_ClearProgram
!=NULL
, "Create clear pixel shader");
170 D3D::SetDebugObjectName((ID3D11DeviceChild
*)s_ClearProgram
, "clear pixel shader");
172 // used when copying/resolving the color buffer
173 s_ColorCopyProgram
= D3D::CompileAndCreatePixelShader(color_copy_program_code
, sizeof(color_copy_program_code
));
174 CHECK(s_ColorCopyProgram
!=NULL
, "Create color copy pixel shader");
175 D3D::SetDebugObjectName((ID3D11DeviceChild
*)s_ClearProgram
, "color copy pixel shader");
177 // used for color conversion
178 s_ColorMatrixProgram
= D3D::CompileAndCreatePixelShader(color_matrix_program_code
, sizeof(color_matrix_program_code
));
179 CHECK(s_ColorMatrixProgram
!=NULL
, "Create color matrix pixel shader");
180 D3D::SetDebugObjectName((ID3D11DeviceChild
*)s_ClearProgram
, "color matrix pixel shader");
182 // used for depth copy
183 s_DepthMatrixProgram
= D3D::CompileAndCreatePixelShader(depth_matrix_program
, sizeof(depth_matrix_program
));
184 CHECK(s_DepthMatrixProgram
!=NULL
, "Create depth matrix pixel shader");
185 D3D::SetDebugObjectName((ID3D11DeviceChild
*)s_ClearProgram
, "depth matrix pixel shader");
189 if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX
)))
190 File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX
));
192 char cache_filename
[MAX_PATH
];
193 sprintf(cache_filename
, "%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX
), globals
->unique_id
);
194 PixelShaderCacheInserter inserter
;
195 g_ps_disk_cache
.OpenAndRead(cache_filename
, &inserter
);
198 // ONLY to be used during shutdown.
199 void PixelShaderCache::Clear()
201 for (PSCache::iterator iter
= PixelShaders
.begin(); iter
!= PixelShaders
.end(); iter
++)
202 iter
->second
.Destroy();
203 PixelShaders
.clear();
206 void PixelShaderCache::Shutdown()
208 SAFE_RELEASE(s_ColorMatrixProgram
);
209 SAFE_RELEASE(s_ColorCopyProgram
);
210 SAFE_RELEASE(s_DepthMatrixProgram
);
211 SAFE_RELEASE(s_ClearProgram
);
214 g_ps_disk_cache
.Sync();
215 g_ps_disk_cache
.Close();
218 bool PixelShaderCache::SetShader(bool dstAlpha
)
221 GetPixelShaderId(&uid
, PixelShaderManager::GetTextureMask(), dstAlpha
);
223 // check if the shader is already set
224 if (uid
== last_pixel_shader_uid
&& PixelShaders
[uid
].frameCount
== frameCount
)
226 PSCache::const_iterator iter
= PixelShaders
.find(uid
);
227 return (iter
!= PixelShaders
.end() && iter
->second
.shader
);
230 memcpy(&last_pixel_shader_uid
, &uid
, sizeof(PIXELSHADERUID
));
232 // check if the shader is already in the cache
233 PSCache::iterator iter
;
234 iter
= PixelShaders
.find(uid
);
235 if (iter
!= PixelShaders
.end())
237 iter
->second
.frameCount
= frameCount
;
238 const PSCacheEntry
&entry
= iter
->second
;
241 D3D::gfxstate
->SetPShader(entry
.shader
);
242 return (entry
.shader
!= NULL
);
245 // need to compile a new shader
246 const char* code
= GeneratePixelShaderCode(PixelShaderManager::GetTextureMask(), dstAlpha
, API_D3D11
);
249 if (!D3D::CompilePixelShader(code
, strlen(code
), &pbytecode
))
251 PanicAlert("Failed to compile Pixel Shader:\n\n%s", code
);
255 // insert the bytecode into the caches
256 g_ps_disk_cache
.Append((u8
*)&uid
, sizeof(uid
), (const u8
*)pbytecode
->Data(), pbytecode
->Size());
257 g_ps_disk_cache
.Sync();
259 bool result
= InsertByteCode(uid
, pbytecode
->Data(), pbytecode
->Size());
260 D3D::gfxstate
->SetPShader(last_entry
->shader
);
261 pbytecode
->Release();
265 bool PixelShaderCache::InsertByteCode(const PIXELSHADERUID
&uid
, void* bytecode
, unsigned int bytecodelen
)
267 ID3D11PixelShader
* shader
= D3D::CreatePixelShaderFromByteCode(bytecode
, bytecodelen
);
270 PanicAlert("Failed to create pixel shader at %s %d\n", __FILE__
, __LINE__
);
273 // TODO: Somehow make the debug name a bit more specific
274 D3D::SetDebugObjectName((ID3D11DeviceChild
*)shader
, "a pixel shader of PixelShaderCache");
276 // make an entry in the table
277 PSCacheEntry newentry
;
278 newentry
.shader
= shader
;
279 newentry
.frameCount
= frameCount
;
280 PixelShaders
[uid
] = newentry
;
281 last_entry
= &PixelShaders
[uid
];
283 INCSTAT(stats
.numPixelShadersCreated
);
284 SETSTAT(stats
.numPixelShadersAlive
, PixelShaders
.size());