void ShaderCache::HandlePSUIDChange( const PixelShaderUid &ps_uid, bool on_gpu_thread) { s_shaders_lock.lock(); ByteCodeCacheEntry* entry = &ps_bytecode_cache->GetOrAdd(ps_uid); s_shaders_lock.unlock(); if (on_gpu_thread) { s_last_pixel_shader_bytecode = entry; } if (entry->m_initialized.test_and_set()) { return; } // Need to compile a new shader ShaderCompilerWorkUnit *wunit = s_compiler->NewUnit(PIXELSHADERGEN_BUFFERSIZE); wunit->GenerateCodeHandler = [ps_uid](ShaderCompilerWorkUnit* wunit) { ShaderCode code; code.SetBuffer(wunit->code.data()); GeneratePixelShaderCodeD3D11(code, ps_uid.GetUidData()); wunit->codesize = (u32)code.BufferSize(); }; wunit->entrypoint = "main"; wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3; wunit->target = D3D::PixelShaderVersionString(); wunit->ResultHandler = [ps_uid, entry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { D3DBlob* shaderBuffer = new D3DBlob(wunit->shaderbytecode); s_ps_disk_cache.Append(ps_uid, shaderBuffer->Data(), shaderBuffer->Size()); PushByteCode(entry, shaderBuffer); wunit->shaderbytecode->Release(); wunit->shaderbytecode = nullptr; } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_ps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char *)wunit->code.data()); file << ((const char *)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile pixel shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::PixelShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; s_compiler->CompileShaderAsync(wunit); }
void VertexShaderCache::Clear() { vshaderslock.lock(); for (VSCache::iterator iter = vshaders.begin(); iter != vshaders.end(); ++iter) iter->second.Destroy(); vshaders.clear(); vshaderslock.unlock(); last_entry = NULL; }
void ShaderCache::InsertByteCode(const UidType& uid, ShaderCacheType* shader_cache, D3DBlob* bytecode_blob) { s_shader_blob_list.push_back(bytecode_blob); s_shaders_lock.lock(); ByteCodeCacheEntry* entry = entry = &shader_cache->GetOrAdd(uid); s_shaders_lock.unlock(); entry->m_shader_bytecode.pShaderBytecode = bytecode_blob->Data(); entry->m_shader_bytecode.BytecodeLength = bytecode_blob->Size(); entry->m_compiled = true; entry->m_initialized.test_and_set(); }
void ShaderCache::InsertHSByteCode(const TessellationShaderUid & uid, D3DBlob * bytecode_blob) { s_shader_blob_list.push_back(bytecode_blob); s_shaders_lock.lock(); ByteCodeCacheEntry* entry = &ts_bytecode_cache->GetOrAdd(uid).second; s_shaders_lock.unlock(); entry->m_shader_bytecode.pShaderBytecode = bytecode_blob->Data(); entry->m_shader_bytecode.BytecodeLength = bytecode_blob->Size(); entry->m_compiled = true; entry->m_initialized.test_and_set(); }
void ShaderCache::HandleTSUIDChange( const TessellationShaderUid& ts_uid, bool on_gpu_thread) { s_shaders_lock.lock(); std::pair<ByteCodeCacheEntry, ByteCodeCacheEntry>& entry = ts_bytecode_cache->GetOrAdd(ts_uid); s_shaders_lock.unlock(); ByteCodeCacheEntry* dentry = &entry.first; ByteCodeCacheEntry* hentry = &entry.second; if (on_gpu_thread) { if (dentry->m_compiled && hentry->m_compiled) { s_last_domain_shader_bytecode = dentry; s_last_hull_shader_bytecode = hentry; } else { s_last_tessellation_shader_uid = {}; s_last_domain_shader_bytecode = &s_pass_entry; s_last_hull_shader_bytecode = &s_pass_entry; } } if (dentry->m_initialized.test_and_set()) { return; } hentry->m_initialized.test_and_set(); // Need to compile a new shader ShaderCode code; ShaderCompilerWorkUnit *wunit = s_compiler->NewUnit(TESSELLATIONSHADERGEN_BUFFERSIZE); ShaderCompilerWorkUnit *wunitd = s_compiler->NewUnit(TESSELLATIONSHADERGEN_BUFFERSIZE); code.SetBuffer(wunit->code.data()); GenerateTessellationShaderCode(code, API_D3D11, ts_uid.GetUidData()); memcpy(wunitd->code.data(), wunit->code.data(), code.BufferSize()); wunit->codesize = (u32)code.BufferSize(); wunit->entrypoint = "HS_TFO"; wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_SKIP_OPTIMIZATION; wunit->target = D3D::HullShaderVersionString(); wunitd->codesize = (u32)code.BufferSize(); wunitd->entrypoint = "DS_TFO"; wunitd->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3; wunitd->target = D3D::DomainShaderVersionString(); wunitd->ResultHandler = [ts_uid, dentry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { D3DBlob* shaderBuffer = new D3DBlob(wunit->shaderbytecode); s_ds_disk_cache.Append(ts_uid, shaderBuffer->Data(), shaderBuffer->Size()); PushByteCode(dentry, shaderBuffer); wunit->shaderbytecode->Release(); wunit->shaderbytecode = nullptr; } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_ds_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char *)wunit->code.data()); file << ((const char *)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile domain shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::DomainShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; wunit->ResultHandler = [ts_uid, hentry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { D3DBlob* shaderBuffer = new D3DBlob(wunit->shaderbytecode); s_hs_disk_cache.Append(ts_uid, shaderBuffer->Data(), shaderBuffer->Size()); PushByteCode(hentry, shaderBuffer); wunit->shaderbytecode->Release(); wunit->shaderbytecode = nullptr; } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_hs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char *)wunit->code.data()); file << ((const char *)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile hull shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::HullShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; s_compiler->CompileShaderAsync(wunit); s_compiler->CompileShaderAsync(wunitd); }
void ShaderCache::Init() { s_compiler = &HLSLAsyncCompiler::getInstance(); s_shaders_lock.unlock(); s_pass_entry.m_compiled = true; s_pass_entry.m_initialized.test_and_set(); // This class intentionally shares its shader cache files with DX11, as the shaders are (right now) identical. // Reduces unnecessary compilation when switching between APIs. s_last_domain_shader_bytecode = &s_pass_entry; s_last_hull_shader_bytecode = &s_pass_entry; s_last_geometry_shader_bytecode = &s_pass_entry; s_last_pixel_shader_bytecode = nullptr; s_last_vertex_shader_bytecode = nullptr; s_last_geometry_shader_uid = {}; s_last_pixel_shader_uid = {}; s_last_vertex_shader_uid = {}; s_last_tessellation_shader_uid = {}; s_last_cpu_geometry_shader_uid = {}; s_last_cpu_pixel_shader_uid = {}; s_last_cpu_vertex_shader_uid = {}; s_last_cpu_tessellation_shader_uid = {}; // Ensure shader cache directory exists.. std::string shader_cache_path = File::GetUserPath(D_SHADERCACHE_IDX); if (!File::Exists(shader_cache_path)) File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); std::string title_unique_id = SConfig::GetInstance().m_strGameID; std::string ds_cache_filename = StringFromFormat("%sIDX11-%s-ds.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string hs_cache_filename = StringFromFormat("%sIDX11-%s-hs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string gs_cache_filename = StringFromFormat("%sIDX11-%s-gs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string ps_cache_filename = StringFromFormat("%sIDX11-%s-ps.cache", shader_cache_path.c_str(), title_unique_id.c_str()); std::string vs_cache_filename = StringFromFormat("%sIDX11-%s-vs.cache", shader_cache_path.c_str(), title_unique_id.c_str()); pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0); vs_bytecode_cache = VsBytecodeCache::Create( gameid, VERTEXSHADERGEN_UID_VERSION, "Ishiiruka.vs", StringFromFormat("%s.vs", title_unique_id.c_str()) ); ps_bytecode_cache = PsBytecodeCache::Create( gameid, PIXELSHADERGEN_UID_VERSION, "Ishiiruka.ps", StringFromFormat("%s.ps", title_unique_id.c_str()) ); gs_bytecode_cache = GsBytecodeCache::Create( gameid, GEOMETRYSHADERGEN_UID_VERSION, "Ishiiruka.gs", StringFromFormat("%s.gs", title_unique_id.c_str()) ); ts_bytecode_cache = TsBytecodeCache::Create( gameid, TESSELLATIONSHADERGEN_UID_VERSION, "Ishiiruka.ts", StringFromFormat("%s.ts", title_unique_id.c_str()) ); DShaderCacheInserter ds_inserter; s_ds_disk_cache.OpenAndRead(ds_cache_filename, ds_inserter); HShaderCacheInserter hs_inserter; s_hs_disk_cache.OpenAndRead(hs_cache_filename, hs_inserter); ShaderCacheInserter<GeometryShaderUid, GsBytecodeCache, &gs_bytecode_cache> gs_inserter; s_gs_disk_cache.OpenAndRead(gs_cache_filename, gs_inserter); ShaderCacheInserter<PixelShaderUid, PsBytecodeCache, &ps_bytecode_cache> ps_inserter; s_ps_disk_cache.OpenAndRead(ps_cache_filename, ps_inserter); ShaderCacheInserter<VertexShaderUid, VsBytecodeCache, &vs_bytecode_cache> vs_inserter; s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter); // Clear out disk cache when debugging shaders to ensure stale ones don't stick around.. SETSTAT(stats.numGeometryShadersAlive, static_cast<int>(gs_bytecode_cache->size())); SETSTAT(stats.numGeometryShadersCreated, 0); SETSTAT(stats.numPixelShadersAlive, static_cast<int>(ps_bytecode_cache->size())); SETSTAT(stats.numPixelShadersCreated, 0); SETSTAT(stats.numVertexShadersAlive, static_cast<int>(vs_bytecode_cache->size())); SETSTAT(stats.numVertexShadersCreated, 0); if (g_ActiveConfig.bCompileShaderOnStartup) { size_t shader_count = 0; ps_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const PixelShaderUid& it, size_t total) { PixelShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandlePSUIDChange(item, true); shader_count++; if ((shader_count & 7) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Pixel Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](ByteCodeCacheEntry& entry) { return !entry.m_shader_bytecode.pShaderBytecode; } , true); shader_count = 0; vs_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const VertexShaderUid& it, size_t total) { VertexShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandleVSUIDChange(item, true); shader_count++; if ((shader_count & 31) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Vertex Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](ByteCodeCacheEntry& entry) { return !entry.m_shader_bytecode.pShaderBytecode; } , true); shader_count = 0; gs_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const GeometryShaderUid& it, size_t total) { GeometryShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandleGSUIDChange(item, true); shader_count++; if ((shader_count & 7) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Geometry Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](ByteCodeCacheEntry& entry) { return !entry.m_shader_bytecode.pShaderBytecode; } , true); shader_count = 0; ts_bytecode_cache->ForEachMostUsedByCategory(gameid, [&](const TessellationShaderUid& it, size_t total) { TessellationShaderUid item = it; item.ClearHASH(); item.CalculateUIDHash(); HandleTSUIDChange(item, true); shader_count++; if ((shader_count & 31) == 0) { Host_UpdateTitle(StringFromFormat("Compiling Tessellation Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total)); s_compiler->WaitForFinish(); } }, [](std::pair<ByteCodeCacheEntry, ByteCodeCacheEntry>& entry) { return !entry.first.m_shader_bytecode.pShaderBytecode; } , true); s_compiler->WaitForFinish(); } }
void VertexShaderCache::Init() { Compiler = &HLSLAsyncCompiler::getInstance(); vshaderslock.unlock(); const char* code = "struct VSOUTPUT\n" "{\n" "float4 vPosition : POSITION;\n" "float2 vTexCoord : TEXCOORD0;\n" "float vTexCoord1 : TEXCOORD1;\n" "};\n" "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float inTEX2 : TEXCOORD2)\n" "{\n" "VSOUTPUT OUT;\n" "OUT.vPosition = inPosition;\n" "OUT.vTexCoord = inTEX0;\n" "OUT.vTexCoord1 = inTEX2;\n" "return OUT;\n" "}\0"; SimpleVertexShader[0] = D3D::CompileAndCreateVertexShader(code, (int)strlen(code)); code = "struct VSOUTPUT\n" "{\n" "float4 vPosition : POSITION;\n" "float4 vColor0 : COLOR0;\n" "};\n" "VSOUTPUT main(float4 inPosition : POSITION,float4 inColor0: COLOR0)\n" "{\n" "VSOUTPUT OUT;\n" "OUT.vPosition = inPosition;\n" "OUT.vColor0 = inColor0;\n" "return OUT;\n" "}\0"; ClearVertexShader = D3D::CompileAndCreateVertexShader(code, (int)strlen(code)); code = "struct VSOUTPUT\n" "{\n" "float4 vPosition : POSITION;\n" "float4 vTexCoord : TEXCOORD0;\n" "float vTexCoord1 : TEXCOORD1;\n" "float4 vTexCoord2 : TEXCOORD2;\n" "float4 vTexCoord3 : TEXCOORD3;\n" "};\n" "VSOUTPUT main(float4 inPosition : POSITION,float2 inTEX0 : TEXCOORD0,float2 inTEX1 : TEXCOORD1,float inTEX2 : TEXCOORD2)\n" "{\n" "VSOUTPUT OUT;" "OUT.vPosition = inPosition;\n" "OUT.vTexCoord = inTEX0.xyyx;\n" "OUT.vTexCoord1 = inTEX2.x;\n" "OUT.vTexCoord2 = inTEX0.xyyx + (float4(-0.375f,-0.125f,-0.375f, 0.125f) * inTEX1.xyyx);\n" "OUT.vTexCoord3 = inTEX0.xyyx + (float4( 0.375f, 0.125f, 0.375f,-0.125f) * inTEX1.xyyx);\n" "return OUT;\n" "}\0"; SimpleVertexShader[1] = D3D::CompileAndCreateVertexShader(code, (int)strlen(code)); Clear(); if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str()); SETSTAT(stats.numVertexShadersCreated, 0); SETSTAT(stats.numVertexShadersAlive, 0); char cache_filename[MAX_PATH]; sprintf(cache_filename, "%sIDX9-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), SConfig::GetInstance().m_strUniqueID.c_str()); VertexShaderCacheInserter inserter; vshaderslock.lock(); g_vs_disk_cache.OpenAndRead(cache_filename, inserter); vshaderslock.unlock(); if (g_Config.bEnableShaderDebugging) Clear(); last_entry = NULL; }
void VertexShaderCache::PrepareShader(u32 components, const XFMemory &xfr, const BPMemory &bpm, bool ongputhread) { VertexShaderUid uid; GetVertexShaderUID(uid, components, xfr, bpm); if (ongputhread) { Compiler->ProcCompilationResults(); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; GenerateVertexShaderCodeD3D9(code, uid.GetUidData()); } #endif if (last_entry) { if (uid == last_uid) { return; } } last_uid = uid; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); } else { if (external_last_uid == uid) { return; } external_last_uid = uid; } vshaderslock.lock(); VSCacheEntry *entry = &vshaders[uid]; vshaderslock.unlock(); if (ongputhread) { last_entry = entry; } // Compile only when we have a new instance if (entry->initialized.test_and_set()) { return; } ShaderCompilerWorkUnit *wunit = Compiler->NewUnit(VERTEXSHADERGEN_BUFFERSIZE); wunit->GenerateCodeHandler = [uid](ShaderCompilerWorkUnit* wunit) { ShaderCode code; code.SetBuffer(wunit->code.data()); GenerateVertexShaderCodeD3D9(code, uid.GetUidData()); wunit->codesize = (u32)code.BufferSize(); }; wunit->entrypoint = "main"; wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3; wunit->target = D3D::VertexShaderVersionString(); wunit->ResultHandler = [uid, entry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { ID3DBlob* shaderBuffer = wunit->shaderbytecode; const u8* bytecode = (const u8*)shaderBuffer->GetBufferPointer(); u32 bytecodelen = (u32)shaderBuffer->GetBufferSize(); g_vs_disk_cache.Append(uid, bytecode, bytecodelen); PushByteCode(uid, bytecode, bytecodelen, entry); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.bEnableShaderDebugging) { entry->code = wunit->code.data(); } #endif } else { static int num_failures = 0; std::string filename = StringFromFormat("%sbad_vs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); file << ((const char*)wunit->code.data()); file << ((const char*)wunit->error->GetBufferPointer()); file.close(); PanicAlert("Failed to compile vertex shader!\nThis usually happens when trying to use Dolphin with an outdated GPU or integrated GPU like the Intel GMA series.\n\nIf you're sure this is Dolphin's error anyway, post the contents of %s along with this error message at the forums.\n\nDebug info (%s):\n%s", filename, D3D::VertexShaderVersionString(), (char*)wunit->error->GetBufferPointer()); } }; Compiler->CompileShaderAsync(wunit); }