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 "content/browser/compositor/reflector_impl.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "content/browser/compositor/browser_compositor_output_surface.h"
10#include "content/browser/compositor/owned_mailbox.h"
11#include "content/common/gpu/client/gl_helper.h"
12#include "ui/compositor/layer.h"
13
14namespace content {
15
16ReflectorImpl::ReflectorImpl(
17    ui::Compositor* mirrored_compositor,
18    ui::Layer* mirroring_layer,
19    IDMap<BrowserCompositorOutputSurface>* output_surface_map,
20    base::MessageLoopProxy* compositor_thread_loop,
21    int surface_id)
22    : impl_unsafe_(output_surface_map),
23      main_unsafe_(mirrored_compositor, mirroring_layer),
24      impl_message_loop_(compositor_thread_loop),
25      main_message_loop_(base::MessageLoopProxy::current()),
26      surface_id_(surface_id) {
27  GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper();
28  MainThreadData& main = GetMain();
29  main.mailbox = new OwnedMailbox(helper);
30  impl_message_loop_->PostTask(
31      FROM_HERE,
32      base::Bind(
33          &ReflectorImpl::InitOnImplThread, this, main.mailbox->holder()));
34}
35
36ReflectorImpl::MainThreadData::MainThreadData(
37    ui::Compositor* mirrored_compositor,
38    ui::Layer* mirroring_layer)
39    : needs_set_mailbox(true),
40      mirrored_compositor(mirrored_compositor),
41      mirroring_layer(mirroring_layer) {}
42
43ReflectorImpl::MainThreadData::~MainThreadData() {}
44
45ReflectorImpl::ImplThreadData::ImplThreadData(
46    IDMap<BrowserCompositorOutputSurface>* output_surface_map)
47    : output_surface_map(output_surface_map),
48      output_surface(NULL),
49      texture_id(0) {}
50
51ReflectorImpl::ImplThreadData::~ImplThreadData() {}
52
53ReflectorImpl::ImplThreadData& ReflectorImpl::GetImpl() {
54  DCHECK(impl_message_loop_->BelongsToCurrentThread());
55  return impl_unsafe_;
56}
57
58ReflectorImpl::MainThreadData& ReflectorImpl::GetMain() {
59  DCHECK(main_message_loop_->BelongsToCurrentThread());
60  return main_unsafe_;
61}
62
63void ReflectorImpl::InitOnImplThread(const gpu::MailboxHolder& mailbox_holder) {
64  ImplThreadData& impl = GetImpl();
65  // Ignore if the reflector was shutdown before
66  // initialized, or it's already initialized.
67  if (!impl.output_surface_map || impl.gl_helper.get())
68    return;
69
70  impl.mailbox_holder = mailbox_holder;
71
72  BrowserCompositorOutputSurface* source_surface =
73      impl.output_surface_map->Lookup(surface_id_);
74  // Skip if the source surface isn't ready yet. This will be
75  // initialized when the source surface becomes ready.
76  if (!source_surface)
77    return;
78
79  AttachToOutputSurfaceOnImplThread(impl.mailbox_holder, source_surface);
80}
81
82void ReflectorImpl::OnSourceSurfaceReady(
83    BrowserCompositorOutputSurface* source_surface) {
84  ImplThreadData& impl = GetImpl();
85  AttachToOutputSurfaceOnImplThread(impl.mailbox_holder, source_surface);
86}
87
88void ReflectorImpl::Shutdown() {
89  MainThreadData& main = GetMain();
90  main.mailbox = NULL;
91  main.mirroring_layer->SetShowPaintedContent();
92  main.mirroring_layer = NULL;
93  impl_message_loop_->PostTask(
94      FROM_HERE, base::Bind(&ReflectorImpl::ShutdownOnImplThread, this));
95}
96
97void ReflectorImpl::DetachFromOutputSurface() {
98  ImplThreadData& impl = GetImpl();
99  DCHECK(impl.output_surface);
100  impl.output_surface->SetReflector(NULL);
101  DCHECK(impl.texture_id);
102  impl.gl_helper->DeleteTexture(impl.texture_id);
103  impl.texture_id = 0;
104  impl.gl_helper.reset();
105  impl.output_surface = NULL;
106}
107
108void ReflectorImpl::ShutdownOnImplThread() {
109  ImplThreadData& impl = GetImpl();
110  if (impl.output_surface)
111    DetachFromOutputSurface();
112  impl.output_surface_map = NULL;
113  // The instance must be deleted on main thread.
114  main_message_loop_->PostTask(FROM_HERE,
115                               base::Bind(&ReflectorImpl::DeleteOnMainThread,
116                                          scoped_refptr<ReflectorImpl>(this)));
117}
118
119void ReflectorImpl::ReattachToOutputSurfaceFromMainThread(
120    BrowserCompositorOutputSurface* output_surface) {
121  MainThreadData& main = GetMain();
122  GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper();
123  main.mailbox = new OwnedMailbox(helper);
124  main.needs_set_mailbox = true;
125  main.mirroring_layer->SetShowPaintedContent();
126  impl_message_loop_->PostTask(
127      FROM_HERE,
128      base::Bind(&ReflectorImpl::AttachToOutputSurfaceOnImplThread,
129                 this,
130                 main.mailbox->holder(),
131                 output_surface));
132}
133
134void ReflectorImpl::OnMirroringCompositorResized() {
135  MainThreadData& main = GetMain();
136  main.mirroring_layer->SchedulePaint(main.mirroring_layer->bounds());
137}
138
139void ReflectorImpl::OnSwapBuffers() {
140  ImplThreadData& impl = GetImpl();
141  gfx::Size size = impl.output_surface->SurfaceSize();
142  if (impl.texture_id) {
143    impl.gl_helper->CopyTextureFullImage(impl.texture_id, size);
144    impl.gl_helper->Flush();
145  }
146  main_message_loop_->PostTask(
147      FROM_HERE,
148      base::Bind(
149          &ReflectorImpl::FullRedrawOnMainThread, this->AsWeakPtr(), size));
150}
151
152void ReflectorImpl::OnPostSubBuffer(gfx::Rect rect) {
153  ImplThreadData& impl = GetImpl();
154  if (impl.texture_id) {
155    impl.gl_helper->CopyTextureSubImage(impl.texture_id, rect);
156    impl.gl_helper->Flush();
157  }
158  main_message_loop_->PostTask(
159      FROM_HERE,
160      base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread,
161                 this->AsWeakPtr(),
162                 impl.output_surface->SurfaceSize(),
163                 rect));
164}
165
166ReflectorImpl::~ReflectorImpl() {
167  // Make sure the reflector is deleted on main thread.
168  DCHECK_EQ(main_message_loop_.get(), base::MessageLoopProxy::current().get());
169}
170
171static void ReleaseMailbox(scoped_refptr<OwnedMailbox> mailbox,
172                           unsigned int sync_point,
173                           bool is_lost) {
174  mailbox->UpdateSyncPoint(sync_point);
175}
176
177void ReflectorImpl::AttachToOutputSurfaceOnImplThread(
178    const gpu::MailboxHolder& mailbox_holder,
179    BrowserCompositorOutputSurface* output_surface) {
180  ImplThreadData& impl = GetImpl();
181  if (output_surface == impl.output_surface)
182    return;
183  if (impl.output_surface)
184    DetachFromOutputSurface();
185  impl.output_surface = output_surface;
186  output_surface->context_provider()->BindToCurrentThread();
187  impl.gl_helper.reset(
188      new GLHelper(output_surface->context_provider()->ContextGL(),
189                   output_surface->context_provider()->ContextSupport()));
190  impl.texture_id = impl.gl_helper->ConsumeMailboxToTexture(
191      mailbox_holder.mailbox, mailbox_holder.sync_point);
192  impl.gl_helper->ResizeTexture(impl.texture_id, output_surface->SurfaceSize());
193  impl.gl_helper->Flush();
194  output_surface->SetReflector(this);
195  // The texture doesn't have the data, so invokes full redraw now.
196  main_message_loop_->PostTask(
197      FROM_HERE,
198      base::Bind(&ReflectorImpl::FullRedrawContentOnMainThread,
199                 scoped_refptr<ReflectorImpl>(this)));
200}
201
202void ReflectorImpl::UpdateTextureSizeOnMainThread(gfx::Size size) {
203  MainThreadData& main = GetMain();
204  if (!main.mirroring_layer || !main.mailbox.get() ||
205      main.mailbox->mailbox().IsZero())
206    return;
207  if (main.needs_set_mailbox) {
208    main.mirroring_layer->SetTextureMailbox(
209        cc::TextureMailbox(main.mailbox->holder()),
210        cc::SingleReleaseCallback::Create(
211            base::Bind(ReleaseMailbox, main.mailbox)),
212        size);
213    main.needs_set_mailbox = false;
214  } else {
215    main.mirroring_layer->SetTextureSize(size);
216  }
217  main.mirroring_layer->SetBounds(gfx::Rect(size));
218}
219
220void ReflectorImpl::FullRedrawOnMainThread(gfx::Size size) {
221  MainThreadData& main = GetMain();
222  if (!main.mirroring_layer)
223    return;
224  UpdateTextureSizeOnMainThread(size);
225  main.mirroring_layer->SchedulePaint(main.mirroring_layer->bounds());
226}
227
228void ReflectorImpl::UpdateSubBufferOnMainThread(gfx::Size size,
229                                                gfx::Rect rect) {
230  MainThreadData& main = GetMain();
231  if (!main.mirroring_layer)
232    return;
233  UpdateTextureSizeOnMainThread(size);
234  // Flip the coordinates to compositor's one.
235  int y = size.height() - rect.y() - rect.height();
236  gfx::Rect new_rect(rect.x(), y, rect.width(), rect.height());
237  main.mirroring_layer->SchedulePaint(new_rect);
238}
239
240void ReflectorImpl::FullRedrawContentOnMainThread() {
241  MainThreadData& main = GetMain();
242  main.mirrored_compositor->ScheduleFullRedraw();
243}
244
245}  // namespace content
246