void ShaderCache::HandleVSUIDChange(VertexShaderUid vs_uid) { s_last_vertex_shader_uid = vs_uid; auto vs_iterator = s_vs_bytecode_cache.find(vs_uid); if (vs_iterator != s_vs_bytecode_cache.end()) { s_last_vertex_shader_bytecode = vs_iterator->second; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); } else { ShaderCode vs_code = GenerateVertexShaderCode(APIType::D3D, vs_uid.GetUidData()); ID3DBlob* vs_bytecode = nullptr; if (!D3D::CompileVertexShader(vs_code.GetBuffer(), &vs_bytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return; } s_last_vertex_shader_bytecode = InsertByteCode(vs_uid, &s_vs_bytecode_cache, vs_bytecode); s_vs_disk_cache.Append(vs_uid, reinterpret_cast<u8*>(vs_bytecode->GetBufferPointer()), static_cast<u32>(vs_bytecode->GetBufferSize())); SETSTAT(stats.numVertexShadersAlive, static_cast<int>(s_vs_bytecode_cache.size())); INCSTAT(stats.numVertexShadersCreated); } }
void VertexShaderCache::CompileVShader(const VertexShaderUid& uid, bool ongputhread) { s_vshaders_lock.lock(); VSCacheEntry* entry = &s_vshaders->GetOrAdd(uid); s_vshaders_lock.unlock(); if (ongputhread) { s_last_entry = entry; } // Compile only when we have a new instance if (entry->initialized.test_and_set()) { return; } ShaderCompilerWorkUnit *wunit = s_compiler->NewUnit(VERTEXSHADERGEN_BUFFERSIZE); wunit->GenerateCodeHandler = [uid](ShaderCompilerWorkUnit* wunit) { ShaderCode code; code.SetBuffer(wunit->code.data()); GenerateVertexShaderCodeD3D11(code, uid.GetUidData()); wunit->codesize = (u32)code.BufferSize(); }; wunit->entrypoint = "main"; #if defined(_DEBUG) || defined(DEBUGFAST) wunit->flags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else wunit->flags = D3DCOMPILE_SKIP_VALIDATION | D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY; #endif wunit->target = D3D::VertexShaderVersionString(); wunit->ResultHandler = [uid, entry](ShaderCompilerWorkUnit* wunit) { if (SUCCEEDED(wunit->cresult)) { g_vs_disk_cache.Append(uid, (const u8*)wunit->shaderbytecode->GetBufferPointer(), (u32)wunit->shaderbytecode->GetBufferSize()); PushByteCode(D3DBlob(D3D::UniquePtr<ID3D10Blob>(wunit->shaderbytecode)), entry); wunit->shaderbytecode = nullptr; } 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.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()); } }; s_compiler->CompileShaderAsync(wunit); }
bool VertexShaderCache::SetShader() { VertexShaderUid uid = GetVertexShaderUid(); if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (last_entry->shader != nullptr); } } last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry& entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != nullptr); } ShaderCode code = GenerateVertexShaderCode(API_D3D, uid.GetUidData()); D3DBlob* pbytecode = nullptr; D3D::CompileVertexShader(code.GetBuffer(), &pbytecode); if (pbytecode == nullptr) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode); pbytecode->Release(); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
bool VertexShaderCache::SetShader(D3DVertexFormat* vertex_format) { if (g_ActiveConfig.bDisableSpecializedShaders) return SetUberShader(vertex_format); VertexShaderUid uid = GetVertexShaderUid(); if (last_entry && uid == last_uid) { if (last_entry->pending) return SetUberShader(vertex_format); if (!last_entry->shader) return false; vertex_format->SetInputLayout(last_entry->bytecode); D3D::stateman->SetVertexShader(last_entry->shader); return true; } auto iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry& entry = iter->second; if (entry.pending) return SetUberShader(vertex_format); last_uid = uid; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); if (!last_entry->shader) return false; vertex_format->SetInputLayout(last_entry->bytecode); D3D::stateman->SetVertexShader(last_entry->shader); return true; } // Background compiling? if (g_ActiveConfig.CanBackgroundCompileShaders()) { // Create a pending entry VSCacheEntry entry; entry.pending = true; vshaders[uid] = entry; // Queue normal shader compiling and use ubershader g_async_compiler->QueueWorkItem( g_async_compiler->CreateWorkItem<VertexShaderCompilerWorkItem>(uid)); return SetUberShader(vertex_format); } // Need to compile a new shader D3DBlob* bytecode = nullptr; ShaderCode code = GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3D::CompileVertexShader(code.GetBuffer(), &bytecode); if (!InsertByteCode(uid, bytecode)) { SAFE_RELEASE(bytecode); return false; } g_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size()); bytecode->Release(); return SetShader(vertex_format); }
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); }