Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Side by Side Diff: content/common/gpu/image_transport_surface_overlay_mac.mm

Issue 1273563002: Mac Overlays: Add GPU back-pressure (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporate review feedback Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/common/gpu/image_transport_surface_overlay_mac.h" 5 #include "content/common/gpu/image_transport_surface_overlay_mac.h"
6 6
7 #include <OpenGL/gl.h> 7 // This type consistently causes problem on Mac, and needs to be dealt with
8 // in a systemic way.
9 // http://crbug.com/517208
10 #ifndef GL_OES_EGL_image
11 typedef void* GLeglImageOES;
12 #endif
8 13
9 #include "content/common/gpu/gpu_messages.h" 14 #include "content/common/gpu/gpu_messages.h"
10 #include "ui/accelerated_widget_mac/surface_handle_types.h" 15 #include "ui/accelerated_widget_mac/surface_handle_types.h"
11 #include "ui/base/cocoa/animation_utils.h" 16 #include "ui/base/cocoa/animation_utils.h"
12 #include "ui/base/cocoa/remote_layer_api.h" 17 #include "ui/base/cocoa/remote_layer_api.h"
13 #include "ui/gfx/geometry/dip_util.h" 18 #include "ui/gfx/geometry/dip_util.h"
19 #include "ui/gl/gl_fence_apple.h"
14 #include "ui/gl/gl_image_io_surface.h" 20 #include "ui/gl/gl_image_io_surface.h"
21 #include "ui/gl/scoped_api.h"
22 #include "ui/gl/scoped_cgl.h"
23
24 namespace {
25
26 void CheckGLErrors(const char* msg) {
27 GLenum gl_error;
28 while ((gl_error = glGetError()) != GL_NO_ERROR) {
29 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error;
30 }
31 }
32
33 } // namespace
15 34
16 namespace content { 35 namespace content {
17 36
37 class ImageTransportSurfaceOverlayMac::PendingSwap :
38 public base::RefCounted<PendingSwap> {
39 public:
40 PendingSwap() {}
41
42 // The IOSurface with new content for this swap.
43 base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
44
45 // A fence object, and the CGL context it was issued in.
46 base::ScopedTypeRef<CGLContextObj> cgl_context;
47 scoped_ptr<gfx::GLFenceAPPLE> fence;
48
49 // The size of the full frame, in dip.
50 gfx::Size dip_size;
51
52 protected:
53 friend class base::RefCounted<PendingSwap>;
54
55 virtual ~PendingSwap() { DCHECK(!fence); }
56 };
57
18 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( 58 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac(
19 GpuChannelManager* manager, 59 GpuChannelManager* manager,
20 GpuCommandBufferStub* stub, 60 GpuCommandBufferStub* stub,
21 gfx::PluginWindowHandle handle) 61 gfx::PluginWindowHandle handle)
22 : scale_factor_(1), pending_overlay_image_(nullptr) { 62 : scale_factor_(1), pending_overlay_image_(nullptr), weak_factory_(this) {
23 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); 63 helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
24 } 64 }
25 65
26 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { 66 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() {
27 gfx::GLImageIOSurface::SetLayerForWidget(widget_, nil);
28 } 67 }
29 68
30 bool ImageTransportSurfaceOverlayMac::Initialize() { 69 bool ImageTransportSurfaceOverlayMac::Initialize() {
31 if (!helper_->Initialize()) 70 if (!helper_->Initialize())
32 return false; 71 return false;
33 72
34 // Create the CAContext to send this to the GPU process, and the layer for 73 // Create the CAContext to send this to the GPU process, and the layer for
35 // the context. 74 // the context.
36 CGSConnectionID connection_id = CGSMainConnectionID(); 75 CGSConnectionID connection_id = CGSMainConnectionID();
37 ca_context_.reset( 76 ca_context_.reset(
38 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); 77 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]);
39 layer_.reset([[CALayer alloc] init]); 78 layer_.reset([[CALayer alloc] init]);
79 [layer_ setGeometryFlipped:YES];
40 [ca_context_ setLayer:layer_]; 80 [ca_context_ setLayer:layer_];
41 81
42 // Register the CALayer so that it can be picked up in GLImageIOSurface.
43 static intptr_t previous_widget = 0;
44 previous_widget += 1;
45 widget_ = reinterpret_cast<gfx::AcceleratedWidget>(previous_widget);
46 gfx::GLImageIOSurface::SetLayerForWidget(widget_, layer_);
47
48 return true; 82 return true;
49 } 83 }
50 84
51 void ImageTransportSurfaceOverlayMac::Destroy() {} 85 void ImageTransportSurfaceOverlayMac::Destroy() {
86 FinishAllPendingSwaps();
87 }
52 88
53 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { 89 bool ImageTransportSurfaceOverlayMac::IsOffscreen() {
54 return false; 90 return false;
55 } 91 }
56 92
57 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { 93 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
94 const gfx::Rect& pixel_damage_rect) {
58 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers"); 95 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers");
59 96
60 // A flush is required to ensure that all content appears in the layer. 97 // The remainder of the function will populate the PendingSwap structure and
61 { 98 // then enqueue it.
62 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); 99 scoped_refptr<PendingSwap> this_swap(new PendingSwap);
63 glFlush();
64 }
65 100
66 // There should exist only one overlay image, and it should cover the whole 101 // There should exist only one overlay image, and it should cover the whole
67 // surface. 102 // surface.
68 DCHECK(pending_overlay_image_); 103 DCHECK(pending_overlay_image_);
69 if (pending_overlay_image_) { 104 if (pending_overlay_image_) {
70 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::setContents"); 105 gfx::GLImageIOSurface* pending_overlay_image_io_surface =
71 ScopedCAActionDisabler disabler; 106 static_cast<gfx::GLImageIOSurface*>(pending_overlay_image_);
72 gfx::Rect dip_bounds = gfx::ConvertRectToDIP( 107 this_swap->io_surface = pending_overlay_image_io_surface->io_surface();
73 scale_factor_, gfx::Rect(pixel_size_));
74 gfx::RectF crop_rect(0, 0, 1, 1);
75 pending_overlay_image_->ScheduleOverlayPlane(
76 widget_, 0, gfx::OVERLAY_TRANSFORM_NONE, dip_bounds, crop_rect);
77 pending_overlay_image_ = nullptr; 108 pending_overlay_image_ = nullptr;
78 } 109 }
79 110
111 // A flush is required to ensure that all content appears in the layer.
112 {
113 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
114 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::glFlush", "surface",
115 this_swap->io_surface.get());
116 CheckGLErrors("before flushing frame");
117 this_swap->cgl_context.reset(CGLGetCurrentContext(),
118 base::scoped_policy::RETAIN);
119 this_swap->fence.reset(new gfx::GLFenceAPPLE);
120 CheckGLErrors("while flushing frame");
121 }
122
123 this_swap->dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_);
124 pending_swaps_.push_back(this_swap);
125
126 PostCheckAndDisplayPendingSwaps();
127 return gfx::SwapResult::SWAP_ACK;
128 }
129
130 void ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps(
131 bool force_immediate_display) {
132 TRACE_EVENT0("gpu",
133 "ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps");
134 if (pending_swaps_.empty())
135 return;
136
137 // Check if the pending work has finished (and early-out if it is not, and
138 // this is not forced).
139 scoped_refptr<PendingSwap> this_swap = pending_swaps_.front();
140 {
141 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
142 gfx::ScopedCGLSetCurrentContext scoped_set_current(this_swap->cgl_context);
143
144 CheckGLErrors("before testing fence");
145 bool result = this_swap->fence->HasCompleted();
146 CheckGLErrors("after testing fence");
147 if (!result && !force_immediate_display) {
148 PostCheckAndDisplayPendingSwaps();
149 return;
150 }
151 this_swap->fence.reset();
152 CheckGLErrors("while deleting fence");
153 }
154
155 // Update the CALayer hierarchy.
156 {
157 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents",
158 "surface", this_swap->io_surface.get());
159 ScopedCAActionDisabler disabler;
160 id new_contents = static_cast<id>(this_swap->io_surface.get());
161 [layer_ setContents:new_contents];
162 CGRect new_frame = gfx::Rect(this_swap->dip_size).ToCGRect();
163 if (!CGRectEqualToRect([layer_ frame], new_frame))
164 [layer_ setFrame:new_frame];
165 }
166
167 // Remove this swap from the queue.
168 pending_swaps_.pop_front();
169
170 // Send acknowledgement to the browser.
80 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; 171 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
81 params.surface_handle = 172 params.surface_handle =
82 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); 173 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]);
83 params.size = pixel_size_; 174 params.size = pixel_size_;
84 params.scale_factor = scale_factor_; 175 params.scale_factor = scale_factor_;
85 params.latency_info.swap(latency_info_); 176 params.latency_info.swap(latency_info_);
86 helper_->SendAcceleratedSurfaceBuffersSwapped(params); 177 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
87 return gfx::SwapResult::SWAP_ACK; 178 }
179
180 void ImageTransportSurfaceOverlayMac::PostCheckAndDisplayPendingSwaps() {
181 bool force_immediate_display = true;
182 base::TimeDelta delay;
183 if (display_link_mac_) {
184 base::TimeTicks timebase;
185 base::TimeDelta interval;
186 if (display_link_mac_->GetVSyncParameters(&timebase, &interval)) {
187 base::TimeTicks now = base::TimeTicks::Now();
188 // Make the timer fire halfway through the vsync interval (since that
189 // makes actual vsync alignment the most likely).
190 timebase -= interval / 2;
191 // Make sure that timebase is before now (to simplify the below
192 // computations).
193 if (timebase >= now)
194 timebase -= (1 + (timebase - now) / interval) * interval;
195 // Compute the target time.
196 base::TimeTicks target =
197 timebase + (1 + (now - timebase) / interval) * interval;
tapted 2015/08/06 00:56:49 nit: indent 2 extra spaces
ccameron 2015/08/06 01:42:47 Done.
198 delay = target - now;
199 force_immediate_display = false;
200 }
201 }
202 base::MessageLoop::current()->PostDelayedTask(
203 FROM_HERE,
204 base::Bind(&ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps,
205 weak_factory_.GetWeakPtr(), force_immediate_display),
206 delay);
Ken Russell (switch to Gerrit) 2015/08/05 21:55:23 This will busy-loop while the browser is waiting f
ccameron 2015/08/06 01:42:47 That could very well happen -- the effect of it wo
207 }
208
209 void ImageTransportSurfaceOverlayMac::FinishAllPendingSwaps() {
210 while (!pending_swaps_.empty())
211 CheckAndDisplayPendingSwaps(true);
Ken Russell (switch to Gerrit) 2015/08/05 21:55:23 Would it better match the intended behavior to act
ccameron 2015/08/06 01:42:47 Doing a finish on the GLFenceAPPLE would have this
212 }
213
214 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() {
215 return SwapBuffersInternal(gfx::Rect(pixel_size_));
88 } 216 }
89 217
90 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, 218 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x,
91 int y, 219 int y,
92 int width, 220 int width,
93 int height) { 221 int height) {
94 return SwapBuffers(); 222 return SwapBuffersInternal(gfx::Rect(x, y, width, height));
95 } 223 }
96 224
97 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { 225 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() {
98 return true; 226 return true;
99 } 227 }
100 228
101 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { 229 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() {
102 return gfx::Size(); 230 return gfx::Size();
103 } 231 }
104 232
(...skipping 17 matching lines...) Expand all
122 DCHECK(!pending_overlay_image_); 250 DCHECK(!pending_overlay_image_);
123 pending_overlay_image_ = image; 251 pending_overlay_image_ = image;
124 return true; 252 return true;
125 } 253 }
126 254
127 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { 255 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const {
128 return true; 256 return true;
129 } 257 }
130 258
131 void ImageTransportSurfaceOverlayMac::OnBufferPresented( 259 void ImageTransportSurfaceOverlayMac::OnBufferPresented(
132 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {} 260 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
261 if (display_link_mac_ && display_link_mac_->display_id() == params.display_id)
262 return;
263 display_link_mac_ = ui::DisplayLinkMac::GetForDisplay(params.display_id);
264 }
133 265
134 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size, 266 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size,
135 float scale_factor) { 267 float scale_factor) {
268 // Flush through any pending frames.
269 FinishAllPendingSwaps();
136 pixel_size_ = pixel_size; 270 pixel_size_ = pixel_size;
137 scale_factor_ = scale_factor; 271 scale_factor_ = scale_factor;
138 } 272 }
139 273
140 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( 274 void ImageTransportSurfaceOverlayMac::SetLatencyInfo(
141 const std::vector<ui::LatencyInfo>& latency_info) { 275 const std::vector<ui::LatencyInfo>& latency_info) {
142 latency_info_.insert( 276 latency_info_.insert(
143 latency_info_.end(), latency_info.begin(), latency_info.end()); 277 latency_info_.end(), latency_info.begin(), latency_info.end());
144 } 278 }
145 279
146 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {} 280 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {}
147 281
148 } // namespace content 282 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698