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.
4
5#include "cc/surfaces/display.h"
6
7#include "base/debug/trace_event.h"
8#include "base/message_loop/message_loop.h"
9#include "cc/output/compositor_frame.h"
10#include "cc/output/compositor_frame_ack.h"
11#include "cc/output/direct_renderer.h"
12#include "cc/output/gl_renderer.h"
13#include "cc/output/software_renderer.h"
14#include "cc/surfaces/display_client.h"
15#include "cc/surfaces/surface.h"
16#include "cc/surfaces/surface_aggregator.h"
17#include "cc/surfaces/surface_manager.h"
18#include "cc/trees/blocking_task_runner.h"
19
20namespace cc {
21
22Display::Display(DisplayClient* client,
23                 SurfaceManager* manager,
24                 SharedBitmapManager* bitmap_manager)
25    : client_(client),
26      manager_(manager),
27      bitmap_manager_(bitmap_manager),
28      blocking_main_thread_task_runner_(
29          BlockingTaskRunner::Create(base::MessageLoopProxy::current())) {
30  manager_->AddObserver(this);
31}
32
33Display::~Display() {
34  manager_->RemoveObserver(this);
35}
36
37void Display::Resize(SurfaceId id, const gfx::Size& size) {
38  current_surface_id_ = id;
39  current_surface_size_ = size;
40  client_->DisplayDamaged();
41}
42
43void Display::InitializeOutputSurface() {
44  if (output_surface_)
45    return;
46  scoped_ptr<OutputSurface> output_surface = client_->CreateOutputSurface();
47  if (!output_surface->BindToClient(this))
48    return;
49
50  int highp_threshold_min = 0;
51  bool use_rgba_4444_texture_format = false;
52  size_t id_allocation_chunk_size = 1;
53  bool use_distance_field_text = false;
54  scoped_ptr<ResourceProvider> resource_provider =
55      ResourceProvider::Create(output_surface.get(),
56                               bitmap_manager_,
57                               blocking_main_thread_task_runner_.get(),
58                               highp_threshold_min,
59                               use_rgba_4444_texture_format,
60                               id_allocation_chunk_size,
61                               use_distance_field_text);
62  if (!resource_provider)
63    return;
64
65  if (output_surface->context_provider()) {
66    TextureMailboxDeleter* texture_mailbox_deleter = NULL;
67    scoped_ptr<GLRenderer> renderer =
68        GLRenderer::Create(this,
69                           &settings_,
70                           output_surface.get(),
71                           resource_provider.get(),
72                           texture_mailbox_deleter,
73                           highp_threshold_min);
74    if (!renderer)
75      return;
76    renderer_ = renderer.Pass();
77  } else {
78    scoped_ptr<SoftwareRenderer> renderer = SoftwareRenderer::Create(
79        this, &settings_, output_surface.get(), resource_provider.get());
80    if (!renderer)
81      return;
82    renderer_ = renderer.Pass();
83  }
84
85  output_surface_ = output_surface.Pass();
86  resource_provider_ = resource_provider.Pass();
87  aggregator_.reset(new SurfaceAggregator(manager_, resource_provider_.get()));
88}
89
90bool Display::Draw() {
91  if (current_surface_id_.is_null())
92    return false;
93
94  InitializeOutputSurface();
95  if (!output_surface_)
96    return false;
97
98  // TODO(skyostil): We should hold a BlockingTaskRunner::CapturePostTasks
99  // while Aggregate is called to immediately run release callbacks afterward.
100  scoped_ptr<CompositorFrame> frame =
101      aggregator_->Aggregate(current_surface_id_);
102  if (!frame)
103    return false;
104
105  TRACE_EVENT0("cc", "Display::Draw");
106  DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
107
108  // Only reshape when we know we are going to draw. Otherwise, the reshape
109  // can leave the window at the wrong size if we never draw and the proper
110  // viewport size is never set.
111  output_surface_->Reshape(current_surface_size_, 1.f);
112  float device_scale_factor = 1.0f;
113  gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
114  gfx::Rect device_clip_rect = device_viewport_rect;
115  bool disable_picture_quad_image_filtering = false;
116
117  renderer_->DecideRenderPassAllocationsForFrame(frame_data->render_pass_list);
118  renderer_->DrawFrame(&frame_data->render_pass_list,
119                       device_scale_factor,
120                       device_viewport_rect,
121                       device_clip_rect,
122                       disable_picture_quad_image_filtering);
123  renderer_->SwapBuffers(frame->metadata);
124  for (SurfaceAggregator::SurfaceIndexMap::iterator it =
125           aggregator_->previous_contained_surfaces().begin();
126       it != aggregator_->previous_contained_surfaces().end();
127       ++it) {
128    Surface* surface = manager_->GetSurfaceForId(it->first);
129    if (surface)
130      surface->RunDrawCallbacks();
131  }
132  return true;
133}
134
135void Display::DidSwapBuffers() {
136  client_->DidSwapBuffers();
137}
138
139void Display::DidSwapBuffersComplete() {
140  client_->DidSwapBuffersComplete();
141}
142
143void Display::CommitVSyncParameters(base::TimeTicks timebase,
144                                    base::TimeDelta interval) {
145  client_->CommitVSyncParameters(timebase, interval);
146}
147
148void Display::OnSurfaceDamaged(SurfaceId surface) {
149  if (aggregator_ && aggregator_->previous_contained_surfaces().count(surface))
150    client_->DisplayDamaged();
151}
152
153SurfaceId Display::CurrentSurfaceId() {
154  return current_surface_id_;
155}
156
157int Display::GetMaxFramesPending() {
158  if (!output_surface_)
159    return OutputSurface::DEFAULT_MAX_FRAMES_PENDING;
160  return output_surface_->capabilities().max_frames_pending;
161}
162
163}  // namespace cc
164