OLD | NEW |
---|---|
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 Loading... | |
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 |
OLD | NEW |