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