| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 "blimp/client/core/compositor/blimp_compositor.h" | |
| 6 | |
| 7 #include "base/bind_helpers.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/memory/ptr_util.h" | |
| 10 #include "base/metrics/histogram_macros.h" | |
| 11 #include "base/numerics/safe_conversions.h" | |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "base/threading/thread.h" | |
| 14 #include "base/threading/thread_local.h" | |
| 15 #include "base/threading/thread_restrictions.h" | |
| 16 #include "base/threading/thread_task_runner_handle.h" | |
| 17 #include "blimp/client/core/compositor/blimp_compositor_dependencies.h" | |
| 18 #include "blimp/client/core/compositor/blimp_compositor_frame_sink.h" | |
| 19 #include "blimp/client/public/compositor/compositor_dependencies.h" | |
| 20 #include "blimp/net/blimp_stats.h" | |
| 21 #include "cc/animation/animation_host.h" | |
| 22 #include "cc/blimp/client_picture_cache.h" | |
| 23 #include "cc/blimp/compositor_state_deserializer.h" | |
| 24 #include "cc/blimp/image_serialization_processor.h" | |
| 25 #include "cc/layers/layer.h" | |
| 26 #include "cc/layers/surface_layer.h" | |
| 27 #include "cc/output/compositor_frame_sink.h" | |
| 28 #include "cc/proto/compositor_message.pb.h" | |
| 29 #include "cc/surfaces/surface.h" | |
| 30 #include "cc/surfaces/surface_factory.h" | |
| 31 #include "cc/surfaces/surface_id_allocator.h" | |
| 32 #include "cc/surfaces/surface_manager.h" | |
| 33 #include "cc/trees/layer_tree_host_in_process.h" | |
| 34 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" | |
| 35 #include "net/base/net_errors.h" | |
| 36 #include "ui/gl/gl_surface.h" | |
| 37 | |
| 38 namespace blimp { | |
| 39 namespace client { | |
| 40 | |
| 41 class BlimpCompositor::FrameTrackingSwapPromise : public cc::SwapPromise { | |
| 42 public: | |
| 43 FrameTrackingSwapPromise( | |
| 44 std::unique_ptr<cc::CopyOutputRequest> copy_request, | |
| 45 base::WeakPtr<BlimpCompositor> compositor, | |
| 46 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) | |
| 47 : copy_request_(std::move(copy_request)), | |
| 48 compositor_weak_ptr_(compositor), | |
| 49 main_task_runner_(std::move(main_task_runner)) {} | |
| 50 ~FrameTrackingSwapPromise() override = default; | |
| 51 | |
| 52 // cc::SwapPromise implementation. | |
| 53 void DidActivate() override {} | |
| 54 void WillSwap(cc::CompositorFrameMetadata* metadata) override {} | |
| 55 void DidSwap() override { | |
| 56 // DidSwap could be called on compositor thread and we need this to run on | |
| 57 // the main thread. | |
| 58 main_task_runner_->PostTask( | |
| 59 FROM_HERE, | |
| 60 base::Bind(&BlimpCompositor::MakeCopyRequestOnNextSwap, | |
| 61 compositor_weak_ptr_, base::Passed(©_request_))); | |
| 62 } | |
| 63 DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { | |
| 64 switch (reason) { | |
| 65 case DidNotSwapReason::SWAP_FAILS: | |
| 66 // The swap will fail if there is no frame damage, we can queue the | |
| 67 // request right away. | |
| 68 main_task_runner_->PostTask( | |
| 69 FROM_HERE, base::Bind(&BlimpCompositor::RequestCopyOfOutput, | |
| 70 compositor_weak_ptr_, | |
| 71 base::Passed(©_request_), false)); | |
| 72 break; | |
| 73 case DidNotSwapReason::COMMIT_FAILS: | |
| 74 // The commit fails when the host is going away. | |
| 75 break; | |
| 76 case DidNotSwapReason::COMMIT_NO_UPDATE: | |
| 77 main_task_runner_->PostTask( | |
| 78 FROM_HERE, base::Bind(&BlimpCompositor::RequestCopyOfOutput, | |
| 79 compositor_weak_ptr_, | |
| 80 base::Passed(©_request_), false)); | |
| 81 break; | |
| 82 case DidNotSwapReason::ACTIVATION_FAILS: | |
| 83 // Failure to activate the pending tree implies either the host in going | |
| 84 // away or the FrameSink was lost. | |
| 85 break; | |
| 86 } | |
| 87 return DidNotSwapAction::BREAK_PROMISE; | |
| 88 } | |
| 89 int64_t TraceId() const override { return 0; } | |
| 90 | |
| 91 private: | |
| 92 std::unique_ptr<cc::CopyOutputRequest> copy_request_; | |
| 93 base::WeakPtr<BlimpCompositor> compositor_weak_ptr_; | |
| 94 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | |
| 95 }; | |
| 96 | |
| 97 // static | |
| 98 std::unique_ptr<BlimpCompositor> BlimpCompositor::Create( | |
| 99 BlimpCompositorDependencies* compositor_dependencies, | |
| 100 BlimpCompositorClient* client) { | |
| 101 std::unique_ptr<BlimpCompositor> compositor = | |
| 102 base::WrapUnique(new BlimpCompositor(compositor_dependencies, client)); | |
| 103 compositor->Initialize(); | |
| 104 return compositor; | |
| 105 } | |
| 106 | |
| 107 BlimpCompositor::BlimpCompositor( | |
| 108 BlimpCompositorDependencies* compositor_dependencies, | |
| 109 BlimpCompositorClient* client) | |
| 110 : client_(client), | |
| 111 compositor_dependencies_(compositor_dependencies), | |
| 112 frame_sink_id_(compositor_dependencies_->GetEmbedderDependencies() | |
| 113 ->AllocateFrameSinkId()), | |
| 114 proxy_client_(nullptr), | |
| 115 bound_to_proxy_(false), | |
| 116 compositor_frame_sink_request_pending_(false), | |
| 117 layer_(cc::Layer::Create()), | |
| 118 weak_ptr_factory_(this) { | |
| 119 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 120 } | |
| 121 | |
| 122 void BlimpCompositor::Initialize() { | |
| 123 surface_id_allocator_ = base::MakeUnique<cc::SurfaceIdAllocator>(); | |
| 124 GetEmbedderDeps()->GetSurfaceManager()->RegisterFrameSinkId(frame_sink_id_); | |
| 125 surface_factory_ = base::MakeUnique<cc::SurfaceFactory>( | |
| 126 frame_sink_id_, GetEmbedderDeps()->GetSurfaceManager(), this); | |
| 127 animation_host_ = cc::AnimationHost::CreateMainInstance(); | |
| 128 host_ = CreateLayerTreeHost(); | |
| 129 | |
| 130 std::unique_ptr<cc::ClientPictureCache> client_picture_cache = | |
| 131 compositor_dependencies_->GetImageSerializationProcessor() | |
| 132 ->CreateClientPictureCache(); | |
| 133 compositor_state_deserializer_ = | |
| 134 base::MakeUnique<cc::CompositorStateDeserializer>( | |
| 135 host_.get(), std::move(client_picture_cache), this); | |
| 136 } | |
| 137 | |
| 138 BlimpCompositor::~BlimpCompositor() { | |
| 139 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 140 | |
| 141 DestroyLayerTreeHost(); | |
| 142 GetEmbedderDeps()->GetSurfaceManager()->InvalidateFrameSinkId(frame_sink_id_); | |
| 143 } | |
| 144 | |
| 145 void BlimpCompositor::SetVisible(bool visible) { | |
| 146 host_->SetVisible(visible); | |
| 147 } | |
| 148 | |
| 149 bool BlimpCompositor::IsVisible() const { | |
| 150 return host_->IsVisible(); | |
| 151 } | |
| 152 | |
| 153 bool BlimpCompositor::HasPendingFrameUpdateFromEngine() const { | |
| 154 return pending_frame_update_.get() != nullptr; | |
| 155 } | |
| 156 | |
| 157 void BlimpCompositor::RequestCopyOfOutput( | |
| 158 std::unique_ptr<cc::CopyOutputRequest> copy_request, | |
| 159 bool flush_pending_update) { | |
| 160 // If we don't have a FrameSink, fail right away. | |
| 161 if (!bound_to_proxy_) | |
| 162 return; | |
| 163 | |
| 164 if (flush_pending_update) { | |
| 165 // Always request a commit when queuing the promise to make sure that any | |
| 166 // frames pending draws are cleared from the pipeline. | |
| 167 host_->QueueSwapPromise(base::MakeUnique<FrameTrackingSwapPromise>( | |
| 168 std::move(copy_request), weak_ptr_factory_.GetWeakPtr(), | |
| 169 base::ThreadTaskRunnerHandle::Get())); | |
| 170 host_->SetNeedsCommit(); | |
| 171 } else if (local_frame_id_.is_valid()) { | |
| 172 // Make a copy request for the surface directly. | |
| 173 surface_factory_->RequestCopyOfSurface(std::move(copy_request)); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 void BlimpCompositor::UpdateLayerTreeHost() { | |
| 178 // UpdateLayerTreeHost marks the end of reporting of any deltas from the impl | |
| 179 // thread. So send a client state update if the local state was modified now. | |
| 180 FlushClientState(); | |
| 181 | |
| 182 if (pending_frame_update_) { | |
| 183 compositor_state_deserializer_->DeserializeCompositorUpdate( | |
| 184 pending_frame_update_->layer_tree_host()); | |
| 185 pending_frame_update_ = nullptr; | |
| 186 cc::proto::CompositorMessage frame_ack; | |
| 187 frame_ack.set_frame_ack(true); | |
| 188 client_->SendCompositorMessage(frame_ack); | |
| 189 } | |
| 190 | |
| 191 // Send back any deltas that have not yet been resolved on the main thread | |
| 192 // back to the impl thread. | |
| 193 compositor_state_deserializer_->SendUnappliedDeltasToLayerTreeHost(); | |
| 194 } | |
| 195 | |
| 196 void BlimpCompositor::ApplyViewportDeltas( | |
| 197 const gfx::Vector2dF& inner_delta, | |
| 198 const gfx::Vector2dF& outer_delta, | |
| 199 const gfx::Vector2dF& elastic_overscroll_delta, | |
| 200 float page_scale, | |
| 201 float top_controls_delta) { | |
| 202 compositor_state_deserializer_->ApplyViewportDeltas( | |
| 203 inner_delta, outer_delta, elastic_overscroll_delta, page_scale, | |
| 204 top_controls_delta); | |
| 205 } | |
| 206 | |
| 207 void BlimpCompositor::RequestNewCompositorFrameSink() { | |
| 208 DCHECK(!bound_to_proxy_); | |
| 209 DCHECK(!compositor_frame_sink_request_pending_); | |
| 210 | |
| 211 compositor_frame_sink_request_pending_ = true; | |
| 212 GetEmbedderDeps()->GetContextProviders( | |
| 213 base::Bind(&BlimpCompositor::OnContextProvidersCreated, | |
| 214 weak_ptr_factory_.GetWeakPtr())); | |
| 215 } | |
| 216 | |
| 217 void BlimpCompositor::DidInitializeCompositorFrameSink() { | |
| 218 compositor_frame_sink_request_pending_ = false; | |
| 219 } | |
| 220 | |
| 221 void BlimpCompositor::DidCommitAndDrawFrame() {} | |
| 222 | |
| 223 void BlimpCompositor::OnCompositorMessageReceived( | |
| 224 std::unique_ptr<cc::proto::CompositorMessage> message) { | |
| 225 cc::proto::CompositorMessage* message_received = message.get(); | |
| 226 | |
| 227 if (message_received->has_layer_tree_host()) { | |
| 228 DCHECK(!pending_frame_update_) | |
| 229 << "We should have only a single frame in flight"; | |
| 230 | |
| 231 UMA_HISTOGRAM_MEMORY_KB("Blimp.Compositor.CommitSizeKb", | |
| 232 (float)message->ByteSize() / 1024); | |
| 233 BlimpStats::GetInstance()->Add(BlimpStats::COMMIT, 1); | |
| 234 | |
| 235 pending_frame_update_ = std::move(message); | |
| 236 host_->SetNeedsAnimate(); | |
| 237 } | |
| 238 | |
| 239 if (message_received->client_state_update_ack()) { | |
| 240 DCHECK(client_state_update_ack_pending_); | |
| 241 | |
| 242 client_state_update_ack_pending_ = false; | |
| 243 compositor_state_deserializer_->DidApplyStateUpdatesOnEngine(); | |
| 244 | |
| 245 // If there are any updates that we have queued because we were waiting for | |
| 246 // an ack, send them now. | |
| 247 FlushClientState(); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 const base::WeakPtr<cc::InputHandler>& BlimpCompositor::GetInputHandler() { | |
| 252 return host_->GetInputHandler(); | |
| 253 } | |
| 254 | |
| 255 void BlimpCompositor::OnContextProvidersCreated( | |
| 256 const scoped_refptr<cc::ContextProvider>& compositor_context_provider, | |
| 257 const scoped_refptr<cc::ContextProvider>& worker_context_provider) { | |
| 258 DCHECK(!bound_to_proxy_) << "Any connection to the old CompositorFrameSink " | |
| 259 "should have been destroyed"; | |
| 260 | |
| 261 // Make sure we still have a host and we're still expecting a | |
| 262 // CompositorFrameSink. This can happen if the host dies while the request is | |
| 263 // outstanding and we build a new one that hasn't asked for a surface yet. | |
| 264 if (!compositor_frame_sink_request_pending_) | |
| 265 return; | |
| 266 | |
| 267 // Try again if the context creation failed. | |
| 268 if (!compositor_context_provider) { | |
| 269 GetEmbedderDeps()->GetContextProviders( | |
| 270 base::Bind(&BlimpCompositor::OnContextProvidersCreated, | |
| 271 weak_ptr_factory_.GetWeakPtr())); | |
| 272 return; | |
| 273 } | |
| 274 | |
| 275 auto compositor_frame_sink = base::MakeUnique<BlimpCompositorFrameSink>( | |
| 276 std::move(compositor_context_provider), | |
| 277 std::move(worker_context_provider), | |
| 278 GetEmbedderDeps()->GetGpuMemoryBufferManager(), nullptr, | |
| 279 base::ThreadTaskRunnerHandle::Get(), weak_ptr_factory_.GetWeakPtr()); | |
| 280 | |
| 281 host_->SetCompositorFrameSink(std::move(compositor_frame_sink)); | |
| 282 } | |
| 283 | |
| 284 void BlimpCompositor::BindToProxyClient( | |
| 285 base::WeakPtr<BlimpCompositorFrameSinkProxyClient> proxy_client) { | |
| 286 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 287 DCHECK(!bound_to_proxy_); | |
| 288 | |
| 289 bound_to_proxy_ = true; | |
| 290 proxy_client_ = proxy_client; | |
| 291 } | |
| 292 | |
| 293 void BlimpCompositor::SubmitCompositorFrame(cc::CompositorFrame frame) { | |
| 294 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 295 DCHECK(bound_to_proxy_); | |
| 296 | |
| 297 cc::RenderPass* root_pass = frame.render_pass_list.back().get(); | |
| 298 gfx::Size surface_size = root_pass->output_rect.size(); | |
| 299 | |
| 300 if (!local_frame_id_.is_valid() || current_surface_size_ != surface_size) { | |
| 301 DestroyDelegatedContent(); | |
| 302 DCHECK(layer_->children().empty()); | |
| 303 | |
| 304 local_frame_id_ = surface_id_allocator_->GenerateId(); | |
| 305 current_surface_size_ = surface_size; | |
| 306 | |
| 307 // manager must outlive compositors using it. | |
| 308 cc::SurfaceManager* surface_manager = | |
| 309 GetEmbedderDeps()->GetSurfaceManager(); | |
| 310 auto content_layer = | |
| 311 cc::SurfaceLayer::Create(surface_manager->reference_factory()); | |
| 312 cc::SurfaceId surface_id(surface_factory_->frame_sink_id(), | |
| 313 local_frame_id_); | |
| 314 content_layer->SetSurfaceInfo( | |
| 315 cc::SurfaceInfo(surface_id, 1.f, surface_size)); | |
| 316 content_layer->SetBounds(current_surface_size_); | |
| 317 content_layer->SetIsDrawable(true); | |
| 318 content_layer->SetContentsOpaque(true); | |
| 319 | |
| 320 layer_->AddChild(content_layer); | |
| 321 } | |
| 322 | |
| 323 surface_factory_->SubmitCompositorFrame( | |
| 324 local_frame_id_, std::move(frame), | |
| 325 base::Bind(&BlimpCompositor::SubmitCompositorFrameAck, | |
| 326 weak_ptr_factory_.GetWeakPtr())); | |
| 327 | |
| 328 for (auto& copy_request : copy_requests_for_next_swap_) { | |
| 329 surface_factory_->RequestCopyOfSurface(std::move(copy_request)); | |
| 330 } | |
| 331 copy_requests_for_next_swap_.clear(); | |
| 332 } | |
| 333 | |
| 334 void BlimpCompositor::SubmitCompositorFrameAck() { | |
| 335 compositor_dependencies_->GetCompositorTaskRunner()->PostTask( | |
| 336 FROM_HERE, | |
| 337 base::Bind(&BlimpCompositorFrameSinkProxyClient::SubmitCompositorFrameAck, | |
| 338 proxy_client_)); | |
| 339 } | |
| 340 | |
| 341 void BlimpCompositor::MakeCopyRequestOnNextSwap( | |
| 342 std::unique_ptr<cc::CopyOutputRequest> copy_request) { | |
| 343 copy_requests_for_next_swap_.push_back(std::move(copy_request)); | |
| 344 } | |
| 345 | |
| 346 void BlimpCompositor::UnbindProxyClient() { | |
| 347 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 348 DCHECK(bound_to_proxy_); | |
| 349 | |
| 350 DestroyDelegatedContent(); | |
| 351 surface_factory_->Reset(); | |
| 352 bound_to_proxy_ = false; | |
| 353 proxy_client_ = nullptr; | |
| 354 } | |
| 355 | |
| 356 void BlimpCompositor::ReturnResources( | |
| 357 const cc::ReturnedResourceArray& resources) { | |
| 358 DCHECK(bound_to_proxy_); | |
| 359 compositor_dependencies_->GetCompositorTaskRunner()->PostTask( | |
| 360 FROM_HERE, | |
| 361 base::Bind( | |
| 362 &BlimpCompositorFrameSinkProxyClient::ReclaimCompositorResources, | |
| 363 proxy_client_, resources)); | |
| 364 } | |
| 365 | |
| 366 void BlimpCompositor::DidUpdateLocalState() { | |
| 367 client_state_dirty_ = true; | |
| 368 } | |
| 369 | |
| 370 void BlimpCompositor::FlushClientState() { | |
| 371 // If the client state has not been modified, we don't need to send an update. | |
| 372 if (!client_state_dirty_) | |
| 373 return; | |
| 374 | |
| 375 // If we had sent an update and an ack for it is still pending, we can't send | |
| 376 // another update till the ack is received. | |
| 377 if (client_state_update_ack_pending_) | |
| 378 return; | |
| 379 | |
| 380 cc::proto::CompositorMessage message; | |
| 381 message.set_frame_ack(false); | |
| 382 compositor_state_deserializer_->PullClientStateUpdate( | |
| 383 message.mutable_client_state_update()); | |
| 384 | |
| 385 client_state_dirty_ = false; | |
| 386 client_state_update_ack_pending_ = true; | |
| 387 client_->SendCompositorMessage(message); | |
| 388 } | |
| 389 | |
| 390 CompositorDependencies* BlimpCompositor::GetEmbedderDeps() { | |
| 391 return compositor_dependencies_->GetEmbedderDependencies(); | |
| 392 } | |
| 393 | |
| 394 void BlimpCompositor::DestroyDelegatedContent() { | |
| 395 if (!local_frame_id_.is_valid()) | |
| 396 return; | |
| 397 | |
| 398 // Remove any references for the surface layer that uses this | |
| 399 // |local_frame_id_|. | |
| 400 layer_->RemoveAllChildren(); | |
| 401 surface_factory_->EvictSurface(); | |
| 402 local_frame_id_ = cc::LocalFrameId(); | |
| 403 } | |
| 404 | |
| 405 std::unique_ptr<cc::LayerTreeHostInProcess> | |
| 406 BlimpCompositor::CreateLayerTreeHost() { | |
| 407 DCHECK(animation_host_); | |
| 408 std::unique_ptr<cc::LayerTreeHostInProcess> host; | |
| 409 | |
| 410 cc::LayerTreeHostInProcess::InitParams params; | |
| 411 params.client = this; | |
| 412 params.task_graph_runner = compositor_dependencies_->GetTaskGraphRunner(); | |
| 413 params.main_task_runner = base::ThreadTaskRunnerHandle::Get(); | |
| 414 params.image_serialization_processor = | |
| 415 compositor_dependencies_->GetImageSerializationProcessor(); | |
| 416 | |
| 417 cc::LayerTreeSettings* settings = | |
| 418 compositor_dependencies_->GetLayerTreeSettings(); | |
| 419 params.settings = settings; | |
| 420 params.mutator_host = animation_host_.get(); | |
| 421 | |
| 422 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner = | |
| 423 compositor_dependencies_->GetCompositorTaskRunner(); | |
| 424 | |
| 425 host = cc::LayerTreeHostInProcess::CreateThreaded(compositor_task_runner, | |
| 426 ¶ms); | |
| 427 | |
| 428 return host; | |
| 429 } | |
| 430 | |
| 431 void BlimpCompositor::DestroyLayerTreeHost() { | |
| 432 DCHECK(host_); | |
| 433 | |
| 434 // Tear down the output surface connection with the old LayerTreeHost | |
| 435 // instance. | |
| 436 DestroyDelegatedContent(); | |
| 437 | |
| 438 // Destroy the old LayerTreeHost state. | |
| 439 host_.reset(); | |
| 440 | |
| 441 // Cancel any outstanding CompositorFrameSink requests. That way if we get an | |
| 442 // async callback related to the old request we know to drop it. | |
| 443 compositor_frame_sink_request_pending_ = false; | |
| 444 } | |
| 445 | |
| 446 } // namespace client | |
| 447 } // namespace blimp | |
| OLD | NEW |