Index: cc/surfaces/display.cc |
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d35271272c2598ad4e9c02924e979a3a4a170d22 |
--- /dev/null |
+++ b/cc/surfaces/display.cc |
@@ -0,0 +1,219 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "cc/surfaces/display.h" |
+ |
+#include "base/message_loop/message_loop.h" |
+#include "base/trace_event/trace_event.h" |
+#include "cc/output/compositor_frame.h" |
+#include "cc/output/compositor_frame_ack.h" |
+#include "cc/output/direct_renderer.h" |
+#include "cc/output/gl_renderer.h" |
+#include "cc/output/renderer_settings.h" |
+#include "cc/output/software_renderer.h" |
+#include "cc/resources/texture_mailbox_deleter.h" |
+#include "cc/surfaces/display_client.h" |
+#include "cc/surfaces/surface.h" |
+#include "cc/surfaces/surface_aggregator.h" |
+#include "cc/surfaces/surface_manager.h" |
+ |
+namespace cc { |
+ |
+Display::Display(DisplayClient* client, |
+ SurfaceManager* manager, |
+ SharedBitmapManager* bitmap_manager, |
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, |
+ const RendererSettings& settings) |
+ : client_(client), |
+ manager_(manager), |
+ bitmap_manager_(bitmap_manager), |
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager), |
+ settings_(settings), |
+ device_scale_factor_(1.f), |
+ texture_mailbox_deleter_( |
+ new TextureMailboxDeleter(base::MessageLoopProxy::current())) { |
+ manager_->AddObserver(this); |
+} |
+ |
+Display::~Display() { |
+ manager_->RemoveObserver(this); |
+ if (aggregator_) { |
+ for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { |
+ Surface* surface = manager_->GetSurfaceForId(id_entry.first); |
+ if (surface) |
+ surface->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED); |
+ } |
+ } |
+} |
+ |
+bool Display::Initialize(scoped_ptr<OutputSurface> output_surface) { |
+ output_surface_ = output_surface.Pass(); |
+ return output_surface_->BindToClient(this); |
+} |
+ |
+void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) { |
+ current_surface_id_ = id; |
+ device_scale_factor_ = device_scale_factor; |
+ client_->DisplayDamaged(); |
+} |
+ |
+void Display::Resize(const gfx::Size& size) { |
+ if (size == current_surface_size_) |
+ return; |
+ // Need to ensure all pending swaps have executed before the window is |
+ // resized, or D3D11 will scale the swap output. |
+ if (renderer_ && settings_.finish_rendering_on_resize) |
+ renderer_->Finish(); |
+ current_surface_size_ = size; |
+ client_->DisplayDamaged(); |
+} |
+ |
+void Display::InitializeRenderer() { |
+ if (resource_provider_) |
+ return; |
+ |
+ scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create( |
+ output_surface_.get(), bitmap_manager_, gpu_memory_buffer_manager_, |
+ nullptr, settings_.highp_threshold_min, settings_.use_rgba_4444_textures, |
+ settings_.texture_id_allocation_chunk_size); |
+ if (!resource_provider) |
+ return; |
+ |
+ if (output_surface_->context_provider()) { |
+ scoped_ptr<GLRenderer> renderer = GLRenderer::Create( |
+ this, &settings_, output_surface_.get(), resource_provider.get(), |
+ texture_mailbox_deleter_.get(), settings_.highp_threshold_min); |
+ if (!renderer) |
+ return; |
+ renderer_ = renderer.Pass(); |
+ } else { |
+ scoped_ptr<SoftwareRenderer> renderer = SoftwareRenderer::Create( |
+ this, &settings_, output_surface_.get(), resource_provider.get()); |
+ if (!renderer) |
+ return; |
+ renderer_ = renderer.Pass(); |
+ } |
+ |
+ resource_provider_ = resource_provider.Pass(); |
+ aggregator_.reset(new SurfaceAggregator(manager_, resource_provider_.get())); |
+} |
+ |
+void Display::DidLoseOutputSurface() { |
+ client_->OutputSurfaceLost(); |
+} |
+ |
+bool Display::Draw() { |
+ if (current_surface_id_.is_null()) |
+ return false; |
+ |
+ InitializeRenderer(); |
+ if (!output_surface_) |
+ return false; |
+ |
+ // TODO(skyostil): We should hold a BlockingTaskRunner::CapturePostTasks |
+ // while Aggregate is called to immediately run release callbacks afterward. |
+ scoped_ptr<CompositorFrame> frame = |
+ aggregator_->Aggregate(current_surface_id_); |
+ if (!frame) |
+ return false; |
+ |
+ TRACE_EVENT0("cc", "Display::Draw"); |
+ |
+ // Run callbacks early to allow pipelining. |
+ for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { |
+ Surface* surface = manager_->GetSurfaceForId(id_entry.first); |
+ if (surface) |
+ surface->RunDrawCallbacks(SurfaceDrawStatus::DRAWN); |
+ } |
+ DelegatedFrameData* frame_data = frame->delegated_frame_data.get(); |
+ |
+ frame->metadata.latency_info.insert(frame->metadata.latency_info.end(), |
+ stored_latency_info_.begin(), |
+ stored_latency_info_.end()); |
+ stored_latency_info_.clear(); |
+ bool have_copy_requests = false; |
+ for (const auto* pass : frame_data->render_pass_list) { |
+ have_copy_requests |= !pass->copy_requests.empty(); |
+ } |
+ |
+ gfx::Size surface_size; |
+ bool have_damage = false; |
+ if (!frame_data->render_pass_list.empty()) { |
+ surface_size = frame_data->render_pass_list.back()->output_rect.size(); |
+ have_damage = |
+ !frame_data->render_pass_list.back()->damage_rect.size().IsEmpty(); |
+ } |
+ bool avoid_swap = surface_size != current_surface_size_; |
+ bool should_draw = !frame->metadata.latency_info.empty() || |
+ have_copy_requests || (have_damage && !avoid_swap); |
+ |
+ if (should_draw) { |
+ gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_); |
+ gfx::Rect device_clip_rect = device_viewport_rect; |
+ bool disable_picture_quad_image_filtering = false; |
+ |
+ renderer_->DecideRenderPassAllocationsForFrame( |
+ frame_data->render_pass_list); |
+ renderer_->DrawFrame(&frame_data->render_pass_list, device_scale_factor_, |
+ device_viewport_rect, device_clip_rect, |
+ disable_picture_quad_image_filtering); |
+ } |
+ |
+ if (should_draw && !avoid_swap) { |
+ renderer_->SwapBuffers(frame->metadata); |
+ } else { |
+ stored_latency_info_.insert(stored_latency_info_.end(), |
+ frame->metadata.latency_info.begin(), |
+ frame->metadata.latency_info.end()); |
+ DidSwapBuffers(); |
+ DidSwapBuffersComplete(); |
+ } |
+ |
+ return true; |
+} |
+ |
+void Display::DidSwapBuffers() { |
+ client_->DidSwapBuffers(); |
+} |
+ |
+void Display::DidSwapBuffersComplete() { |
+ client_->DidSwapBuffersComplete(); |
+} |
+ |
+void Display::CommitVSyncParameters(base::TimeTicks timebase, |
+ base::TimeDelta interval) { |
+ client_->CommitVSyncParameters(timebase, interval); |
+} |
+ |
+void Display::OnSurfaceDamaged(SurfaceId surface_id, bool* changed) { |
+ if (aggregator_ && |
+ aggregator_->previous_contained_surfaces().count(surface_id)) { |
+ Surface* surface = manager_->GetSurfaceForId(surface_id); |
+ if (surface) { |
+ const CompositorFrame* current_frame = surface->GetEligibleFrame(); |
+ if (!current_frame || !current_frame->delegated_frame_data || |
+ !current_frame->delegated_frame_data->resource_list.size()) |
+ aggregator_->ReleaseResources(surface_id); |
+ } |
+ client_->DisplayDamaged(); |
+ *changed = true; |
+ } else if (surface_id == current_surface_id_) { |
+ client_->DisplayDamaged(); |
+ *changed = true; |
+ } |
+} |
+ |
+SurfaceId Display::CurrentSurfaceId() { |
+ return current_surface_id_; |
+} |
+ |
+int Display::GetMaxFramesPending() { |
+ int max_frames_pending = |
+ output_surface_ ? output_surface_->capabilities().max_frames_pending : 0; |
+ if (max_frames_pending <= 0) |
+ max_frames_pending = OutputSurface::DEFAULT_MAX_FRAMES_PENDING; |
+ return max_frames_pending; |
+} |
+ |
+} // namespace cc |