swiftshader_component_installer.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/component_updater/swiftshader_component_installer.h" 6 7#include "base/base_paths.h" 8#include "base/bind.h" 9#include "base/compiler_specific.h" 10#include "base/cpu.h" 11#include "base/file_util.h" 12#include "base/files/file_enumerator.h" 13#include "base/files/file_path.h" 14#include "base/logging.h" 15#include "base/path_service.h" 16#include "base/strings/string_util.h" 17#include "base/values.h" 18#include "chrome/browser/component_updater/component_updater_service.h" 19#include "chrome/common/chrome_paths.h" 20#include "content/public/browser/browser_thread.h" 21#include "content/public/browser/gpu_data_manager.h" 22#include "content/public/browser/gpu_data_manager_observer.h" 23#include "gpu/config/gpu_feature_type.h" 24 25using content::BrowserThread; 26using content::GpuDataManager; 27 28namespace { 29 30// CRX hash. The extension id is: nhfgdggnnopgbfdlpeoalgcjdgfafocg. 31const uint8 kSha2Hash[] = {0xd7, 0x56, 0x36, 0x6d, 0xde, 0xf6, 0x15, 0x3b, 32 0xf4, 0xe0, 0xb6, 0x29, 0x36, 0x50, 0x5e, 0x26, 33 0xbd, 0x77, 0x8b, 0x8e, 0x35, 0xc2, 0x7e, 0x43, 34 0x52, 0x47, 0x62, 0xed, 0x12, 0xca, 0xcc, 0x6a}; 35 36// File name of the internal SwiftShader plugin on different platforms. 37const base::FilePath::CharType kSwiftShaderEglName[] = 38 FILE_PATH_LITERAL("libegl.dll"); 39const base::FilePath::CharType kSwiftShaderGlesName[] = 40 FILE_PATH_LITERAL("libglesv2.dll"); 41 42const char kSwiftShaderManifestName[] = "SwiftShader"; 43 44const base::FilePath::CharType kSwiftShaderBaseDirectory[] = 45 FILE_PATH_LITERAL("SwiftShader"); 46 47// If we don't have a SwiftShader component, this is the version we claim. 48const char kNullVersion[] = "0.0.0.0"; 49 50// The base directory on windows looks like: 51// <profile>\AppData\Local\Google\Chrome\User Data\SwiftShader\. 52base::FilePath GetSwiftShaderBaseDirectory() { 53 base::FilePath result; 54 PathService::Get(chrome::DIR_USER_DATA, &result); 55 return result.Append(kSwiftShaderBaseDirectory); 56} 57 58// SwiftShader has version encoded in the path itself 59// so we need to enumerate the directories to find the full path. 60// On success it returns something like: 61// <profile>\AppData\Local\Google\Chrome\User Data\SwiftShader\10.3.44.555\. 62bool GetLatestSwiftShaderDirectory(base::FilePath* result, 63 Version* latest, 64 std::vector<base::FilePath>* older_dirs) { 65 base::FilePath base_dir = GetSwiftShaderBaseDirectory(); 66 bool found = false; 67 base::FileEnumerator 68 file_enumerator(base_dir, false, base::FileEnumerator::DIRECTORIES); 69 for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); 70 path = file_enumerator.Next()) { 71 Version version(path.BaseName().MaybeAsASCII()); 72 if (!version.IsValid()) 73 continue; 74 if (version.CompareTo(*latest) > 0 && 75 file_util::PathExists(path.Append(kSwiftShaderEglName)) && 76 file_util::PathExists(path.Append(kSwiftShaderGlesName))) { 77 if (found && older_dirs) 78 older_dirs->push_back(*result); 79 *latest = version; 80 *result = path; 81 found = true; 82 } else { 83 if (older_dirs) 84 older_dirs->push_back(path); 85 } 86 } 87 return found; 88} 89 90void RegisterSwiftShaderWithChrome(const base::FilePath& path) { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 92 GpuDataManager::GetInstance()->RegisterSwiftShaderPath(path); 93} 94 95} // namespace 96 97class SwiftShaderComponentInstaller : public ComponentInstaller { 98 public: 99 explicit SwiftShaderComponentInstaller(const Version& version); 100 101 virtual ~SwiftShaderComponentInstaller() {} 102 103 virtual void OnUpdateError(int error) OVERRIDE; 104 105 virtual bool Install(const base::DictionaryValue& manifest, 106 const base::FilePath& unpack_path) OVERRIDE; 107 108 private: 109 Version current_version_; 110}; 111 112SwiftShaderComponentInstaller::SwiftShaderComponentInstaller( 113 const Version& version) : current_version_(version) { 114 DCHECK(version.IsValid()); 115} 116 117void SwiftShaderComponentInstaller::OnUpdateError(int error) { 118 NOTREACHED() << "SwiftShader update error: " << error; 119} 120 121bool SwiftShaderComponentInstaller::Install( 122 const base::DictionaryValue& manifest, 123 const base::FilePath& unpack_path) { 124 std::string name; 125 manifest.GetStringASCII("name", &name); 126 if (name != kSwiftShaderManifestName) 127 return false; 128 std::string proposed_version; 129 manifest.GetStringASCII("version", &proposed_version); 130 Version version(proposed_version.c_str()); 131 if (!version.IsValid()) 132 return false; 133 if (current_version_.CompareTo(version) >= 0) 134 return false; 135 if (!file_util::PathExists(unpack_path.Append(kSwiftShaderEglName)) || 136 !file_util::PathExists(unpack_path.Append(kSwiftShaderGlesName))) 137 return false; 138 // Passed the basic tests. Time to install it. 139 base::FilePath path = 140 GetSwiftShaderBaseDirectory().AppendASCII(version.GetString()); 141 if (file_util::PathExists(path)) 142 return false; 143 if (!file_util::Move(unpack_path, path)) 144 return false; 145 // Installation is done. Now tell the rest of chrome. 146 current_version_ = version; 147 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 148 base::Bind(&RegisterSwiftShaderWithChrome, path)); 149 return true; 150} 151 152void FinishSwiftShaderUpdateRegistration(ComponentUpdateService* cus, 153 const Version& version) { 154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 155 156 CrxComponent swiftshader; 157 swiftshader.name = "Swift Shader"; 158 swiftshader.installer = new SwiftShaderComponentInstaller(version); 159 swiftshader.version = version; 160 swiftshader.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]); 161 if (cus->RegisterComponent(swiftshader) != ComponentUpdateService::kOk) { 162 NOTREACHED() << "SwiftShader component registration fail"; 163 } 164} 165 166class UpdateChecker : public content::GpuDataManagerObserver { 167 public: 168 explicit UpdateChecker(ComponentUpdateService* cus); 169 170 virtual void OnGpuInfoUpdate() OVERRIDE; 171 172 private: 173 ComponentUpdateService* cus_; 174}; 175 176UpdateChecker::UpdateChecker(ComponentUpdateService* cus) 177 : cus_(cus) { 178} 179 180void UpdateChecker::OnGpuInfoUpdate() { 181 GpuDataManager *gpu_data_manager = GpuDataManager::GetInstance(); 182 183 if (!gpu_data_manager->GpuAccessAllowed(NULL) || 184 gpu_data_manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) || 185 gpu_data_manager->ShouldUseSwiftShader()) { 186 gpu_data_manager->RemoveObserver(this); 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 188 base::FilePath path = GetSwiftShaderBaseDirectory(); 189 190 Version version(kNullVersion); 191 GetLatestSwiftShaderDirectory(&path, &version, NULL); 192 193 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 194 base::Bind(&FinishSwiftShaderUpdateRegistration, cus_, version)); 195 } 196} 197 198// Check if there already is a version of swiftshader installed, 199// and if so register it. 200void RegisterSwiftShaderPath(ComponentUpdateService* cus) { 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 202 base::FilePath path = GetSwiftShaderBaseDirectory(); 203 if (!file_util::PathExists(path)) { 204 if (!file_util::CreateDirectory(path)) { 205 NOTREACHED() << "Could not create SwiftShader directory."; 206 return; 207 } 208 } 209 210 Version version(kNullVersion); 211 std::vector<base::FilePath> older_dirs; 212 if (GetLatestSwiftShaderDirectory(&path, &version, &older_dirs)) 213 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 214 base::Bind(&RegisterSwiftShaderWithChrome, path)); 215 216 UpdateChecker *update_checker = new UpdateChecker(cus); 217 GpuDataManager::GetInstance()->AddObserver(update_checker); 218 update_checker->OnGpuInfoUpdate(); 219 // We leak update_checker here, because it has to stick around for the life 220 // of the GpuDataManager. 221 222 // Remove older versions of SwiftShader. 223 for (std::vector<base::FilePath>::iterator iter = older_dirs.begin(); 224 iter != older_dirs.end(); ++iter) { 225 file_util::Delete(*iter, true); 226 } 227} 228 229void RegisterSwiftShaderComponent(ComponentUpdateService* cus) { 230#if defined(ENABLE_SWIFTSHADER) 231 base::CPU cpu; 232 233 if (!cpu.has_sse2()) 234 return; 235 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 236 base::Bind(&RegisterSwiftShaderPath, cus)); 237#endif 238} 239