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 "content/browser/compositor/reflector_impl.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"
16 ReflectorImpl::ReflectorImpl(ui::Compositor
* mirrored_compositor
,
17 ui::Layer
* mirroring_layer
)
18 : mirrored_compositor_(mirrored_compositor
),
19 mirroring_layer_(mirroring_layer
),
20 mirrored_compositor_gl_helper_texture_id_(0),
21 needs_set_mailbox_(false),
23 output_surface_(nullptr) {
26 ReflectorImpl::~ReflectorImpl() {
29 void ReflectorImpl::Shutdown() {
31 DetachFromOutputSurface();
32 // Prevent the ReflectorImpl from picking up a new output surface.
33 mirroring_layer_
= nullptr;
36 void ReflectorImpl::DetachFromOutputSurface() {
37 DCHECK(output_surface_
);
38 output_surface_
->SetReflector(nullptr);
39 DCHECK(mailbox_
.get());
41 output_surface_
= nullptr;
42 mirrored_compositor_gl_helper_
->DeleteTexture(
43 mirrored_compositor_gl_helper_texture_id_
);
44 mirrored_compositor_gl_helper_texture_id_
= 0;
45 mirrored_compositor_gl_helper_
= nullptr;
46 mirroring_layer_
->SetShowSolidColorContent();
49 void ReflectorImpl::OnSourceSurfaceReady(
50 BrowserCompositorOutputSurface
* output_surface
) {
51 if (!mirroring_layer_
)
52 return; // Was already Shutdown().
53 if (output_surface
== output_surface_
)
54 return; // Is already attached.
56 DetachFromOutputSurface();
58 // Use the GLHelper from the ImageTransportFactory for our OwnedMailbox so we
59 // don't have to manage the lifetime of the GLHelper relative to the lifetime
61 GLHelper
* shared_helper
= ImageTransportFactory::GetInstance()->GetGLHelper();
62 mailbox_
= new OwnedMailbox(shared_helper
);
63 needs_set_mailbox_
= true;
65 // Create a GLHelper attached to the mirrored compositor's output surface for
66 // copying the output of the mirrored compositor.
67 mirrored_compositor_gl_helper_
.reset(
68 new GLHelper(output_surface
->context_provider()->ContextGL(),
69 output_surface
->context_provider()->ContextSupport()));
70 // Create a texture id in the name space of the new GLHelper to update the
71 // mailbox being held by the |mirroring_layer_|.
72 mirrored_compositor_gl_helper_texture_id_
=
73 mirrored_compositor_gl_helper_
->ConsumeMailboxToTexture(
74 mailbox_
->mailbox(), mailbox_
->sync_point());
76 flip_texture_
= !output_surface
->capabilities().flipped_output_surface
;
78 // The texture doesn't have the data. Request full redraw on mirrored
79 // compositor so that the full content will be copied to mirroring compositor.
80 // This full redraw should land us in OnSourceSwapBuffers() to resize the
81 // texture appropriately.
82 mirrored_compositor_
->ScheduleFullRedraw();
84 output_surface_
= output_surface
;
85 output_surface_
->SetReflector(this);
88 void ReflectorImpl::OnMirroringCompositorResized() {
89 mirroring_layer_
->SchedulePaint(mirroring_layer_
->bounds());
92 void ReflectorImpl::OnSourceSwapBuffers() {
93 if (!mirroring_layer_
)
95 // Should be attached to the source output surface already.
96 DCHECK(mailbox_
.get());
98 gfx::Size size
= output_surface_
->SurfaceSize();
99 mirrored_compositor_gl_helper_
->CopyTextureFullImage(
100 mirrored_compositor_gl_helper_texture_id_
, size
);
101 // Insert a barrier to make the copy show up in the mirroring compositor's
102 // mailbox. Since the the compositor contexts and the ImageTransportFactory's
103 // GLHelper are all on the same GPU channel, this is sufficient instead of
104 // plumbing through a sync point.
105 mirrored_compositor_gl_helper_
->InsertOrderingBarrier();
107 // Request full redraw on mirroring compositor.
108 UpdateTexture(size
, mirroring_layer_
->bounds());
111 void ReflectorImpl::OnSourcePostSubBuffer(const gfx::Rect
& rect
) {
112 if (!mirroring_layer_
)
114 // Should be attached to the source output surface already.
115 DCHECK(mailbox_
.get());
117 gfx::Size size
= output_surface_
->SurfaceSize();
118 mirrored_compositor_gl_helper_
->CopyTextureSubImage(
119 mirrored_compositor_gl_helper_texture_id_
, rect
);
120 // Insert a barrier to make the copy show up in the mirroring compositor's
121 // mailbox. Since the the compositor contexts and the ImageTransportFactory's
122 // GLHelper are all on the same GPU channel, this is sufficient instead of
123 // plumbing through a sync point.
124 mirrored_compositor_gl_helper_
->InsertOrderingBarrier();
127 // Flip the coordinates to compositor's one.
129 y
= size
.height() - rect
.y() - rect
.height();
130 gfx::Rect
mirroring_rect(rect
.x(), y
, rect
.width(), rect
.height());
132 // Request redraw of the dirty portion in mirroring compositor.
133 UpdateTexture(size
, mirroring_rect
);
136 static void ReleaseMailbox(scoped_refptr
<OwnedMailbox
> mailbox
,
137 unsigned int sync_point
,
139 mailbox
->UpdateSyncPoint(sync_point
);
142 void ReflectorImpl::UpdateTexture(const gfx::Size
& source_size
,
143 const gfx::Rect
& redraw_rect
) {
144 if (needs_set_mailbox_
) {
145 mirroring_layer_
->SetTextureMailbox(
146 cc::TextureMailbox(mailbox_
->holder()),
147 cc::SingleReleaseCallback::Create(base::Bind(ReleaseMailbox
, mailbox_
)),
149 needs_set_mailbox_
= false;
151 mirroring_layer_
->SetTextureSize(source_size
);
153 mirroring_layer_
->SetBounds(gfx::Rect(source_size
));
154 mirroring_layer_
->SetTextureFlipped(flip_texture_
);
155 mirroring_layer_
->SchedulePaint(redraw_rect
);
158 } // namespace content