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

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

Powered by Google App Engine
This is Rietveld 408576698