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