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

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: More sdk differences 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 <OpenGL/gl.h>
8 #include <OpenGL/glext.h>
8 9
9 #include "content/common/gpu/gpu_messages.h" 10 #include "content/common/gpu/gpu_messages.h"
10 #include "ui/accelerated_widget_mac/surface_handle_types.h" 11 #include "ui/accelerated_widget_mac/surface_handle_types.h"
11 #include "ui/base/cocoa/animation_utils.h" 12 #include "ui/base/cocoa/animation_utils.h"
12 #include "ui/base/cocoa/remote_layer_api.h" 13 #include "ui/base/cocoa/remote_layer_api.h"
13 #include "ui/gfx/geometry/dip_util.h" 14 #include "ui/gfx/geometry/dip_util.h"
14 #include "ui/gl/gl_image_io_surface.h" 15 #include "ui/gl/gl_image_io_surface.h"
16 #include "ui/gl/scoped_api.h"
17 #include "ui/gl/scoped_cgl.h"
18
19 #define LOG_GL_ERRORS(msg) \
tapted 2015/08/05 07:55:57 Not sure a macro is right for this. There's a `Cle
ccameron 2015/08/05 21:00:43 Changed this to a function.
20 do { \
21 for (GLenum gl_error = glGetError(); gl_error != GL_NO_ERROR; \
22 gl_error = glGetError()) { \
23 LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; \
24 } \
25 } while (0)
15 26
16 namespace content { 27 namespace content {
17 28
18 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( 29 ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac(
19 GpuChannelManager* manager, 30 GpuChannelManager* manager,
20 GpuCommandBufferStub* stub, 31 GpuCommandBufferStub* stub,
21 gfx::PluginWindowHandle handle) 32 gfx::PluginWindowHandle handle)
22 : scale_factor_(1), pending_overlay_image_(nullptr) { 33 : scale_factor_(1), pending_overlay_image_(nullptr), weak_factory_(this) {
23 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); 34 helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
24 } 35 }
25 36
26 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { 37 ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() {
27 gfx::GLImageIOSurface::SetLayerForWidget(widget_, nil);
28 } 38 }
29 39
30 bool ImageTransportSurfaceOverlayMac::Initialize() { 40 bool ImageTransportSurfaceOverlayMac::Initialize() {
31 if (!helper_->Initialize()) 41 if (!helper_->Initialize())
32 return false; 42 return false;
33 43
34 // Create the CAContext to send this to the GPU process, and the layer for 44 // Create the CAContext to send this to the GPU process, and the layer for
35 // the context. 45 // the context.
36 CGSConnectionID connection_id = CGSMainConnectionID(); 46 CGSConnectionID connection_id = CGSMainConnectionID();
37 ca_context_.reset( 47 ca_context_.reset(
38 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); 48 [[CAContext contextWithCGSConnection:connection_id options:@{}] retain]);
39 layer_.reset([[CALayer alloc] init]); 49 layer_.reset([[CALayer alloc] init]);
50 [layer_ setGeometryFlipped:YES];
40 [ca_context_ setLayer:layer_]; 51 [ca_context_ setLayer:layer_];
41 52
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; 53 return true;
49 } 54 }
50 55
51 void ImageTransportSurfaceOverlayMac::Destroy() {} 56 void ImageTransportSurfaceOverlayMac::Destroy() {
57 CheckAndDisplayPendingSwaps(true);
58 }
52 59
53 bool ImageTransportSurfaceOverlayMac::IsOffscreen() { 60 bool ImageTransportSurfaceOverlayMac::IsOffscreen() {
54 return false; 61 return false;
55 } 62 }
56 63
57 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { 64 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
65 const gfx::Rect& pixel_damage_rect) {
58 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers"); 66 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers");
59 67
60 // A flush is required to ensure that all content appears in the layer. 68 // The remainder of the function will populate the PendingSwap structure and
61 { 69 // then enqueue it.
62 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); 70 PendingSwap this_swap;
63 glFlush();
64 }
65 71
66 // There should exist only one overlay image, and it should cover the whole 72 // There should exist only one overlay image, and it should cover the whole
67 // surface. 73 // surface.
68 DCHECK(pending_overlay_image_); 74 DCHECK(pending_overlay_image_);
69 if (pending_overlay_image_) { 75 if (pending_overlay_image_) {
70 TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::setContents"); 76 gfx::GLImageIOSurface* pending_overlay_image_io_surface =
71 ScopedCAActionDisabler disabler; 77 static_cast<gfx::GLImageIOSurface*>(pending_overlay_image_);
72 gfx::Rect dip_bounds = gfx::ConvertRectToDIP( 78 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; 79 pending_overlay_image_ = nullptr;
78 } 80 }
79 81
82 // A flush is required to ensure that all content appears in the layer.
83 {
84 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
85 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::glFlush", "surface",
86 this_swap.io_surface.get());
87 LOG_GL_ERRORS("before flushing frame");
88 this_swap.cgl_context.reset(CGLGetCurrentContext(),
89 base::scoped_policy::RETAIN);
90 glGenFencesAPPLE(1, &this_swap.fence);
91 glSetFenceAPPLE(this_swap.fence);
92 glFlush();
93 LOG_GL_ERRORS("while flushing frame");
94 }
95
96 this_swap.dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_);
97 pending_swaps_.push_back(this_swap);
98
99 PostCheckAndDisplayPendingSwaps();
100 return gfx::SwapResult::SWAP_ACK;
101 }
102
103 void ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps(
104 bool force_immediate_display) {
105 TRACE_EVENT0("gpu",
106 "ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps");
107 if (pending_swaps_.empty())
108 return;
109
110 // Check if the pending work has finished (and early-out if it is not, and
111 // this is not forced).
112 const PendingSwap& this_swap = pending_swaps_.front();
113 {
114 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
115 gfx::ScopedCGLSetCurrentContext scoped_set_current(this_swap.cgl_context);
116
117 LOG_GL_ERRORS("before testing fence");
118 bool result = !glIsFenceAPPLE(this_swap.fence) ||
tapted 2015/08/05 07:55:57 Should `glIsFenceAPPLE` be a DCHECK?
ccameron 2015/08/05 21:00:43 Done.
119 glTestFenceAPPLE(this_swap.fence);
120 LOG_GL_ERRORS("after testing fence");
121 if (!result && !force_immediate_display) {
122 PostCheckAndDisplayPendingSwaps();
123 return;
124 }
125 glDeleteFencesAPPLE(1, &this_swap.fence);
126 LOG_GL_ERRORS("while deleting fence");
127 }
128
129 // Update the CALayer hierarchy.
130 {
131 TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents",
132 "surface", this_swap.io_surface.get());
133 ScopedCAActionDisabler disabler;
134 id new_contents = static_cast<id>(this_swap.io_surface.get());
135 [layer_ setContents:new_contents];
136 [layer_ setFrame:gfx::Rect(this_swap.dip_size).ToCGRect()];
tapted 2015/08/05 07:55:57 I wonder if there's a downside to calling this whe
ccameron 2015/08/05 21:00:43 Sounds like a good idea. Updated.
137 }
138
139 // Remove this swap from the queue.
140 pending_swaps_.pop_front();
141
142 // Send acknowledgement to the browser.
80 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; 143 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
81 params.surface_handle = 144 params.surface_handle =
82 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); 145 ui::SurfaceHandleFromCAContextID([ca_context_ contextId]);
83 params.size = pixel_size_; 146 params.size = pixel_size_;
84 params.scale_factor = scale_factor_; 147 params.scale_factor = scale_factor_;
85 params.latency_info.swap(latency_info_); 148 params.latency_info.swap(latency_info_);
86 helper_->SendAcceleratedSurfaceBuffersSwapped(params); 149 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
87 return gfx::SwapResult::SWAP_ACK; 150
151 // If this was a forced display, ensure that all pending swaps are flushed.
152 if (force_immediate_display && !pending_swaps_.empty())
153 CheckAndDisplayPendingSwaps(true);
tapted 2015/08/05 07:55:57 tail recursion scares me a bit - maybe a wrapper f
ccameron 2015/08/05 21:00:43 Sounds reasonable. Done.
154 }
155
156 void ImageTransportSurfaceOverlayMac::PostCheckAndDisplayPendingSwaps() {
157 bool force_immediate_display = true;
158 base::TimeDelta delay;
159 if (display_link_mac_) {
160 base::TimeTicks timebase;
161 base::TimeDelta interval;
162 if (display_link_mac_->GetVSyncParameters(&timebase, &interval)) {
163 base::TimeTicks now = base::TimeTicks::Now();
164 // Make the timer fire halfway through the vsync interval (since that
165 // makes actual vsync alignment the most likely).
166 timebase -= interval / 2;
167 // Make sure that timebase is before now (to simplify the below
168 // computations).
169 if (timebase >= now)
170 timebase -= (1 + (timebase - now) / interval) * interval;
171 // Compute the target time.
172 base::TimeTicks target =
173 timebase + (1 + (now - timebase) / interval) * interval;
174 delay = target - now;
175 force_immediate_display = false;
176 }
177 }
178 base::MessageLoop::current()->PostDelayedTask(
179 FROM_HERE,
180 base::Bind(&ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps,
181 weak_factory_.GetWeakPtr(), force_immediate_display),
182 delay);
183 }
184
185 gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() {
186 return SwapBuffersInternal(gfx::Rect(pixel_size_));
88 } 187 }
89 188
90 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, 189 gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x,
91 int y, 190 int y,
92 int width, 191 int width,
93 int height) { 192 int height) {
94 return SwapBuffers(); 193 return SwapBuffersInternal(gfx::Rect(x, y, width, height));
95 } 194 }
96 195
97 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { 196 bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() {
98 return true; 197 return true;
99 } 198 }
100 199
101 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() { 200 gfx::Size ImageTransportSurfaceOverlayMac::GetSize() {
102 return gfx::Size(); 201 return gfx::Size();
103 } 202 }
104 203
(...skipping 17 matching lines...) Expand all
122 DCHECK(!pending_overlay_image_); 221 DCHECK(!pending_overlay_image_);
123 pending_overlay_image_ = image; 222 pending_overlay_image_ = image;
124 return true; 223 return true;
125 } 224 }
126 225
127 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const { 226 bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const {
128 return true; 227 return true;
129 } 228 }
130 229
131 void ImageTransportSurfaceOverlayMac::OnBufferPresented( 230 void ImageTransportSurfaceOverlayMac::OnBufferPresented(
132 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {} 231 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
232 if (display_link_mac_ && display_link_mac_->display_id() == params.display_id)
233 return;
234 display_link_mac_ = ui::DisplayLinkMac::GetForDisplay(params.display_id);
235 }
133 236
134 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size, 237 void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size,
135 float scale_factor) { 238 float scale_factor) {
239 // Flush through any pending frames.
240 CheckAndDisplayPendingSwaps(true);
136 pixel_size_ = pixel_size; 241 pixel_size_ = pixel_size;
137 scale_factor_ = scale_factor; 242 scale_factor_ = scale_factor;
138 } 243 }
139 244
140 void ImageTransportSurfaceOverlayMac::SetLatencyInfo( 245 void ImageTransportSurfaceOverlayMac::SetLatencyInfo(
141 const std::vector<ui::LatencyInfo>& latency_info) { 246 const std::vector<ui::LatencyInfo>& latency_info) {
142 latency_info_.insert( 247 latency_info_.insert(
143 latency_info_.end(), latency_info.begin(), latency_info.end()); 248 latency_info_.end(), latency_info.begin(), latency_info.end());
144 } 249 }
145 250
146 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {} 251 void ImageTransportSurfaceOverlayMac::WakeUpGpu() {}
147 252
253
254 ImageTransportSurfaceOverlayMac::PendingSwap::PendingSwap()
255 : fence(0) {
256 }
257
258 ImageTransportSurfaceOverlayMac::PendingSwap::~PendingSwap() {
259 }
260
148 } // namespace content 261 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698