Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 "content/browser/renderer_host/context_provider_factory_impl_android.h" | |
| 6 | |
| 7 #include "base/auto_reset.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/lazy_instance.h" | |
| 10 #include "base/memory/singleton.h" | |
| 11 #include "cc/output/context_provider.h" | |
| 12 #include "cc/output/vulkan_in_process_context_provider.h" | |
| 13 #include "content/browser/gpu/browser_gpu_channel_host_factory.h" | |
| 14 #include "content/browser/gpu/compositor_util.h" | |
| 15 #include "content/common/gpu/client/context_provider_command_buffer.h" | |
| 16 #include "content/public/common/content_switches.h" | |
| 17 #include "gpu/command_buffer/client/gles2_interface.h" | |
| 18 #include "gpu/ipc/client/gpu_channel_host.h" | |
| 19 | |
| 20 namespace content { | |
| 21 | |
| 22 base::LazyInstance<scoped_refptr<cc::VulkanInProcessContextProvider>> | |
| 23 g_shared_vulkan_context_provider_android = LAZY_INSTANCE_INITIALIZER; | |
| 24 | |
| 25 // static | |
| 26 ContextProviderFactory* ContextProviderFactory::GetInstance() { | |
| 27 return ContextProviderFactoryImpl::GetInstance(); | |
| 28 } | |
| 29 | |
| 30 ContextProviderFactory::ContextProviders::ContextProviders() = default; | |
| 31 | |
| 32 ContextProviderFactory::ContextProviders::~ContextProviders() = default; | |
| 33 | |
| 34 // static | |
| 35 ContextProviderFactoryImpl* ContextProviderFactoryImpl::GetInstance() { | |
| 36 return base::Singleton<ContextProviderFactoryImpl>::get(); | |
| 37 } | |
| 38 | |
| 39 ContextProviderFactoryImpl::ContextProviderFactoryImpl() | |
| 40 : in_handle_pending_requests_(false), weak_factory_(this) {} | |
| 41 | |
| 42 ContextProviderFactoryImpl::~ContextProviderFactoryImpl() {} | |
| 43 | |
| 44 void ContextProviderFactoryImpl::RequestRenderContextProvider( | |
| 45 ContextProviderCallback result_callback) { | |
| 46 render_context_request_callbacks_.push_back(result_callback); | |
| 47 | |
| 48 HandlePendingRequests(); | |
| 49 } | |
| 50 | |
| 51 void ContextProviderFactoryImpl::RequestGpuChannel( | |
| 52 GpuChannelRequestCallback gpu_channel_request_callback) { | |
| 53 gpu_channel_request_callback_ = gpu_channel_request_callback; | |
| 54 | |
| 55 HandlePendingRequests(); | |
| 56 } | |
| 57 | |
| 58 scoped_refptr<cc::VulkanInProcessContextProvider> | |
| 59 ContextProviderFactoryImpl::GetSharedVulkanContextProviderAndroid() { | |
| 60 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 61 switches::kEnableVulkan)) { | |
| 62 scoped_refptr<cc::VulkanInProcessContextProvider>* context_provider = | |
| 63 g_shared_vulkan_context_provider_android.Pointer(); | |
| 64 if (!*context_provider) | |
| 65 *context_provider = cc::VulkanInProcessContextProvider::Create(); | |
| 66 return *context_provider; | |
| 67 } | |
| 68 return nullptr; | |
| 69 } | |
| 70 | |
| 71 void ContextProviderFactoryImpl::HandlePendingRequests() { | |
| 72 // Failure to initialize the context could result in new requests. Handle | |
| 73 // them after going through the current list. | |
| 74 if (in_handle_pending_requests_) | |
| 75 return; | |
| 76 | |
| 77 { | |
| 78 base::AutoReset<bool> auto_reset_in_handle_requests( | |
| 79 &in_handle_pending_requests_, true); | |
| 80 | |
| 81 scoped_refptr<cc::VulkanInProcessContextProvider> vulkan_context_provider = | |
| 82 GetSharedVulkanContextProviderAndroid(); | |
| 83 | |
| 84 scoped_refptr<gpu::GpuChannelHost> gpu_channel_host( | |
| 85 vulkan_context_provider ? nullptr : EnsureGpuChannelEstablished()); | |
| 86 | |
| 87 if (!vulkan_context_provider && !gpu_channel_host) | |
| 88 return; | |
| 89 | |
| 90 if (!render_context_request_callbacks_.empty()) { | |
| 91 std::list<ContextProviderCallback> context_requests = | |
| 92 render_context_request_callbacks_; | |
| 93 render_context_request_callbacks_.clear(); | |
| 94 | |
| 95 for (ContextProviderCallback& context_request : context_requests) { | |
| 96 ContextProviders context_providers; | |
| 97 | |
| 98 if (vulkan_context_provider) | |
| 99 context_providers.vulkan_context_provider = vulkan_context_provider; | |
| 100 else | |
| 101 CreateRenderCompositorContexts(context_providers, gpu_channel_host); | |
| 102 | |
| 103 context_request.Run(context_providers); | |
| 104 } | |
| 105 } | |
| 106 | |
| 107 if (!gpu_channel_request_callback_.is_null()) { | |
| 108 if (!gpu_channel_host) | |
| 109 gpu_channel_host = EnsureGpuChannelEstablished(); | |
| 110 | |
| 111 if (!gpu_channel_host) | |
| 112 return; | |
| 113 | |
| 114 GpuChannelRequestCallback gpu_request_callback = | |
| 115 gpu_channel_request_callback_; | |
| 116 gpu_channel_request_callback_ = GpuChannelRequestCallback(); | |
| 117 gpu_request_callback.Run(gpu_channel_host); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 if (!gpu_channel_request_callback_.is_null() || | |
| 122 !render_context_request_callbacks_.empty()) | |
| 123 HandlePendingRequests(); | |
| 124 } | |
| 125 | |
| 126 void ContextProviderFactoryImpl::CreateRenderCompositorContexts( | |
| 127 ContextProviders& context_providers, | |
| 128 scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) { | |
| 129 DCHECK(gpu_channel_host); | |
| 130 | |
| 131 // TODO(khushalsagar): Figure out if we can share this code with the | |
| 132 // renderer compositor. | |
| 133 scoped_refptr<ContextProviderCommandBuffer> worker_context_provider = | |
| 134 SharedCompositorWorkerContextProvider(gpu_channel_host); | |
| 135 if (!worker_context_provider) { | |
| 136 // Cause the compositor to wait and try again. | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 // The renderer compositor context doesn't do a lot of stuff, so we don't | |
| 141 // expect it to need a lot of space for commands or transfer. Raster and | |
| 142 // uploads happen on the worker context instead. | |
| 143 gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext(); | |
| 144 | |
| 145 // This is for an offscreen context for the compositor. So the default | |
| 146 // framebuffer doesn't need alpha, depth, stencil, antialiasing. | |
| 147 gpu::gles2::ContextCreationAttribHelper attributes; | |
| 148 attributes.alpha_size = -1; | |
| 149 attributes.depth_size = 0; | |
| 150 attributes.stencil_size = 0; | |
| 151 attributes.samples = 0; | |
| 152 attributes.sample_buffers = 0; | |
| 153 attributes.bind_generates_resource = false; | |
| 154 attributes.lose_context_when_out_of_memory = true; | |
| 155 | |
| 156 constexpr bool automatic_flushes = false; | |
| 157 constexpr bool support_locking = false; | |
| 158 | |
| 159 // The compositor context shares resources with the worker context unless | |
| 160 // the worker is async. | |
| 161 ContextProviderCommandBuffer* share_context = worker_context_provider.get(); | |
| 162 if (IsAsyncWorkerContextEnabled()) | |
| 163 share_context = nullptr; | |
| 164 | |
| 165 scoped_refptr<ContextProviderCommandBuffer> context_provider( | |
| 166 new ContextProviderCommandBuffer( | |
| 167 gpu_channel_host, gpu::GPU_STREAM_DEFAULT, | |
| 168 gpu::GpuStreamPriority::NORMAL, gpu::kNullSurfaceHandle, | |
| 169 GURL(std::string("chrome://gpu/ContextProviderFactoryImpl::") + | |
| 170 std::string("CompositorContextProvider")), | |
| 171 automatic_flushes, support_locking, limits, attributes, share_context, | |
| 172 command_buffer_metrics::RENDER_COMPOSITOR_CONTEXT)); | |
| 173 | |
| 174 context_providers.compositor_context_provider = std::move(context_provider); | |
| 175 context_providers.worker_context_provider = | |
| 176 std::move(worker_context_provider); | |
| 177 } | |
| 178 | |
| 179 scoped_refptr<ContextProviderCommandBuffer> | |
| 180 ContextProviderFactoryImpl::SharedCompositorWorkerContextProvider( | |
| 181 scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) { | |
| 182 // Try to reuse existing shared worker context provider. | |
| 183 if (shared_worker_context_provider_) { | |
| 184 // Note: If context is lost, delete reference after releasing the lock. | |
| 185 cc::ContextProvider::ScopedContextLock lock( | |
| 186 shared_worker_context_provider_.get()); | |
| 187 if (shared_worker_context_provider_->ContextGL() | |
| 188 ->GetGraphicsResetStatusKHR() == GL_NO_ERROR) | |
| 189 return shared_worker_context_provider_; | |
| 190 } | |
| 191 | |
| 192 int32_t stream_id = gpu::GPU_STREAM_DEFAULT; | |
| 193 gpu::GpuStreamPriority stream_priority = gpu::GpuStreamPriority::NORMAL; | |
| 194 if (IsAsyncWorkerContextEnabled()) { | |
| 195 stream_id = gpu_channel_host->GenerateStreamID(); | |
| 196 stream_priority = gpu::GpuStreamPriority::LOW; | |
| 197 } | |
| 198 | |
| 199 bool support_locking = true; | |
| 200 gpu::gles2::ContextCreationAttribHelper attributes; | |
| 201 attributes.alpha_size = -1; | |
| 202 attributes.depth_size = 0; | |
| 203 attributes.stencil_size = 0; | |
| 204 attributes.samples = 0; | |
| 205 attributes.sample_buffers = 0; | |
| 206 attributes.bind_generates_resource = false; | |
| 207 attributes.lose_context_when_out_of_memory = true; | |
| 208 const bool automatic_flushes = false; | |
| 209 | |
| 210 shared_worker_context_provider_ = new ContextProviderCommandBuffer( | |
| 211 std::move(gpu_channel_host), stream_id, stream_priority, | |
| 212 gpu::kNullSurfaceHandle, | |
| 213 GURL(std::string("chrome://gpu/ContextProviderFactoryImpl::") + | |
| 214 std::string("SharedCompositorWorkerContextProvider")), | |
| 215 automatic_flushes, support_locking, gpu::SharedMemoryLimits(), attributes, | |
| 216 nullptr, command_buffer_metrics::RENDER_WORKER_CONTEXT); | |
| 217 | |
| 218 if (!shared_worker_context_provider_->BindToCurrentThread()) | |
|
Khushal
2016/07/28 18:12:31
Does this look correct? We do it on the main threa
| |
| 219 shared_worker_context_provider_ = nullptr; | |
| 220 return shared_worker_context_provider_; | |
| 221 } | |
| 222 | |
| 223 gpu::GpuChannelHost* ContextProviderFactoryImpl::EnsureGpuChannelEstablished() { | |
| 224 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \ | |
| 225 defined(SYZYASAN) || defined(CYGPROFILE_INSTRUMENTATION) | |
| 226 const int64_t kGpuChannelTimeoutInSeconds = 40; | |
| 227 #else | |
| 228 const int64_t kGpuChannelTimeoutInSeconds = 10; | |
| 229 #endif | |
| 230 | |
| 231 BrowserGpuChannelHostFactory* factory = | |
| 232 BrowserGpuChannelHostFactory::instance(); | |
| 233 | |
| 234 if (factory->GetGpuChannel()) | |
| 235 return factory->GetGpuChannel(); | |
| 236 | |
| 237 factory->EstablishGpuChannel( | |
| 238 CAUSE_FOR_GPU_LAUNCH_DISPLAY_COMPOSITOR_CONTEXT, | |
| 239 base::Bind(&ContextProviderFactoryImpl::OnGpuChannelEstablished, | |
| 240 weak_factory_.GetWeakPtr())); | |
| 241 establish_gpu_channel_timeout_.Start( | |
| 242 FROM_HERE, base::TimeDelta::FromSeconds(kGpuChannelTimeoutInSeconds), | |
| 243 this, &ContextProviderFactoryImpl::OnGpuChannelTimeout); | |
| 244 | |
| 245 return nullptr; | |
| 246 } | |
| 247 | |
| 248 void ContextProviderFactoryImpl::OnGpuChannelEstablished() { | |
| 249 establish_gpu_channel_timeout_.Stop(); | |
| 250 HandlePendingRequests(); | |
| 251 } | |
| 252 | |
| 253 void ContextProviderFactoryImpl::OnGpuChannelTimeout() { | |
| 254 LOG(FATAL) << "Timed out waiting for GPU channel."; | |
| 255 } | |
| 256 | |
| 257 } // namespace content | |
| OLD | NEW |