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