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

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: IRF 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 #include <IOSurface/IOSurface.h>
8 #include <OpenGL/GL.h>
8 9
10 // This type consistently causes problem on Mac, and needs to be dealt with
11 // in a systemic way.
12 // http://crbug.com/517208
13 #ifndef GL_OES_EGL_image
14 typedef void* GLeglImageOES;
15 #endif
16
17 #include "base/mac/scoped_cftyperef.h"
9 #include "content/common/gpu/gpu_messages.h" 18 #include "content/common/gpu/gpu_messages.h"
10 #include "ui/accelerated_widget_mac/surface_handle_types.h" 19 #include "ui/accelerated_widget_mac/surface_handle_types.h"
11 #include "ui/base/cocoa/animation_utils.h" 20 #include "ui/base/cocoa/animation_utils.h"
12 #include "ui/base/cocoa/remote_layer_api.h" 21 #include "ui/base/cocoa/remote_layer_api.h"
13 #include "ui/gfx/geometry/dip_util.h" 22 #include "ui/gfx/geometry/dip_util.h"
23 #include "ui/gl/gl_fence_apple.h"
14 #include "ui/gl/gl_image_io_surface.h" 24 #include "ui/gl/gl_image_io_surface.h"
25 #include "ui/gl/scoped_api.h"
26 #include "ui/gl/scoped_cgl.h"
27
28 namespace {
29
30 void CheckGLErrors(const char* msg) {
31 GLenum gl_error;
32 while ((gl_error = glGetError()) != GL_NO_ERROR) {
33 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error;
34 }
35 }
36
37 } // namespace
15 38
16 namespace content { 39 namespace content {
17 40
41 class ImageTransportSurfaceOverlayMac::PendingSwap :
42 public base::RefCounted<PendingSwap> {
43 public:
44 PendingSwap() {}
45
46 // The IOSurface with new content for this swap.
47 base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
48
49 // A fence object, and the CGL context it was issued in.
50 base::ScopedTypeRef<CGLContextObj> cgl_context;
51 scoped_ptr<gfx::GLFenceAPPLE> fence;
52
53 // The size of the full frame, in dip.
54 gfx::Size dip_size;
55
56 std::vector<ui::LatencyInfo> latency_info;
57
58 protected:
59 friend class base::RefCounted<PendingSwap>;
60
61 virtual ~PendingSwap() { DCHECK(!fence); }
62 };
63
18 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( 64 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac(
19 GpuChannelManager* manager, 65 GpuChannelManager* manager,
20 GpuCommandBufferStub* stub, 66 GpuCommandBufferStub* stub,
21 gfx::PluginWindowHandle handle) 67 gfx::PluginWindowHandle handle)
22 : scale_factor_(1), pending_overlay_image_(nullptr) { 68 : scale_factor_(1), pending_overlay_image_(nullptr), weak_factory_(this) {
23 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); 69 helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
24 } 70 }
25 71
26 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { 72 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() {
27 gfx::GLImageIOSurface::SetLayerForWidget(widget_, nil);
28 } 73 }
29 74
30 bool ImageTransportSurfaceOverlayMac::Initialize() { 75 bool ImageTransportSurfaceOverlayMac::Initialize() {
31 if (!helper_->Initialize()) 76 if (!helper_->Initialize())
32 return false; 77 return false;
33 78
34 // Create the CAContext to send this to the GPU process, and the layer for 79 // Create the CAContext to send this to the GPU process, and the layer for
35 // the context. 80 // the context.
36 CGSConnectionID connection_id = CGSMainConnectionID(); 81 CGSConnectionID connection_id = CGSMainConnectionID();
37 ca_context_.reset( 82 ca_context_.reset(
38 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); 83 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]);
39 layer_.reset([[CALayer alloc] init]); 84 layer_.reset([[CALayer alloc] init]);
85 [layer_ setGeometryFlipped:YES];
40 [ca_context_ setLayer:layer_]; 86 [ca_context_ setLayer:layer_];
41 87
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; 88 return true;
49 } 89 }
50 90
51 void ImageTransportSurfaceOverlayMac::Destroy() {} 91 void ImageTransportSurfaceOverlayMac::Destroy() {
92 FinishAllPendingSwaps();
93 }
52 94
53 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { 95 bool ImageTransportSurfaceOverlayMac::IsOffscreen() {
54 return false; 96 return false;
55 } 97 }
56 98
57 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { 99 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
100 const gfx::Rect& pixel_damage_rect) {
58 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers"); 101 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers");
59 102
60 // A flush is required to ensure that all content appears in the layer. 103 // The remainder of the function will populate the PendingSwap structure and
61 { 104 // then enqueue it.
62 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); 105 scoped_refptr<PendingSwap> this_swap(new PendingSwap);
63 glFlush(); 106 this_swap->latency_info.swap(latency_info_);
64 }
65 107
66 // There should exist only one overlay image, and it should cover the whole 108 // There should exist only one overlay image, and it should cover the whole
67 // surface. 109 // surface.
68 DCHECK(pending_overlay_image_); 110 DCHECK(pending_overlay_image_);
69 if (pending_overlay_image_) { 111 if (pending_overlay_image_) {
70 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::setContents"); 112 gfx::GLImageIOSurface* pending_overlay_image_io_surface =
71 ScopedCAActionDisabler disabler; 113 static_cast<gfx::GLImageIOSurface*>(pending_overlay_image_);
72 gfx::Rect dip_bounds = gfx::ConvertRectToDIP( 114 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; 115 pending_overlay_image_ = nullptr;
78 } 116 }
79 117
118 // A flush is required to ensure that all content appears in the layer.
119 {
120 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
121 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::glFlush", "surface",
122 this_swap->io_surface.get());
123 CheckGLErrors("before flushing frame");
124 this_swap->cgl_context.reset(CGLGetCurrentContext(),
125 base::scoped_policy::RETAIN);
126 this_swap->fence.reset(new gfx::GLFenceAPPLE);
127 CheckGLErrors("while flushing frame");
128 }
129
130 this_swap->dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_);
131 pending_swaps_.push_back(this_swap);
132
133 PostCheckAndDisplayPendingSwaps();
134 return gfx::SwapResult::SWAP_ACK;
135 }
136
137 void ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps(
138 bool force_immediate_display) {
139 TRACE_EVENT0("gpu",
140 "ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps");
141 if (pending_swaps_.empty())
142 return;
143
144 // Check if the pending work has finished (and early-out if it is not, and
145 // this is not forced).
146 scoped_refptr<PendingSwap> this_swap = pending_swaps_.front();
147 {
148 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
149 gfx::ScopedCGLSetCurrentContext scoped_set_current(this_swap->cgl_context);
150
151 CheckGLErrors("before testing fence");
152 bool result = this_swap->fence->HasCompleted();
153 CheckGLErrors("after testing fence");
154 if (!result && !force_immediate_display) {
155 PostCheckAndDisplayPendingSwaps();
156 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::fenceNotReady",
157 "surface", this_swap->io_surface.get());
158 return;
159 }
160 this_swap->fence.reset();
161 CheckGLErrors("while deleting fence");
162 }
163
164 // Update the CALayer hierarchy.
165 {
166 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents",
167 "surface", this_swap->io_surface.get());
168 ScopedCAActionDisabler disabler;
169 id new_contents = static_cast<id>(this_swap->io_surface.get());
170 [layer_ setContents:new_contents];
171 CGRect new_frame = gfx::Rect(this_swap->dip_size).ToCGRect();
172 if (!CGRectEqualToRect([layer_ frame], new_frame))
173 [layer_ setFrame:new_frame];
174 }
175
176 // Remove this swap from the queue.
177 pending_swaps_.pop_front();
178
179 // Send acknowledgement to the browser.
80 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; 180 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
81 params.surface_handle = 181 params.surface_handle =
82 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); 182 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]);
83 params.size = pixel_size_; 183 params.size = pixel_size_;
84 params.scale_factor = scale_factor_; 184 params.scale_factor = scale_factor_;
85 params.latency_info.swap(latency_info_); 185 params.latency_info.swap(this_swap->latency_info);
86 helper_->SendAcceleratedSurfaceBuffersSwapped(params); 186 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
87 return gfx::SwapResult::SWAP_ACK; 187 }
188
189 void ImageTransportSurfaceOverlayMac::PostCheckAndDisplayPendingSwaps() {
190 bool force_immediate_display = true;
191 base::TimeDelta delay;
192 if (display_link_mac_) {
193 base::TimeTicks timebase;
194 base::TimeDelta interval;
195 if (display_link_mac_->GetVSyncParameters(&timebase, &interval)) {
196 base::TimeTicks now = base::TimeTicks::Now();
197 // Make the timer fire halfway through the vsync interval (since that
198 // makes actual vsync alignment the most likely).
199 timebase -= interval / 2;
200 // Make sure that timebase is before now (to simplify the below
201 // computations).
202 if (timebase >= now)
203 timebase -= (1 + (timebase - now) / interval) * interval;
204 // Compute the target time.
205 base::TimeTicks target =
206 timebase + (1 + (now - timebase) / interval) * interval;
207 delay = target - now;
208 force_immediate_display = false;
209 }
210 }
211 base::MessageLoop::current()->PostDelayedTask(
212 FROM_HERE,
213 base::Bind(&ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps,
214 weak_factory_.GetWeakPtr(), force_immediate_display),
215 delay);
216 }
217
218 void ImageTransportSurfaceOverlayMac::FinishAllPendingSwaps() {
219 while (!pending_swaps_.empty())
220 CheckAndDisplayPendingSwaps(true);
221 }
222
223 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() {
224 return SwapBuffersInternal(gfx::Rect(pixel_size_));
88 } 225 }
89 226
90 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, 227 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x,
91 int y, 228 int y,
92 int width, 229 int width,
93 int height) { 230 int height) {
94 return SwapBuffers(); 231 return SwapBuffersInternal(gfx::Rect(x, y, width, height));
95 } 232 }
96 233
97 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { 234 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() {
98 return true; 235 return true;
99 } 236 }
100 237
101 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { 238 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() {
102 return gfx::Size(); 239 return gfx::Size();
103 } 240 }
104 241
(...skipping 17 matching lines...) Expand all
122 DCHECK(!pending_overlay_image_); 259 DCHECK(!pending_overlay_image_);
123 pending_overlay_image_ = image; 260 pending_overlay_image_ = image;
124 return true; 261 return true;
125 } 262 }
126 263
127 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { 264 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const {
128 return true; 265 return true;
129 } 266 }
130 267
131 void ImageTransportSurfaceOverlayMac::OnBufferPresented( 268 void ImageTransportSurfaceOverlayMac::OnBufferPresented(
132 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {} 269 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
270 if (display_link_mac_ &&
271 display_link_mac_->display_id() == params.display_id_for_vsync)
272 return;
273 display_link_mac_ = ui::DisplayLinkMac::GetForDisplay(
274 params.display_id_for_vsync);
275 }
133 276
134 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size, 277 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size,
135 float scale_factor) { 278 float scale_factor) {
279 // Flush through any pending frames.
280 FinishAllPendingSwaps();
136 pixel_size_ = pixel_size; 281 pixel_size_ = pixel_size;
137 scale_factor_ = scale_factor; 282 scale_factor_ = scale_factor;
138 } 283 }
139 284
140 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( 285 void ImageTransportSurfaceOverlayMac::SetLatencyInfo(
141 const std::vector<ui::LatencyInfo>& latency_info) { 286 const std::vector<ui::LatencyInfo>& latency_info) {
142 latency_info_.insert( 287 latency_info_.insert(
143 latency_info_.end(), latency_info.begin(), latency_info.end()); 288 latency_info_.end(), latency_info.begin(), latency_info.end());
144 } 289 }
145 290
146 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {} 291 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {}
147 292
148 } // namespace content 293 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698