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 PixelShaderCache::SetShader(DSTALPHA_MODE dstAlphaMode) { PixelShaderUid uid = GetPixelShaderUid(dstAlphaMode, API_OPENGL); // Check if the shader is already set if (last_entry) { if (uid == last_uid) { return true; } } last_uid = uid; // Check if the shader is already in the cache PSCache::iterator iter; iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { const std::string &entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return true; } // Need to compile a new shader ShaderCode code = GeneratePixelShaderCode(dstAlphaMode, API_OPENGL); PixelShaders.insert(std::make_pair(uid, code.GetBuffer())); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return true; }
bool VertexShaderCache::UberVertexShaderCompilerWorkItem::Compile() { ShaderCode code = UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), m_uid.GetUidData()); if (D3D::CompileVertexShader(code.GetBuffer(), &m_bytecode)) m_vs = D3D::CreateVertexShaderFromByteCode(m_bytecode); return true; }
bool GeometryShaderCache::SetShader(u32 primitive_type) { GeometryShaderUid uid = GetGeometryShaderUid(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); return true; } } last_uid = uid; // Check if the shader is a pass-through shader if (uid.GetUidData()->IsPassthrough()) { // Return the default pass-through shader last_entry = &pass_entry; return true; } // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); if (iter != GeometryShaders.end()) { const GSCacheEntry& entry = iter->second; last_entry = &entry; return (entry.shader != nullptr); } // Need to compile a new shader ShaderCode code = GenerateGeometryShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); return success; }
bool PixelShaderCache::SetShader() { PixelShaderUid uid = GetPixelShaderUid(); // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return (last_entry->shader != nullptr); } } last_uid = uid; // Check if the shader is already in the cache PSCache::iterator iter; iter = PixelShaders.find(uid); if (iter != PixelShaders.end()) { const PSCacheEntry& entry = iter->second; last_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return (entry.shader != nullptr); } // Need to compile a new shader ShaderCode code = GeneratePixelShaderCode(APIType::D3D, uid.GetUidData()); D3DBlob* pbytecode; if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_ps_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE, true); return success; }
bool VertexShaderCache::SetUberShader(D3DVertexFormat* vertex_format) { D3DVertexFormat* uber_vertex_format = static_cast<D3DVertexFormat*>( VertexLoaderManager::GetUberVertexFormat(vertex_format->GetVertexDeclaration())); UberShader::VertexShaderUid uid = UberShader::GetVertexShaderUid(); if (last_uber_entry && last_uber_uid == uid) { if (!last_uber_entry->shader) return false; uber_vertex_format->SetInputLayout(last_uber_entry->bytecode); D3D::stateman->SetVertexShader(last_uber_entry->shader); return true; } auto iter = ubervshaders.find(uid); if (iter != ubervshaders.end()) { const VSCacheEntry& entry = iter->second; last_uber_uid = uid; last_uber_entry = &entry; GFX_DEBUGGER_PAUSE_AT(NEXT_VERTEX_SHADER_CHANGE, true); if (!last_uber_entry->shader) return false; uber_vertex_format->SetInputLayout(last_uber_entry->bytecode); D3D::stateman->SetVertexShader(last_uber_entry->shader); return true; } // Need to compile a new shader D3DBlob* bytecode = nullptr; ShaderCode code = UberShader::GenVertexShader(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3D::CompileVertexShader(code.GetBuffer(), &bytecode); if (!InsertByteCode(uid, bytecode)) { SAFE_RELEASE(bytecode); return false; } g_uber_vs_disk_cache.Append(uid, bytecode->Data(), bytecode->Size()); bytecode->Release(); return SetUberShader(vertex_format); }
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 LineGeometryShader::SetShader(u32 components, float lineWidth, float texOffset, float vpWidth, float vpHeight, const bool* texOffsetEnable) { if (!m_ready) return false; // Make sure geometry shader for "components" is available ComboMap::iterator shaderIt = m_shaders.find(components); if (shaderIt == m_shaders.end()) { // Generate new shader. Warning: not thread-safe. static char buffer[16384]; ShaderCode code; code.SetBuffer(buffer); GenerateVSOutputStructForGS(code, API_D3D); code.Write("\n%s", LINE_GS_COMMON); std::stringstream numTexCoordsStream; numTexCoordsStream << xfmem.numTexGen.numTexGens; INFO_LOG(VIDEO, "Compiling line geometry shader for components 0x%.08X (num texcoords %d)", components, xfmem.numTexGen.numTexGens); const std::string& numTexCoordsStr = numTexCoordsStream.str(); D3D_SHADER_MACRO macros[] = { { "NUM_TEXCOORDS", numTexCoordsStr.c_str() }, { nullptr, nullptr } }; ID3D11GeometryShader* newShader = D3D::CompileAndCreateGeometryShader(code.GetBuffer(), macros); if (!newShader) { WARN_LOG(VIDEO, "Line geometry shader for components 0x%.08X failed to compile", components); // Add dummy shader to prevent trying to compile again m_shaders[components] = nullptr; return false; } shaderIt = m_shaders.insert(std::make_pair(components, newShader)).first; } if (shaderIt != m_shaders.end()) { if (shaderIt->second) { D3D11_MAPPED_SUBRESOURCE map; HRESULT hr = D3D::context->Map(m_paramsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); if (SUCCEEDED(hr)) { LineGSParams* params = (LineGSParams*)map.pData; params->LineWidth = lineWidth; params->TexOffset = texOffset; params->VpWidth = vpWidth; params->VpHeight = vpHeight; for (int i = 0; i < 8; ++i) params->TexOffsetEnable[i] = texOffsetEnable[i] ? 1.f : 0.f; D3D::context->Unmap(m_paramsBuffer, 0); } else ERROR_LOG(VIDEO, "Failed to map line gs params buffer"); DEBUG_LOG(VIDEO, "Line params: width %f, texOffset %f, vpWidth %f, vpHeight %f", lineWidth, texOffset, vpWidth, vpHeight); D3D::context->GSSetShader(shaderIt->second, nullptr, 0); D3D::context->GSSetConstantBuffers(0, 1, &m_paramsBuffer); return true; } else return false; } else return false; }
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); }
bool GeometryShaderCache::SetShader(u32 primitive_type) { switch (primitive_type) { case PRIMITIVE_TRIANGLES: currentPrimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; break; case PRIMITIVE_LINES: currentPrimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; break; case PRIMITIVE_POINTS: currentPrimitiveTopology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; break; default: CHECK(0, "Invalid primitive type."); break; } GeometryShaderUid uid = GetGeometryShaderUid(primitive_type, API_D3D); // Check if the shader is already set if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return true; } last_uid = uid; D3D::commandListMgr->dirtyPso = true; if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); } // Check if the shader is a pass-through shader if (uid.GetUidData()->IsPassthrough()) { // Return the default pass-through shader last_entry = &pass_entry; return true; } // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); if (iter != GeometryShaders.end()) { const GSCacheEntry &entry = iter->second; last_entry = &entry; return (entry.shader12.pShaderBytecode != nullptr); } // Need to compile a new shader ShaderCode code = GenerateGeometryShaderCode(primitive_type, API_D3D); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { GeometryShaders[uid].code = code.GetBuffer(); } return success; }
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; }
bool GeometryShaderCache::SetShader(u32 primitive_type) { GeometryShaderUid uid; GetGeometryShaderUid(uid, primitive_type, API_D3D); if (g_ActiveConfig.bEnableShaderDebugging) { ShaderCode code; GenerateGeometryShaderCode(code, primitive_type, API_D3D); geometry_uid_checker.AddToIndexAndCheck(code, uid, "Geometry", "g"); } // Check if the shader is already set if (last_entry) { if (uid == last_uid) { GFX_DEBUGGER_PAUSE_AT(NEXT_PIXEL_SHADER_CHANGE,true); return true; } } last_uid = uid; // Check if the shader is a pass-through shader if (uid.GetUidData()->IsPassthrough()) { // Return the default pass-through shader last_entry = &pass_entry; return true; } // Check if the shader is already in the cache GSCache::iterator iter; iter = GeometryShaders.find(uid); if (iter != GeometryShaders.end()) { const GSCacheEntry &entry = iter->second; last_entry = &entry; return (entry.shader != nullptr); } // Need to compile a new shader ShaderCode code; GenerateGeometryShaderCode(code, primitive_type, API_D3D); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) { GFX_DEBUGGER_PAUSE_AT(NEXT_ERROR, true); return false; } // Insert the bytecode into the caches g_gs_disk_cache.Append(uid, pbytecode->Data(), pbytecode->Size()); bool success = InsertByteCode(uid, pbytecode->Data(), pbytecode->Size()); pbytecode->Release(); if (g_ActiveConfig.bEnableShaderDebugging && success) { GeometryShaders[uid].code = code.GetBuffer(); } return success; }