bool VertexShaderCache::SetShader(u32 components) { VertexShaderUid uid; GetVertexShaderUid(uid, components, API_D3D); if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; GenerateVertexShaderCode(code, components, API_D3D); vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v"); } 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(code, components, API_D3D); 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(); if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code.GetBuffer(); } GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
bool VertexShaderCache::SetShader(u32 components) { VertexShaderUid uid; GetVertexShaderUid(uid, components, API_D3D9); if (g_ActiveConfig.bEnableShaderDebugging) { VertexShaderCode code; GenerateVertexShaderCode(code, components, API_D3D9); vertex_uid_checker.AddToIndexAndCheck(code, uid, "Vertex", "v"); } if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (last_entry->shader != NULL); } } last_uid = uid; VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { const VSCacheEntry &entry = iter->second; last_entry = &entry; if (entry.shader) D3D::SetVertexShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != NULL); } VertexShaderCode code; GenerateVertexShaderCode(code, components, API_D3D9); u8 *bytecode; int bytecodelen; if (!D3D::CompileVertexShader(code.GetBuffer(), (int)strlen(code.GetBuffer()), &bytecode, &bytecodelen)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, bytecode, bytecodelen); bool success = InsertByteCode(uid, bytecode, bytecodelen, true); if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code.GetBuffer(); } delete [] bytecode; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
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); } }
bool VertexShaderCache::VertexShaderCompilerWorkItem::Compile() { ShaderCode code = GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData()); if (D3D::CompileVertexShader(code.GetBuffer(), &m_bytecode)) m_vs = D3D::CreateVertexShaderFromByteCode(m_bytecode); return true; }
bool VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); ValidateVertexShaderIDs(API_D3D11, last_entry->safe_uid, last_entry->code, components); return (last_entry->shader != NULL); } } 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); ValidateVertexShaderIDs(API_D3D11, entry.safe_uid, entry.code, components); return (entry.shader != NULL); } const char *code = GenerateVertexShaderCode(components, API_D3D11); D3DBlob* pbytecode = NULL; D3D::CompileVertexShader(code, (int)strlen(code), &pbytecode); if (pbytecode == NULL) { 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(); if (g_ActiveConfig.bEnableShaderDebugging && success) { vshaders[uid].code = code; GetSafeVertexShaderId(&vshaders[uid].safe_uid, components); } GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return success; }
VERTEXSHADER* VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return pShaderLast; } memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { iter->second.frameCount = frameCount; VSCacheEntry &entry = iter->second; if (&entry.shader != pShaderLast) { pShaderLast = &entry.shader; } GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return pShaderLast; } // Make an entry in the table VSCacheEntry& entry = vshaders[uid]; entry.frameCount = frameCount; pShaderLast = &entry.shader; const char *code = GenerateVertexShaderCode(components, API_OPENGL); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS && code) { static int counter = 0; char szTemp[MAX_PATH]; sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); SaveData(szTemp, code); } #endif if (!code || !VertexShaderCache::CompileVertexShader(entry.shader, code)) { ERROR_LOG(VIDEO, "failed to create vertex shader"); GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return NULL; } INCSTAT(stats.numVertexShadersCreated); SETSTAT(stats.numVertexShadersAlive, vshaders.size()); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return pShaderLast; }
void ProgramShaderCache::GetShaderId(SHADERUID* uid, DSTALPHA_MODE dstAlphaMode, u32 components) { GetPixelShaderUid(uid->puid, dstAlphaMode, API_OPENGL, components); GetVertexShaderUid(uid->vuid, components, API_OPENGL); if (g_ActiveConfig.bEnableShaderDebugging) { PixelShaderCode pcode; GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components); pixel_uid_checker.AddToIndexAndCheck(pcode, uid->puid, "Pixel", "p"); VertexShaderCode vcode; GenerateVertexShaderCode(vcode, components, API_OPENGL); vertex_uid_checker.AddToIndexAndCheck(vcode, uid->vuid, "Vertex", "v"); } }
bool VertexShaderCache::SetShader(u32 components) { VERTEXSHADERUID uid; GetVertexShaderId(&uid, components); if (uid == last_vertex_shader_uid && vshaders[uid].frameCount == frameCount) { GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (vshaders[uid].shader != NULL); } memcpy(&last_vertex_shader_uid, &uid, sizeof(VERTEXSHADERUID)); VSCache::iterator iter = vshaders.find(uid); if (iter != vshaders.end()) { iter->second.frameCount = frameCount; const VSCacheEntry &entry = iter->second; last_entry = &entry; if (entry.shader) D3D::SetVertexShader(entry.shader); GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return (entry.shader != NULL); } const char *code = GenerateVertexShaderCode(components, API_D3D9); 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); } GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } g_vs_disk_cache.Append(uid, bytecode, bytecodelen); g_vs_disk_cache.Sync(); bool result = InsertByteCode(uid, bytecode, bytecodelen, true); delete [] bytecode; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); return result; }
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; }
SHADER* ProgramShaderCache::SetShader ( DSTALPHA_MODE dstAlphaMode, u32 components ) { SHADERUID uid; GetShaderId(&uid, dstAlphaMode, components); // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); last_entry->shader.Bind(); return &last_entry->shader; } } last_uid = uid; // Check if shader is already in cache PCache::iterator iter = pshaders.find(uid); if (iter != pshaders.end()) { PCacheEntry *entry = &iter->second; last_entry = entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); last_entry->shader.Bind(); return &last_entry->shader; } // Make an entry in the table PCacheEntry& newentry = pshaders[uid]; last_entry = &newentry; newentry.in_cache = 0; VertexShaderCode vcode; PixelShaderCode pcode; GenerateVertexShaderCode(vcode, components, API_OPENGL); GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components); if (g_ActiveConfig.bEnableShaderDebugging) { newentry.shader.strvprog = vcode.GetBuffer(); newentry.shader.strpprog = pcode.GetBuffer(); } #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS) { static int counter = 0; char szTemp[MAX_PATH]; sprintf(szTemp, "%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); SaveData(szTemp, vcode.GetBuffer()); sprintf(szTemp, "%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); SaveData(szTemp, pcode.GetBuffer()); } #endif if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer())) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return NULL; } INCSTAT(stats.numPixelShadersCreated); SETSTAT(stats.numPixelShadersAlive, pshaders.size()); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); last_entry->shader.Bind(); return &last_entry->shader; }
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); }
SHADER* ProgramShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode, u32 components, u32 primitive_type) { SHADERUID uid; GetShaderId(&uid, dstAlphaMode, components, primitive_type); // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); last_entry->shader.Bind(); return &last_entry->shader; } } last_uid = uid; // Check if shader is already in cache PCache::iterator iter = pshaders.find(uid); if (iter != pshaders.end()) { PCacheEntry *entry = &iter->second; last_entry = entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); last_entry->shader.Bind(); return &last_entry->shader; } // Make an entry in the table PCacheEntry& newentry = pshaders[uid]; last_entry = &newentry; newentry.in_cache = 0; VertexShaderCode vcode; PixelShaderCode pcode; ShaderCode gcode; GenerateVertexShaderCode(vcode, components, API_OPENGL); GeneratePixelShaderCode(pcode, dstAlphaMode, API_OPENGL, components); if (g_ActiveConfig.backend_info.bSupportsGeometryShaders && !uid.guid.GetUidData()->IsPassthrough()) GenerateGeometryShaderCode(gcode, primitive_type, API_OPENGL); if (g_ActiveConfig.bEnableShaderDebugging) { newentry.shader.strvprog = vcode.GetBuffer(); newentry.shader.strpprog = pcode.GetBuffer(); newentry.shader.strgprog = gcode.GetBuffer(); } #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS) { static int counter = 0; std::string filename = StringFromFormat("%svs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); SaveData(filename, vcode.GetBuffer()); filename = StringFromFormat("%sps_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); SaveData(filename, pcode.GetBuffer()); if (gcode.GetBuffer() != nullptr) { filename = StringFromFormat("%sgs_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); SaveData(filename, gcode.GetBuffer()); } } #endif if (!CompileShader(newentry.shader, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer())) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return nullptr; } INCSTAT(stats.numPixelShadersCreated); SETSTAT(stats.numPixelShadersAlive, pshaders.size()); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); last_entry->shader.Bind(); return &last_entry->shader; }