| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_calayer_mac.h" | 5 #include "content/common/gpu/image_transport_surface_calayer_mac.h" |
| 6 | 6 |
| 7 #include "base/mac/sdk_forward_declarations.h" | 7 #include "base/mac/sdk_forward_declarations.h" |
| 8 #include "content/common/gpu/surface_handle_types_mac.h" | 8 #include "content/common/gpu/surface_handle_types_mac.h" |
| 9 #include "ui/base/cocoa/animation_utils.h" | 9 #include "ui/base/cocoa/animation_utils.h" |
| 10 #include "ui/gfx/geometry/size_conversions.h" | 10 #include "ui/gfx/geometry/size_conversions.h" |
| 11 | 11 |
| 12 @interface ImageTransportLayer (Private) { | 12 @interface ImageTransportLayer : CAOpenGLLayer { |
| 13 content::CALayerStorageProvider* storageProvider_; |
| 13 } | 14 } |
| 15 - (id)initWithStorageProvider:(content::CALayerStorageProvider*)storageProvider; |
| 16 - (void)resetStorageProvider; |
| 14 @end | 17 @end |
| 15 | 18 |
| 16 @implementation ImageTransportLayer | 19 @implementation ImageTransportLayer |
| 17 | 20 |
| 18 - (id)initWithContext:(CGLContextObj)context | 21 - (id)initWithStorageProvider: |
| 19 withTexture:(GLuint)texture | 22 (content::CALayerStorageProvider*)storageProvider { |
| 20 withPixelSize:(gfx::Size)pixelSize | 23 if (self = [super init]) |
| 21 withScaleFactor:(float)scaleFactor { | 24 storageProvider_ = storageProvider; |
| 22 if (self = [super init]) { | |
| 23 shareContext_.reset(CGLRetainContext(context)); | |
| 24 texture_ = texture; | |
| 25 pixelSize_ = pixelSize; | |
| 26 | |
| 27 gfx::Size dipSize(gfx::ToFlooredSize(gfx::ScaleSize( | |
| 28 pixelSize_, 1.0f / scaleFactor))); | |
| 29 [self setContentsScale:scaleFactor]; | |
| 30 [self setFrame:CGRectMake(0, 0, dipSize.width(), dipSize.height())]; | |
| 31 } | |
| 32 return self; | 25 return self; |
| 33 } | 26 } |
| 34 | 27 |
| 28 - (void)resetStorageProvider { |
| 29 storageProvider_ = NULL; |
| 30 } |
| 31 |
| 35 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { | 32 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { |
| 36 return CGLRetainPixelFormat(CGLGetPixelFormat(shareContext_)); | 33 if (!storageProvider_) |
| 34 return NULL; |
| 35 return CGLRetainPixelFormat(CGLGetPixelFormat( |
| 36 storageProvider_->LayerShareGroupContext())); |
| 37 } | 37 } |
| 38 | 38 |
| 39 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { | 39 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { |
| 40 if (!storageProvider_) |
| 41 return NULL; |
| 40 CGLContextObj context = NULL; | 42 CGLContextObj context = NULL; |
| 41 CGLError error = CGLCreateContext(pixelFormat, shareContext_, &context); | 43 CGLError error = CGLCreateContext( |
| 44 pixelFormat, storageProvider_->LayerShareGroupContext(), &context); |
| 42 if (error != kCGLNoError) | 45 if (error != kCGLNoError) |
| 43 DLOG(ERROR) << "CGLCreateContext failed with CGL error: " << error; | 46 DLOG(ERROR) << "CGLCreateContext failed with CGL error: " << error; |
| 44 return context; | 47 return context; |
| 45 } | 48 } |
| 46 | 49 |
| 47 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext | 50 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext |
| 48 pixelFormat:(CGLPixelFormatObj)pixelFormat | 51 pixelFormat:(CGLPixelFormatObj)pixelFormat |
| 49 forLayerTime:(CFTimeInterval)timeInterval | 52 forLayerTime:(CFTimeInterval)timeInterval |
| 50 displayTime:(const CVTimeStamp*)timeStamp { | 53 displayTime:(const CVTimeStamp*)timeStamp { |
| 51 return YES; | 54 if (!storageProvider_) |
| 55 return NO; |
| 56 return storageProvider_->LayerCanDraw(); |
| 52 } | 57 } |
| 53 | 58 |
| 54 - (void)drawInCGLContext:(CGLContextObj)glContext | 59 - (void)drawInCGLContext:(CGLContextObj)glContext |
| 55 pixelFormat:(CGLPixelFormatObj)pixelFormat | 60 pixelFormat:(CGLPixelFormatObj)pixelFormat |
| 56 forLayerTime:(CFTimeInterval)timeInterval | 61 forLayerTime:(CFTimeInterval)timeInterval |
| 57 displayTime:(const CVTimeStamp*)timeStamp { | 62 displayTime:(const CVTimeStamp*)timeStamp { |
| 58 glClearColor(1, 0, 1, 1); | 63 if (storageProvider_) { |
| 59 glClear(GL_COLOR_BUFFER_BIT); | 64 storageProvider_->LayerDoDraw(); |
| 60 | 65 } else { |
| 61 GLint viewport[4] = {0, 0, 0, 0}; | 66 glClearColor(1, 1, 1, 1); |
| 62 glGetIntegerv(GL_VIEWPORT, viewport); | 67 glClear(GL_COLOR_BUFFER_BIT); |
| 63 gfx::Size viewportSize(viewport[2], viewport[3]); | |
| 64 | |
| 65 // Set the coordinate system to be one-to-one with pixels. | |
| 66 glMatrixMode(GL_PROJECTION); | |
| 67 glLoadIdentity(); | |
| 68 glOrtho(0, viewportSize.width(), 0, viewportSize.height(), -1, 1); | |
| 69 glMatrixMode(GL_MODELVIEW); | |
| 70 glLoadIdentity(); | |
| 71 | |
| 72 // Draw a fullscreen quad. | |
| 73 glColor4f(1, 1, 1, 1); | |
| 74 glEnable(GL_TEXTURE_RECTANGLE_ARB); | |
| 75 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_); | |
| 76 glBegin(GL_QUADS); | |
| 77 { | |
| 78 glTexCoord2f(0, 0); | |
| 79 glVertex2f(0, 0); | |
| 80 | |
| 81 glTexCoord2f(0, pixelSize_.height()); | |
| 82 glVertex2f(0, pixelSize_.height()); | |
| 83 | |
| 84 glTexCoord2f(pixelSize_.width(), pixelSize_.height()); | |
| 85 glVertex2f(pixelSize_.width(), pixelSize_.height()); | |
| 86 | |
| 87 glTexCoord2f(pixelSize_.width(), 0); | |
| 88 glVertex2f(pixelSize_.width(), 0); | |
| 89 } | 68 } |
| 90 glEnd(); | |
| 91 glBindTexture(0, texture_); | |
| 92 glDisable(GL_TEXTURE_RECTANGLE_ARB); | |
| 93 | |
| 94 [super drawInCGLContext:glContext | 69 [super drawInCGLContext:glContext |
| 95 pixelFormat:pixelFormat | 70 pixelFormat:pixelFormat |
| 96 forLayerTime:timeInterval | 71 forLayerTime:timeInterval |
| 97 displayTime:timeStamp]; | 72 displayTime:timeStamp]; |
| 98 } | 73 } |
| 99 | 74 |
| 100 @end | 75 @end |
| 101 | 76 |
| 102 namespace content { | 77 namespace content { |
| 103 | 78 |
| 104 CALayerStorageProvider::CALayerStorageProvider() { | 79 CALayerStorageProvider::CALayerStorageProvider( |
| 80 ImageTransportSurfaceFBO* transport_surface) |
| 81 : transport_surface_(transport_surface), |
| 82 has_pending_draw_(false), |
| 83 can_draw_returned_false_count_(0), |
| 84 fbo_texture_(0) { |
| 85 // Allocate a CAContext to use to transport the CALayer to the browser |
| 86 // process. |
| 105 base::scoped_nsobject<NSDictionary> dict([[NSDictionary alloc] init]); | 87 base::scoped_nsobject<NSDictionary> dict([[NSDictionary alloc] init]); |
| 106 CGSConnectionID connection_id = CGSMainConnectionID(); | 88 CGSConnectionID connection_id = CGSMainConnectionID(); |
| 107 context_.reset([CAContext contextWithCGSConnection:connection_id | 89 context_.reset([CAContext contextWithCGSConnection:connection_id |
| 108 options:dict]); | 90 options:dict]); |
| 109 [context_ retain]; | 91 [context_ retain]; |
| 110 } | 92 } |
| 111 | 93 |
| 112 CALayerStorageProvider::~CALayerStorageProvider() { | 94 CALayerStorageProvider::~CALayerStorageProvider() { |
| 113 } | 95 } |
| 114 | 96 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 137 error = glGetError(); | 119 error = glGetError(); |
| 138 if (error != GL_NO_ERROR) { | 120 if (error != GL_NO_ERROR) { |
| 139 DLOG(ERROR) << "glTexImage failed with GL error: " << error; | 121 DLOG(ERROR) << "glTexImage failed with GL error: " << error; |
| 140 return false; | 122 return false; |
| 141 } | 123 } |
| 142 glFlush(); | 124 glFlush(); |
| 143 | 125 |
| 144 // Disable the fade-in animation as the layer is changed. | 126 // Disable the fade-in animation as the layer is changed. |
| 145 ScopedCAActionDisabler disabler; | 127 ScopedCAActionDisabler disabler; |
| 146 | 128 |
| 147 // Resize the CAOpenGLLayer to match the size needed, and change it to be the | 129 // Allocate a CALayer to draw texture into. |
| 148 // hosted layer. | 130 share_group_context_.reset(CGLRetainContext(context)); |
| 149 layer_.reset([[ImageTransportLayer alloc] initWithContext:context | 131 fbo_texture_ = texture; |
| 150 withTexture:texture | 132 fbo_pixel_size_ = pixel_size; |
| 151 withPixelSize:pixel_size | 133 layer_.reset([[ImageTransportLayer alloc] initWithStorageProvider:this]); |
| 152 withScaleFactor:scale_factor]); | 134 gfx::Size dip_size(gfx::ToFlooredSize(gfx::ScaleSize( |
| 135 fbo_pixel_size_, 1.0f / scale_factor))); |
| 136 [layer_ setContentsScale:scale_factor]; |
| 137 [layer_ setFrame:CGRectMake(0, 0, dip_size.width(), dip_size.height())]; |
| 153 return true; | 138 return true; |
| 154 } | 139 } |
| 155 | 140 |
| 156 void CALayerStorageProvider::FreeColorBufferStorage() { | 141 void CALayerStorageProvider::FreeColorBufferStorage() { |
| 157 [context_ setLayer:nil]; | 142 // We shouldn't be asked to free a texture when we still have yet to draw it. |
| 143 DCHECK(!has_pending_draw_); |
| 144 has_pending_draw_ = false; |
| 145 can_draw_returned_false_count_ = 0; |
| 146 |
| 147 // Note that |context_| still holds a reference to |layer_|, and will until |
| 148 // a new frame is swapped in. |
| 149 [layer_ displayIfNeeded]; |
| 150 [layer_ resetStorageProvider]; |
| 158 layer_.reset(); | 151 layer_.reset(); |
| 152 |
| 153 share_group_context_.reset(); |
| 154 fbo_texture_ = 0; |
| 155 fbo_pixel_size_ = gfx::Size(); |
| 159 } | 156 } |
| 160 | 157 |
| 161 uint64 CALayerStorageProvider::GetSurfaceHandle() const { | 158 uint64 CALayerStorageProvider::GetSurfaceHandle() const { |
| 162 return SurfaceHandleFromCAContextID([context_ contextId]); | 159 return SurfaceHandleFromCAContextID([context_ contextId]); |
| 163 } | 160 } |
| 164 | 161 |
| 165 void CALayerStorageProvider::WillSwapBuffers() { | 162 void CALayerStorageProvider::WillSwapBuffers() { |
| 163 DCHECK(!has_pending_draw_); |
| 164 has_pending_draw_ = true; |
| 165 |
| 166 // Don't add the layer to the CAContext until a SwapBuffers is going to be | 166 // Don't add the layer to the CAContext until a SwapBuffers is going to be |
| 167 // called, because the texture does not have any content until the | 167 // called, because the texture does not have any content until the |
| 168 // SwapBuffers call is about to be made. | 168 // SwapBuffers call is about to be made. |
| 169 if ([context_ layer] != layer_.get()) | 169 if ([context_ layer] != layer_.get()) |
| 170 [context_ setLayer:layer_]; | 170 [context_ setLayer:layer_]; |
| 171 | 171 |
| 172 // TODO(ccameron): Use the isAsynchronous property to ensure smooth | 172 if (![layer_ isAsynchronous]) |
| 173 // animation. | 173 [layer_ setAsynchronous:YES]; |
| 174 [layer_ setNeedsDisplay]; | 174 } |
| 175 |
| 176 void CALayerStorageProvider::CanFreeSwappedBuffer() { |
| 177 } |
| 178 |
| 179 CGLContextObj CALayerStorageProvider::LayerShareGroupContext() { |
| 180 return share_group_context_; |
| 181 } |
| 182 |
| 183 bool CALayerStorageProvider::LayerCanDraw() { |
| 184 if (has_pending_draw_) { |
| 185 can_draw_returned_false_count_ = 0; |
| 186 return true; |
| 187 } else { |
| 188 if (can_draw_returned_false_count_ == 30) { |
| 189 if ([layer_ isAsynchronous]) |
| 190 [layer_ setAsynchronous:NO]; |
| 191 } else { |
| 192 can_draw_returned_false_count_ += 1; |
| 193 } |
| 194 return false; |
| 195 } |
| 196 } |
| 197 |
| 198 void CALayerStorageProvider::LayerDoDraw() { |
| 199 DCHECK(has_pending_draw_); |
| 200 has_pending_draw_ = false; |
| 201 |
| 202 GLint viewport[4] = {0, 0, 0, 0}; |
| 203 glGetIntegerv(GL_VIEWPORT, viewport); |
| 204 gfx::Size viewport_size(viewport[2], viewport[3]); |
| 205 |
| 206 // Set the coordinate system to be one-to-one with pixels. |
| 207 glMatrixMode(GL_PROJECTION); |
| 208 glLoadIdentity(); |
| 209 glOrtho(0, viewport_size.width(), 0, viewport_size.height(), -1, 1); |
| 210 glMatrixMode(GL_MODELVIEW); |
| 211 glLoadIdentity(); |
| 212 |
| 213 // Draw a fullscreen quad. |
| 214 glColor4f(1, 1, 1, 1); |
| 215 glEnable(GL_TEXTURE_RECTANGLE_ARB); |
| 216 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_texture_); |
| 217 glBegin(GL_QUADS); |
| 218 { |
| 219 glTexCoord2f(0, 0); |
| 220 glVertex2f(0, 0); |
| 221 |
| 222 glTexCoord2f(0, fbo_pixel_size_.height()); |
| 223 glVertex2f(0, fbo_pixel_size_.height()); |
| 224 |
| 225 glTexCoord2f(fbo_pixel_size_.width(), fbo_pixel_size_.height()); |
| 226 glVertex2f(fbo_pixel_size_.width(), fbo_pixel_size_.height()); |
| 227 |
| 228 glTexCoord2f(fbo_pixel_size_.width(), 0); |
| 229 glVertex2f(fbo_pixel_size_.width(), 0); |
| 230 } |
| 231 glEnd(); |
| 232 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); |
| 233 glDisable(GL_TEXTURE_RECTANGLE_ARB); |
| 234 |
| 235 // Allow forward progress in the context now that the swap is complete. |
| 236 transport_surface_->UnblockContextAfterPendingSwap(); |
| 175 } | 237 } |
| 176 | 238 |
| 177 } // namespace content | 239 } // namespace content |
| OLD | NEW |