1 // Copyright 2014 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.
5 #include "cc/surfaces/display.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "base/trace_event/trace_event.h"
9 #include "cc/debug/benchmark_instrumentation.h"
10 #include "cc/output/compositor_frame.h"
11 #include "cc/output/compositor_frame_ack.h"
12 #include "cc/output/direct_renderer.h"
13 #include "cc/output/gl_renderer.h"
14 #include "cc/output/renderer_settings.h"
15 #include "cc/output/software_renderer.h"
16 #include "cc/output/texture_mailbox_deleter.h"
17 #include "cc/surfaces/display_client.h"
18 #include "cc/surfaces/display_scheduler.h"
19 #include "cc/surfaces/surface.h"
20 #include "cc/surfaces/surface_aggregator.h"
21 #include "cc/surfaces/surface_manager.h"
22 #include "gpu/command_buffer/client/gles2_interface.h"
23 #include "ui/gfx/buffer_types.h"
27 Display::Display(DisplayClient
* client
,
28 SurfaceManager
* manager
,
29 SharedBitmapManager
* bitmap_manager
,
30 gpu::GpuMemoryBufferManager
* gpu_memory_buffer_manager
,
31 const RendererSettings
& settings
)
34 bitmap_manager_(bitmap_manager
),
35 gpu_memory_buffer_manager_(gpu_memory_buffer_manager
),
37 device_scale_factor_(1.f
),
38 swapped_since_resize_(false),
40 texture_mailbox_deleter_(new TextureMailboxDeleter(nullptr)) {
41 manager_
->AddObserver(this);
45 manager_
->RemoveObserver(this);
47 for (const auto& id_entry
: aggregator_
->previous_contained_surfaces()) {
48 Surface
* surface
= manager_
->GetSurfaceForId(id_entry
.first
);
50 surface
->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED
);
55 bool Display::Initialize(scoped_ptr
<OutputSurface
> output_surface
,
56 DisplayScheduler
* scheduler
) {
57 output_surface_
= output_surface
.Pass();
58 scheduler_
= scheduler
;
59 return output_surface_
->BindToClient(this);
62 void Display::SetSurfaceId(SurfaceId id
, float device_scale_factor
) {
63 if (current_surface_id_
== id
&& device_scale_factor_
== device_scale_factor
)
66 TRACE_EVENT0("cc", "Display::SetSurfaceId");
68 current_surface_id_
= id
;
69 device_scale_factor_
= device_scale_factor
;
71 UpdateRootSurfaceResourcesLocked();
73 scheduler_
->SetNewRootSurface(id
);
76 void Display::Resize(const gfx::Size
& size
) {
77 if (size
== current_surface_size_
)
80 TRACE_EVENT0("cc", "Display::Resize");
82 // Need to ensure all pending swaps have executed before the window is
83 // resized, or D3D11 will scale the swap output.
84 if (settings_
.finish_rendering_on_resize
) {
85 if (!swapped_since_resize_
&& scheduler_
)
86 scheduler_
->ForceImmediateSwapIfPossible();
87 if (swapped_since_resize_
&& output_surface_
&&
88 output_surface_
->context_provider())
89 output_surface_
->context_provider()->ContextGL()->ShallowFinishCHROMIUM();
91 swapped_since_resize_
= false;
92 current_surface_size_
= size
;
94 scheduler_
->DisplayResized();
97 void Display::SetExternalClip(const gfx::Rect
& clip
) {
98 external_clip_
= clip
;
101 void Display::InitializeRenderer() {
102 if (resource_provider_
)
105 scoped_ptr
<ResourceProvider
> resource_provider
= ResourceProvider::Create(
106 output_surface_
.get(), bitmap_manager_
, gpu_memory_buffer_manager_
,
107 nullptr, settings_
.highp_threshold_min
, settings_
.use_rgba_4444_textures
,
108 settings_
.texture_id_allocation_chunk_size
,
109 std::vector
<unsigned>(static_cast<size_t>(gfx::BufferFormat::LAST
) + 1,
111 if (!resource_provider
)
114 if (output_surface_
->context_provider()) {
115 scoped_ptr
<GLRenderer
> renderer
= GLRenderer::Create(
116 this, &settings_
, output_surface_
.get(), resource_provider
.get(),
117 texture_mailbox_deleter_
.get(), settings_
.highp_threshold_min
);
120 renderer_
= renderer
.Pass();
122 scoped_ptr
<SoftwareRenderer
> renderer
= SoftwareRenderer::Create(
123 this, &settings_
, output_surface_
.get(), resource_provider
.get());
126 renderer_
= renderer
.Pass();
129 resource_provider_
= resource_provider
.Pass();
130 // TODO(jbauman): Outputting an incomplete quad list doesn't work when using
132 bool output_partial_list
= renderer_
->Capabilities().using_partial_swap
&&
133 !output_surface_
->GetOverlayCandidateValidator();
134 aggregator_
.reset(new SurfaceAggregator(manager_
, resource_provider_
.get(),
135 output_partial_list
));
138 void Display::DidLoseOutputSurface() {
140 scheduler_
->OutputSurfaceLost();
141 // WARNING: The client may delete the Display in this method call. Do not
142 // make any additional references to members after this call.
143 client_
->OutputSurfaceLost();
146 void Display::UpdateRootSurfaceResourcesLocked() {
147 Surface
* surface
= manager_
->GetSurfaceForId(current_surface_id_
);
148 bool root_surface_resources_locked
= !surface
|| !surface
->GetEligibleFrame();
150 scheduler_
->SetRootSurfaceResourcesLocked(root_surface_resources_locked
);
153 bool Display::DrawAndSwap() {
154 TRACE_EVENT0("cc", "Display::DrawAndSwap");
156 if (current_surface_id_
.is_null()) {
157 TRACE_EVENT_INSTANT0("cc", "No root surface.", TRACE_EVENT_SCOPE_THREAD
);
161 InitializeRenderer();
162 if (!output_surface_
) {
163 TRACE_EVENT_INSTANT0("cc", "No output surface", TRACE_EVENT_SCOPE_THREAD
);
167 scoped_ptr
<CompositorFrame
> frame
=
168 aggregator_
->Aggregate(current_surface_id_
);
170 TRACE_EVENT_INSTANT0("cc", "Empty aggregated frame.",
171 TRACE_EVENT_SCOPE_THREAD
);
175 // Run callbacks early to allow pipelining.
176 for (const auto& id_entry
: aggregator_
->previous_contained_surfaces()) {
177 Surface
* surface
= manager_
->GetSurfaceForId(id_entry
.first
);
179 surface
->RunDrawCallbacks(SurfaceDrawStatus::DRAWN
);
182 DelegatedFrameData
* frame_data
= frame
->delegated_frame_data
.get();
184 frame
->metadata
.latency_info
.insert(frame
->metadata
.latency_info
.end(),
185 stored_latency_info_
.begin(),
186 stored_latency_info_
.end());
187 stored_latency_info_
.clear();
188 bool have_copy_requests
= false;
189 for (const auto* pass
: frame_data
->render_pass_list
) {
190 have_copy_requests
|= !pass
->copy_requests
.empty();
193 gfx::Size surface_size
;
194 bool have_damage
= false;
195 if (!frame_data
->render_pass_list
.empty()) {
196 surface_size
= frame_data
->render_pass_list
.back()->output_rect
.size();
198 !frame_data
->render_pass_list
.back()->damage_rect
.size().IsEmpty();
201 bool size_matches
= surface_size
== current_surface_size_
;
203 TRACE_EVENT_INSTANT0("cc", "Size missmatch.", TRACE_EVENT_SCOPE_THREAD
);
205 bool should_draw
= !frame
->metadata
.latency_info
.empty() ||
206 have_copy_requests
|| (have_damage
&& size_matches
);
208 // If the surface is suspended then the resources to be used by the draw are
210 if (output_surface_
->SurfaceIsSuspendForRecycle()) {
211 TRACE_EVENT_INSTANT0("cc", "Surface is suspended for recycle.",
212 TRACE_EVENT_SCOPE_THREAD
);
217 gfx::Rect device_viewport_rect
= gfx::Rect(current_surface_size_
);
218 gfx::Rect device_clip_rect
=
219 external_clip_
.IsEmpty() ? device_viewport_rect
: external_clip_
;
220 bool disable_picture_quad_image_filtering
= false;
222 renderer_
->DecideRenderPassAllocationsForFrame(
223 frame_data
->render_pass_list
);
224 renderer_
->DrawFrame(&frame_data
->render_pass_list
, device_scale_factor_
,
225 device_viewport_rect
, device_clip_rect
,
226 disable_picture_quad_image_filtering
);
228 TRACE_EVENT_INSTANT0("cc", "Draw skipped.", TRACE_EVENT_SCOPE_THREAD
);
231 bool should_swap
= should_draw
&& size_matches
;
233 swapped_since_resize_
= true;
234 for (auto& latency
: frame
->metadata
.latency_info
) {
235 TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow",
236 TRACE_ID_DONT_MANGLE(latency
.trace_id()),
237 TRACE_EVENT_FLAG_FLOW_IN
| TRACE_EVENT_FLAG_FLOW_OUT
,
238 "step", "Display::DrawAndSwap");
240 benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
241 renderer_
->SwapBuffers(frame
->metadata
);
243 if (have_damage
&& !size_matches
)
244 aggregator_
->SetFullDamageForSurface(current_surface_id_
);
245 TRACE_EVENT_INSTANT0("cc", "Swap skipped.", TRACE_EVENT_SCOPE_THREAD
);
246 stored_latency_info_
.insert(stored_latency_info_
.end(),
247 frame
->metadata
.latency_info
.begin(),
248 frame
->metadata
.latency_info
.end());
250 DidSwapBuffersComplete();
256 void Display::DidSwapBuffers() {
258 scheduler_
->DidSwapBuffers();
261 void Display::DidSwapBuffersComplete() {
263 scheduler_
->DidSwapBuffersComplete();
266 void Display::CommitVSyncParameters(base::TimeTicks timebase
,
267 base::TimeDelta interval
) {
268 client_
->CommitVSyncParameters(timebase
, interval
);
271 void Display::SetMemoryPolicy(const ManagedMemoryPolicy
& policy
) {
272 client_
->SetMemoryPolicy(policy
);
275 void Display::OnDraw() {
279 void Display::SetNeedsRedrawRect(const gfx::Rect
& damage_rect
) {
283 void Display::ReclaimResources(const CompositorFrameAck
* ack
) {
287 void Display::SetExternalDrawConstraints(
288 const gfx::Transform
& transform
,
289 const gfx::Rect
& viewport
,
290 const gfx::Rect
& clip
,
291 const gfx::Rect
& viewport_rect_for_tile_priority
,
292 const gfx::Transform
& transform_for_tile_priority
,
293 bool resourceless_software_draw
) {
297 void Display::SetTreeActivationCallback(const base::Closure
& callback
) {
301 void Display::SetFullRootLayerDamage() {
302 if (aggregator_
&& !current_surface_id_
.is_null())
303 aggregator_
->SetFullDamageForSurface(current_surface_id_
);
306 void Display::OnSurfaceDamaged(SurfaceId surface_id
, bool* changed
) {
308 aggregator_
->previous_contained_surfaces().count(surface_id
)) {
309 Surface
* surface
= manager_
->GetSurfaceForId(surface_id
);
311 const CompositorFrame
* current_frame
= surface
->GetEligibleFrame();
312 if (!current_frame
|| !current_frame
->delegated_frame_data
||
313 !current_frame
->delegated_frame_data
->resource_list
.size()) {
314 aggregator_
->ReleaseResources(surface_id
);
318 scheduler_
->SurfaceDamaged(surface_id
);
320 } else if (surface_id
== current_surface_id_
) {
322 scheduler_
->SurfaceDamaged(surface_id
);
326 if (surface_id
== current_surface_id_
)
327 UpdateRootSurfaceResourcesLocked();
330 SurfaceId
Display::CurrentSurfaceId() {
331 return current_surface_id_
;