| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.h" | 5 #include "content/common/gpu/image_transport_surface_fbo_mac.h" |
| 6 | 6 |
| 7 #include "base/mac/scoped_cftyperef.h" | |
| 8 #include "base/memory/scoped_ptr.h" | |
| 9 #include "content/common/gpu/gpu_command_buffer_stub.h" | |
| 10 #include "content/common/gpu/gpu_messages.h" | 7 #include "content/common/gpu/gpu_messages.h" |
| 8 #include "content/common/gpu/image_transport_surface_iosurface_mac.h" |
| 11 #include "ui/gfx/native_widget_types.h" | 9 #include "ui/gfx/native_widget_types.h" |
| 12 #include "ui/gl/gl_bindings.h" | |
| 13 #include "ui/gl/gl_context.h" | 10 #include "ui/gl/gl_context.h" |
| 14 #include "ui/gl/gl_implementation.h" | 11 #include "ui/gl/gl_implementation.h" |
| 15 #include "ui/gl/gl_surface_cgl.h" | |
| 16 #include "ui/gl/gl_surface_osmesa.h" | 12 #include "ui/gl/gl_surface_osmesa.h" |
| 17 | 13 |
| 18 // Note that this must be included after gl_bindings.h to avoid conflicts. | 14 namespace content { |
| 19 #include <OpenGL/CGLIOSurface.h> | |
| 20 | 15 |
| 21 namespace content { | 16 ImageTransportSurfaceFBO::ImageTransportSurfaceFBO( |
| 22 namespace { | 17 StorageProvider* storage_provider, |
| 23 | |
| 24 // IOSurface dimensions will be rounded up to a multiple of this value in order | |
| 25 // to reduce memory thrashing during resize. This must be a power of 2. | |
| 26 const uint32 kIOSurfaceDimensionRoundup = 64; | |
| 27 | |
| 28 int RoundUpSurfaceDimension(int number) { | |
| 29 DCHECK(number >= 0); | |
| 30 // Cast into unsigned space for portable bitwise ops. | |
| 31 uint32 unsigned_number = static_cast<uint32>(number); | |
| 32 uint32 roundup_sub_1 = kIOSurfaceDimensionRoundup - 1; | |
| 33 unsigned_number = (unsigned_number + roundup_sub_1) & ~roundup_sub_1; | |
| 34 return static_cast<int>(unsigned_number); | |
| 35 } | |
| 36 | |
| 37 // We are backed by an offscreen surface for the purposes of creating | |
| 38 // a context, but use FBOs to render to texture backed IOSurface | |
| 39 class IOSurfaceImageTransportSurface | |
| 40 : public gfx::NoOpGLSurfaceCGL, | |
| 41 public ImageTransportSurface, | |
| 42 public GpuCommandBufferStub::DestructionObserver { | |
| 43 public: | |
| 44 IOSurfaceImageTransportSurface(GpuChannelManager* manager, | |
| 45 GpuCommandBufferStub* stub, | |
| 46 gfx::PluginWindowHandle handle); | |
| 47 | |
| 48 // GLSurface implementation | |
| 49 virtual bool Initialize() OVERRIDE; | |
| 50 virtual void Destroy() OVERRIDE; | |
| 51 virtual bool DeferDraws() OVERRIDE; | |
| 52 virtual bool IsOffscreen() OVERRIDE; | |
| 53 virtual bool SwapBuffers() OVERRIDE; | |
| 54 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; | |
| 55 virtual bool SupportsPostSubBuffer() OVERRIDE; | |
| 56 virtual gfx::Size GetSize() OVERRIDE; | |
| 57 virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE; | |
| 58 virtual unsigned int GetBackingFrameBufferObject() OVERRIDE; | |
| 59 virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE; | |
| 60 virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE; | |
| 61 | |
| 62 protected: | |
| 63 // ImageTransportSurface implementation | |
| 64 virtual void OnBufferPresented( | |
| 65 const AcceleratedSurfaceMsg_BufferPresented_Params& params) OVERRIDE; | |
| 66 virtual void OnResize(gfx::Size size, float scale_factor) OVERRIDE; | |
| 67 virtual void SetLatencyInfo( | |
| 68 const std::vector<ui::LatencyInfo>&) OVERRIDE; | |
| 69 virtual void WakeUpGpu() OVERRIDE; | |
| 70 | |
| 71 // GpuCommandBufferStub::DestructionObserver implementation. | |
| 72 virtual void OnWillDestroyStub() OVERRIDE; | |
| 73 | |
| 74 private: | |
| 75 virtual ~IOSurfaceImageTransportSurface() OVERRIDE; | |
| 76 | |
| 77 void AdjustBufferAllocation(); | |
| 78 void UnrefIOSurface(); | |
| 79 void CreateIOSurface(); | |
| 80 | |
| 81 // Tracks the current buffer allocation state. | |
| 82 bool backbuffer_suggested_allocation_; | |
| 83 bool frontbuffer_suggested_allocation_; | |
| 84 | |
| 85 uint32 fbo_id_; | |
| 86 GLuint texture_id_; | |
| 87 GLuint depth_stencil_renderbuffer_id_; | |
| 88 | |
| 89 base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; | |
| 90 | |
| 91 // The id of |io_surface_| or 0 if that's NULL. | |
| 92 uint64 io_surface_handle_; | |
| 93 | |
| 94 // Weak pointer to the context that this was last made current to. | |
| 95 gfx::GLContext* context_; | |
| 96 | |
| 97 gfx::Size size_; | |
| 98 gfx::Size rounded_size_; | |
| 99 float scale_factor_; | |
| 100 | |
| 101 // Whether or not we've successfully made the surface current once. | |
| 102 bool made_current_; | |
| 103 | |
| 104 // Whether a SwapBuffers is pending. | |
| 105 bool is_swap_buffers_pending_; | |
| 106 | |
| 107 // Whether we unscheduled command buffer because of pending SwapBuffers. | |
| 108 bool did_unschedule_; | |
| 109 | |
| 110 std::vector<ui::LatencyInfo> latency_info_; | |
| 111 | |
| 112 scoped_ptr<ImageTransportHelper> helper_; | |
| 113 | |
| 114 DISALLOW_COPY_AND_ASSIGN(IOSurfaceImageTransportSurface); | |
| 115 }; | |
| 116 | |
| 117 void AddBooleanValue(CFMutableDictionaryRef dictionary, | |
| 118 const CFStringRef key, | |
| 119 bool value) { | |
| 120 CFDictionaryAddValue(dictionary, key, | |
| 121 (value ? kCFBooleanTrue : kCFBooleanFalse)); | |
| 122 } | |
| 123 | |
| 124 void AddIntegerValue(CFMutableDictionaryRef dictionary, | |
| 125 const CFStringRef key, | |
| 126 int32 value) { | |
| 127 base::ScopedCFTypeRef<CFNumberRef> number( | |
| 128 CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); | |
| 129 CFDictionaryAddValue(dictionary, key, number.get()); | |
| 130 } | |
| 131 | |
| 132 IOSurfaceImageTransportSurface::IOSurfaceImageTransportSurface( | |
| 133 GpuChannelManager* manager, | 18 GpuChannelManager* manager, |
| 134 GpuCommandBufferStub* stub, | 19 GpuCommandBufferStub* stub, |
| 135 gfx::PluginWindowHandle handle) | 20 gfx::PluginWindowHandle handle) |
| 136 : gfx::NoOpGLSurfaceCGL(gfx::Size(1, 1)), | 21 : storage_provider_(storage_provider), |
| 137 backbuffer_suggested_allocation_(true), | 22 backbuffer_suggested_allocation_(true), |
| 138 frontbuffer_suggested_allocation_(true), | 23 frontbuffer_suggested_allocation_(true), |
| 139 fbo_id_(0), | 24 fbo_id_(0), |
| 140 texture_id_(0), | 25 texture_id_(0), |
| 141 depth_stencil_renderbuffer_id_(0), | 26 depth_stencil_renderbuffer_id_(0), |
| 142 io_surface_handle_(0), | 27 has_complete_framebuffer_(false), |
| 143 context_(NULL), | 28 context_(NULL), |
| 144 scale_factor_(1.f), | 29 scale_factor_(1.f), |
| 145 made_current_(false), | 30 made_current_(false), |
| 146 is_swap_buffers_pending_(false), | 31 is_swap_buffers_pending_(false), |
| 147 did_unschedule_(false) { | 32 did_unschedule_(false) { |
| 148 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); | 33 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); |
| 149 } | 34 } |
| 150 | 35 |
| 151 IOSurfaceImageTransportSurface::~IOSurfaceImageTransportSurface() { | 36 ImageTransportSurfaceFBO::~ImageTransportSurfaceFBO() { |
| 152 } | 37 } |
| 153 | 38 |
| 154 bool IOSurfaceImageTransportSurface::Initialize() { | 39 bool ImageTransportSurfaceFBO::Initialize() { |
| 155 // Only support IOSurfaces if the GL implementation is the native desktop GL. | 40 // Only support IOSurfaces if the GL implementation is the native desktop GL. |
| 156 // IO surfaces will not work with, for example, OSMesa software renderer | 41 // IO surfaces will not work with, for example, OSMesa software renderer |
| 157 // GL contexts. | 42 // GL contexts. |
| 158 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL && | 43 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL && |
| 159 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL) | 44 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL) |
| 160 return false; | 45 return false; |
| 161 | 46 |
| 162 if (!helper_->Initialize()) | 47 if (!helper_->Initialize()) |
| 163 return false; | 48 return false; |
| 164 | 49 |
| 165 if (!NoOpGLSurfaceCGL::Initialize()) { | |
| 166 helper_->Destroy(); | |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 helper_->stub()->AddDestructionObserver(this); | 50 helper_->stub()->AddDestructionObserver(this); |
| 171 return true; | 51 return true; |
| 172 } | 52 } |
| 173 | 53 |
| 174 void IOSurfaceImageTransportSurface::Destroy() { | 54 void ImageTransportSurfaceFBO::Destroy() { |
| 175 UnrefIOSurface(); | 55 DestroyFramebuffer(); |
| 176 | 56 |
| 177 helper_->Destroy(); | 57 helper_->Destroy(); |
| 178 NoOpGLSurfaceCGL::Destroy(); | |
| 179 } | 58 } |
| 180 | 59 |
| 181 bool IOSurfaceImageTransportSurface::DeferDraws() { | 60 bool ImageTransportSurfaceFBO::DeferDraws() { |
| 182 // The command buffer hit a draw/clear command that could clobber the | 61 // The command buffer hit a draw/clear command that could clobber the |
| 183 // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort | 62 // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort |
| 184 // processing of the command by returning true and unschedule until the Swap | 63 // processing of the command by returning true and unschedule until the Swap |
| 185 // Ack arrives. | 64 // Ack arrives. |
| 186 if(did_unschedule_) | 65 if(did_unschedule_) |
| 187 return true; // Still unscheduled, so just return true. | 66 return true; // Still unscheduled, so just return true. |
| 188 if (is_swap_buffers_pending_) { | 67 if (is_swap_buffers_pending_) { |
| 189 did_unschedule_ = true; | 68 did_unschedule_ = true; |
| 190 helper_->SetScheduled(false); | 69 helper_->SetScheduled(false); |
| 191 return true; | 70 return true; |
| 192 } | 71 } |
| 193 return false; | 72 return false; |
| 194 } | 73 } |
| 195 | 74 |
| 196 bool IOSurfaceImageTransportSurface::IsOffscreen() { | 75 bool ImageTransportSurfaceFBO::IsOffscreen() { |
| 197 return false; | 76 return false; |
| 198 } | 77 } |
| 199 | 78 |
| 200 bool IOSurfaceImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { | 79 bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) { |
| 201 context_ = context; | 80 context_ = context; |
| 202 | 81 |
| 203 if (made_current_) | 82 if (made_current_) |
| 204 return true; | 83 return true; |
| 205 | 84 |
| 206 OnResize(gfx::Size(1, 1), 1.f); | 85 OnResize(gfx::Size(1, 1), 1.f); |
| 207 | 86 |
| 208 made_current_ = true; | 87 made_current_ = true; |
| 209 return true; | 88 return true; |
| 210 } | 89 } |
| 211 | 90 |
| 212 unsigned int IOSurfaceImageTransportSurface::GetBackingFrameBufferObject() { | 91 unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() { |
| 213 return fbo_id_; | 92 return fbo_id_; |
| 214 } | 93 } |
| 215 | 94 |
| 216 bool IOSurfaceImageTransportSurface::SetBackbufferAllocation(bool allocation) { | 95 bool ImageTransportSurfaceFBO::SetBackbufferAllocation(bool allocation) { |
| 217 if (backbuffer_suggested_allocation_ == allocation) | 96 if (backbuffer_suggested_allocation_ == allocation) |
| 218 return true; | 97 return true; |
| 219 backbuffer_suggested_allocation_ = allocation; | 98 backbuffer_suggested_allocation_ = allocation; |
| 220 AdjustBufferAllocation(); | 99 AdjustBufferAllocation(); |
| 221 return true; | 100 return true; |
| 222 } | 101 } |
| 223 | 102 |
| 224 void IOSurfaceImageTransportSurface::SetFrontbufferAllocation(bool allocation) { | 103 void ImageTransportSurfaceFBO::SetFrontbufferAllocation(bool allocation) { |
| 225 if (frontbuffer_suggested_allocation_ == allocation) | 104 if (frontbuffer_suggested_allocation_ == allocation) |
| 226 return; | 105 return; |
| 227 frontbuffer_suggested_allocation_ = allocation; | 106 frontbuffer_suggested_allocation_ = allocation; |
| 228 AdjustBufferAllocation(); | 107 AdjustBufferAllocation(); |
| 229 } | 108 } |
| 230 | 109 |
| 231 void IOSurfaceImageTransportSurface::AdjustBufferAllocation() { | 110 void ImageTransportSurfaceFBO::AdjustBufferAllocation() { |
| 232 // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is | 111 // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is |
| 233 // free'd when both the browser and gpu processes have Unref'd the IOSurface. | 112 // free'd when both the browser and gpu processes have Unref'd the IOSurface. |
| 234 if (!backbuffer_suggested_allocation_ && | 113 if (!backbuffer_suggested_allocation_ && |
| 235 !frontbuffer_suggested_allocation_ && | 114 !frontbuffer_suggested_allocation_ && |
| 236 io_surface_.get()) { | 115 has_complete_framebuffer_) { |
| 237 UnrefIOSurface(); | 116 DestroyFramebuffer(); |
| 238 helper_->Suspend(); | 117 helper_->Suspend(); |
| 239 } else if (backbuffer_suggested_allocation_ && !io_surface_) { | 118 } else if (backbuffer_suggested_allocation_ && !has_complete_framebuffer_) { |
| 240 CreateIOSurface(); | 119 CreateFramebuffer(); |
| 241 } | 120 } |
| 242 } | 121 } |
| 243 | 122 |
| 244 bool IOSurfaceImageTransportSurface::SwapBuffers() { | 123 bool ImageTransportSurfaceFBO::SwapBuffers() { |
| 245 DCHECK(backbuffer_suggested_allocation_); | 124 DCHECK(backbuffer_suggested_allocation_); |
| 246 if (!frontbuffer_suggested_allocation_) | 125 if (!frontbuffer_suggested_allocation_) |
| 247 return true; | 126 return true; |
| 248 glFlush(); | 127 glFlush(); |
| 249 | 128 |
| 250 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | 129 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; |
| 251 params.surface_handle = io_surface_handle_; | 130 params.surface_handle = storage_provider_->GetSurfaceHandle(); |
| 252 params.size = GetSize(); | 131 params.size = GetSize(); |
| 253 params.scale_factor = scale_factor_; | 132 params.scale_factor = scale_factor_; |
| 254 params.latency_info.swap(latency_info_); | 133 params.latency_info.swap(latency_info_); |
| 255 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | 134 helper_->SendAcceleratedSurfaceBuffersSwapped(params); |
| 256 | 135 |
| 257 DCHECK(!is_swap_buffers_pending_); | 136 DCHECK(!is_swap_buffers_pending_); |
| 258 is_swap_buffers_pending_ = true; | 137 is_swap_buffers_pending_ = true; |
| 259 return true; | 138 return true; |
| 260 } | 139 } |
| 261 | 140 |
| 262 bool IOSurfaceImageTransportSurface::PostSubBuffer( | 141 bool ImageTransportSurfaceFBO::PostSubBuffer( |
| 263 int x, int y, int width, int height) { | 142 int x, int y, int width, int height) { |
| 264 DCHECK(backbuffer_suggested_allocation_); | 143 DCHECK(backbuffer_suggested_allocation_); |
| 265 if (!frontbuffer_suggested_allocation_) | 144 if (!frontbuffer_suggested_allocation_) |
| 266 return true; | 145 return true; |
| 267 glFlush(); | 146 glFlush(); |
| 268 | 147 |
| 269 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | 148 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; |
| 270 params.surface_handle = io_surface_handle_; | 149 params.surface_handle = storage_provider_->GetSurfaceHandle(); |
| 271 params.x = x; | 150 params.x = x; |
| 272 params.y = y; | 151 params.y = y; |
| 273 params.width = width; | 152 params.width = width; |
| 274 params.height = height; | 153 params.height = height; |
| 275 params.surface_size = GetSize(); | 154 params.surface_size = GetSize(); |
| 276 params.surface_scale_factor = scale_factor_; | 155 params.surface_scale_factor = scale_factor_; |
| 277 params.latency_info.swap(latency_info_); | 156 params.latency_info.swap(latency_info_); |
| 278 helper_->SendAcceleratedSurfacePostSubBuffer(params); | 157 helper_->SendAcceleratedSurfacePostSubBuffer(params); |
| 279 | 158 |
| 280 DCHECK(!is_swap_buffers_pending_); | 159 DCHECK(!is_swap_buffers_pending_); |
| 281 is_swap_buffers_pending_ = true; | 160 is_swap_buffers_pending_ = true; |
| 282 return true; | 161 return true; |
| 283 } | 162 } |
| 284 | 163 |
| 285 bool IOSurfaceImageTransportSurface::SupportsPostSubBuffer() { | 164 bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() { |
| 286 return true; | 165 return true; |
| 287 } | 166 } |
| 288 | 167 |
| 289 gfx::Size IOSurfaceImageTransportSurface::GetSize() { | 168 gfx::Size ImageTransportSurfaceFBO::GetSize() { |
| 290 return size_; | 169 return size_; |
| 291 } | 170 } |
| 292 | 171 |
| 293 void IOSurfaceImageTransportSurface::OnBufferPresented( | 172 void* ImageTransportSurfaceFBO::GetHandle() { |
| 173 return NULL; |
| 174 } |
| 175 |
| 176 void* ImageTransportSurfaceFBO::GetDisplay() { |
| 177 return NULL; |
| 178 } |
| 179 |
| 180 void ImageTransportSurfaceFBO::OnBufferPresented( |
| 294 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { | 181 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { |
| 295 DCHECK(is_swap_buffers_pending_); | 182 DCHECK(is_swap_buffers_pending_); |
| 296 | 183 |
| 297 context_->share_group()->SetRendererID(params.renderer_id); | 184 context_->share_group()->SetRendererID(params.renderer_id); |
| 298 is_swap_buffers_pending_ = false; | 185 is_swap_buffers_pending_ = false; |
| 299 if (did_unschedule_) { | 186 if (did_unschedule_) { |
| 300 did_unschedule_ = false; | 187 did_unschedule_ = false; |
| 301 helper_->SetScheduled(true); | 188 helper_->SetScheduled(true); |
| 302 } | 189 } |
| 303 } | 190 } |
| 304 | 191 |
| 305 void IOSurfaceImageTransportSurface::OnResize(gfx::Size size, | 192 void ImageTransportSurfaceFBO::OnResize(gfx::Size size, |
| 306 float scale_factor) { | 193 float scale_factor) { |
| 307 // This trace event is used in gpu_feature_browsertest.cc - the test will need | 194 // This trace event is used in gpu_feature_browsertest.cc - the test will need |
| 308 // to be updated if this event is changed or moved. | 195 // to be updated if this event is changed or moved. |
| 309 TRACE_EVENT2("gpu", "IOSurfaceImageTransportSurface::OnResize", | 196 TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::OnResize", |
| 310 "old_width", size_.width(), "new_width", size.width()); | 197 "old_width", size_.width(), "new_width", size.width()); |
| 311 // Caching |context_| from OnMakeCurrent. It should still be current. | 198 // Caching |context_| from OnMakeCurrent. It should still be current. |
| 312 DCHECK(context_->IsCurrent(this)); | 199 DCHECK(context_->IsCurrent(this)); |
| 313 | 200 |
| 314 size_ = size; | 201 size_ = size; |
| 315 scale_factor_ = scale_factor; | 202 scale_factor_ = scale_factor; |
| 316 | 203 |
| 317 CreateIOSurface(); | 204 CreateFramebuffer(); |
| 318 } | 205 } |
| 319 | 206 |
| 320 void IOSurfaceImageTransportSurface::SetLatencyInfo( | 207 void ImageTransportSurfaceFBO::SetLatencyInfo( |
| 321 const std::vector<ui::LatencyInfo>& latency_info) { | 208 const std::vector<ui::LatencyInfo>& latency_info) { |
| 322 for (size_t i = 0; i < latency_info.size(); i++) | 209 for (size_t i = 0; i < latency_info.size(); i++) |
| 323 latency_info_.push_back(latency_info[i]); | 210 latency_info_.push_back(latency_info[i]); |
| 324 } | 211 } |
| 325 | 212 |
| 326 void IOSurfaceImageTransportSurface::WakeUpGpu() { | 213 void ImageTransportSurfaceFBO::WakeUpGpu() { |
| 327 NOTIMPLEMENTED(); | 214 NOTIMPLEMENTED(); |
| 328 } | 215 } |
| 329 | 216 |
| 330 void IOSurfaceImageTransportSurface::OnWillDestroyStub() { | 217 void ImageTransportSurfaceFBO::OnWillDestroyStub() { |
| 331 helper_->stub()->RemoveDestructionObserver(this); | 218 helper_->stub()->RemoveDestructionObserver(this); |
| 332 Destroy(); | 219 Destroy(); |
| 333 } | 220 } |
| 334 | 221 |
| 335 void IOSurfaceImageTransportSurface::UnrefIOSurface() { | 222 void ImageTransportSurfaceFBO::DestroyFramebuffer() { |
| 336 // If we have resources to destroy, then make sure that we have a current | 223 // If we have resources to destroy, then make sure that we have a current |
| 337 // context which we can use to delete the resources. | 224 // context which we can use to delete the resources. |
| 338 if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) { | 225 if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) { |
| 339 DCHECK(gfx::GLContext::GetCurrent() == context_); | 226 DCHECK(gfx::GLContext::GetCurrent() == context_); |
| 340 DCHECK(context_->IsCurrent(this)); | 227 DCHECK(context_->IsCurrent(this)); |
| 341 DCHECK(CGLGetCurrentContext()); | 228 DCHECK(CGLGetCurrentContext()); |
| 342 } | 229 } |
| 343 | 230 |
| 344 if (fbo_id_) { | 231 if (fbo_id_) { |
| 345 glDeleteFramebuffersEXT(1, &fbo_id_); | 232 glDeleteFramebuffersEXT(1, &fbo_id_); |
| 346 fbo_id_ = 0; | 233 fbo_id_ = 0; |
| 347 } | 234 } |
| 348 | 235 |
| 349 if (texture_id_) { | 236 if (texture_id_) { |
| 350 glDeleteTextures(1, &texture_id_); | 237 glDeleteTextures(1, &texture_id_); |
| 351 texture_id_ = 0; | 238 texture_id_ = 0; |
| 352 } | 239 } |
| 353 | 240 |
| 354 if (depth_stencil_renderbuffer_id_) { | 241 if (depth_stencil_renderbuffer_id_) { |
| 355 glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_); | 242 glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_); |
| 356 depth_stencil_renderbuffer_id_ = 0; | 243 depth_stencil_renderbuffer_id_ = 0; |
| 357 } | 244 } |
| 358 | 245 |
| 359 io_surface_.reset(); | 246 storage_provider_->FreeColorBufferStorage(); |
| 360 io_surface_handle_ = 0; | 247 |
| 248 has_complete_framebuffer_ = false; |
| 361 } | 249 } |
| 362 | 250 |
| 363 void IOSurfaceImageTransportSurface::CreateIOSurface() { | 251 void ImageTransportSurfaceFBO::CreateFramebuffer() { |
| 364 gfx::Size new_rounded_size(RoundUpSurfaceDimension(size_.width()), | 252 gfx::Size new_rounded_size = storage_provider_->GetRoundedSize(size_); |
| 365 RoundUpSurfaceDimension(size_.height())); | |
| 366 | 253 |
| 367 // Only recreate surface when the rounded up size has changed. | 254 // Only recreate surface when the rounded up size has changed. |
| 368 if (io_surface_.get() && new_rounded_size == rounded_size_) | 255 if (has_complete_framebuffer_ && new_rounded_size == rounded_size_) |
| 369 return; | 256 return; |
| 370 | 257 |
| 371 // This trace event is used in gpu_feature_browsertest.cc - the test will need | 258 // This trace event is used in gpu_feature_browsertest.cc - the test will need |
| 372 // to be updated if this event is changed or moved. | 259 // to be updated if this event is changed or moved. |
| 373 TRACE_EVENT2("gpu", "IOSurfaceImageTransportSurface::CreateIOSurface", | 260 TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::CreateFramebuffer", |
| 374 "width", new_rounded_size.width(), | 261 "width", new_rounded_size.width(), |
| 375 "height", new_rounded_size.height()); | 262 "height", new_rounded_size.height()); |
| 376 | 263 |
| 377 rounded_size_ = new_rounded_size; | 264 rounded_size_ = new_rounded_size; |
| 378 | 265 |
| 266 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on |
| 267 // Mac OS X and is required for IOSurface interoperability. |
| 379 GLint previous_texture_id = 0; | 268 GLint previous_texture_id = 0; |
| 380 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id); | 269 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id); |
| 381 | 270 |
| 382 // Free the old IO Surface first to reduce memory fragmentation. | 271 // Free the old IO Surface first to reduce memory fragmentation. |
| 383 UnrefIOSurface(); | 272 DestroyFramebuffer(); |
| 384 | 273 |
| 385 glGenFramebuffersEXT(1, &fbo_id_); | 274 glGenFramebuffersEXT(1, &fbo_id_); |
| 386 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_); | 275 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_); |
| 387 | 276 |
| 388 glGenTextures(1, &texture_id_); | 277 glGenTextures(1, &texture_id_); |
| 389 | 278 |
| 390 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on | 279 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id_); |
| 391 // Mac OS X and is required for IOSurface interoperability. | 280 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 392 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | 281 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 393 glBindTexture(target, texture_id_); | 282 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
| 394 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 283 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 395 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 284 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
| 396 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 285 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 397 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 398 | 286 |
| 399 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, | 287 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, |
| 400 GL_COLOR_ATTACHMENT0_EXT, | 288 GL_COLOR_ATTACHMENT0_EXT, |
| 401 target, | 289 GL_TEXTURE_RECTANGLE_ARB, |
| 402 texture_id_, | 290 texture_id_, |
| 403 0); | 291 0); |
| 404 | 292 |
| 405 | |
| 406 // Search through the provided attributes; if the caller has | 293 // Search through the provided attributes; if the caller has |
| 407 // requested a stencil buffer, try to get one. | 294 // requested a stencil buffer, try to get one. |
| 408 | 295 |
| 409 int32 stencil_bits = | 296 int32 stencil_bits = |
| 410 helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE); | 297 helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE); |
| 411 if (stencil_bits > 0) { | 298 if (stencil_bits > 0) { |
| 412 // Create and bind the stencil buffer | 299 // Create and bind the stencil buffer |
| 413 bool has_packed_depth_stencil = | 300 bool has_packed_depth_stencil = |
| 414 GLSurface::ExtensionsContain( | 301 GLSurface::ExtensionsContain( |
| 415 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)), | 302 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 426 GL_RENDERBUFFER_EXT, | 313 GL_RENDERBUFFER_EXT, |
| 427 depth_stencil_renderbuffer_id_); | 314 depth_stencil_renderbuffer_id_); |
| 428 } | 315 } |
| 429 | 316 |
| 430 // If we asked for stencil but the extension isn't present, | 317 // If we asked for stencil but the extension isn't present, |
| 431 // it's OK to silently fail; subsequent code will/must check | 318 // it's OK to silently fail; subsequent code will/must check |
| 432 // for the presence of a stencil buffer before attempting to | 319 // for the presence of a stencil buffer before attempting to |
| 433 // do stencil-based operations. | 320 // do stencil-based operations. |
| 434 } | 321 } |
| 435 | 322 |
| 436 // Allocate a new IOSurface, which is the GPU resource that can be | 323 bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage( |
| 437 // shared across processes. | 324 static_cast<CGLContextObj>(context_->GetHandle()), |
| 438 base::ScopedCFTypeRef<CFMutableDictionaryRef> properties; | 325 rounded_size_); |
| 439 properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault, | 326 if (!allocated_color_buffer) { |
| 440 0, | 327 DLOG(ERROR) << "Failed to allocate color buffer storage."; |
| 441 &kCFTypeDictionaryKeyCallBacks, | 328 DestroyFramebuffer(); |
| 442 &kCFTypeDictionaryValueCallBacks)); | |
| 443 AddIntegerValue(properties, | |
| 444 kIOSurfaceWidth, | |
| 445 rounded_size_.width()); | |
| 446 AddIntegerValue(properties, | |
| 447 kIOSurfaceHeight, | |
| 448 rounded_size_.height()); | |
| 449 AddIntegerValue(properties, | |
| 450 kIOSurfaceBytesPerElement, 4); | |
| 451 AddBooleanValue(properties, | |
| 452 kIOSurfaceIsGlobal, true); | |
| 453 // I believe we should be able to unreference the IOSurfaces without | |
| 454 // synchronizing with the browser process because they are | |
| 455 // ultimately reference counted by the operating system. | |
| 456 io_surface_.reset(IOSurfaceCreate(properties)); | |
| 457 io_surface_handle_ = IOSurfaceGetID(io_surface_); | |
| 458 | |
| 459 // Don't think we need to identify a plane. | |
| 460 GLuint plane = 0; | |
| 461 CGLError cglerror = | |
| 462 CGLTexImageIOSurface2D( | |
| 463 static_cast<CGLContextObj>(context_->GetHandle()), | |
| 464 target, | |
| 465 GL_RGBA, | |
| 466 rounded_size_.width(), | |
| 467 rounded_size_.height(), | |
| 468 GL_BGRA, | |
| 469 GL_UNSIGNED_INT_8_8_8_8_REV, | |
| 470 io_surface_.get(), | |
| 471 plane); | |
| 472 if (cglerror != kCGLNoError) { | |
| 473 UnrefIOSurface(); | |
| 474 return; | 329 return; |
| 475 } | 330 } |
| 476 | 331 |
| 477 glFlush(); | |
| 478 | |
| 479 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); | 332 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); |
| 480 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { | 333 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
| 481 DLOG(ERROR) << "Framebuffer was incomplete: " << status; | 334 DLOG(ERROR) << "Framebuffer was incomplete: " << status; |
| 482 UnrefIOSurface(); | 335 DestroyFramebuffer(); |
| 483 return; | 336 return; |
| 484 } | 337 } |
| 485 | 338 |
| 486 glBindTexture(target, previous_texture_id); | 339 has_complete_framebuffer_ = true; |
| 340 |
| 341 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, previous_texture_id); |
| 487 // The FBO remains bound for this GL context. | 342 // The FBO remains bound for this GL context. |
| 488 } | 343 } |
| 489 | 344 |
| 490 // A subclass of GLSurfaceOSMesa that doesn't print an error message when | |
| 491 // SwapBuffers() is called. | |
| 492 class DRTSurfaceOSMesa : public gfx::GLSurfaceOSMesa { | |
| 493 public: | |
| 494 // Size doesn't matter, the surface is resized to the right size later. | |
| 495 DRTSurfaceOSMesa() : GLSurfaceOSMesa(GL_RGBA, gfx::Size(1, 1)) {} | |
| 496 | |
| 497 // Implement a subset of GLSurface. | |
| 498 virtual bool SwapBuffers() OVERRIDE; | |
| 499 | |
| 500 private: | |
| 501 virtual ~DRTSurfaceOSMesa() {} | |
| 502 DISALLOW_COPY_AND_ASSIGN(DRTSurfaceOSMesa); | |
| 503 }; | |
| 504 | |
| 505 bool DRTSurfaceOSMesa::SwapBuffers() { | |
| 506 return true; | |
| 507 } | |
| 508 | |
| 509 bool g_allow_os_mesa = false; | |
| 510 | |
| 511 } // namespace | |
| 512 | |
| 513 // static | |
| 514 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( | |
| 515 GpuChannelManager* manager, | |
| 516 GpuCommandBufferStub* stub, | |
| 517 const gfx::GLSurfaceHandle& surface_handle) { | |
| 518 DCHECK(surface_handle.transport_type == gfx::NATIVE_DIRECT || | |
| 519 surface_handle.transport_type == gfx::NATIVE_TRANSPORT); | |
| 520 | |
| 521 switch (gfx::GetGLImplementation()) { | |
| 522 case gfx::kGLImplementationDesktopGL: | |
| 523 case gfx::kGLImplementationAppleGL: | |
| 524 return scoped_refptr<gfx::GLSurface>(new IOSurfaceImageTransportSurface( | |
| 525 manager, stub, surface_handle.handle)); | |
| 526 | |
| 527 default: | |
| 528 // Content shell in DRT mode spins up a gpu process which needs an | |
| 529 // image transport surface, but that surface isn't used to read pixel | |
| 530 // baselines. So this is mostly a dummy surface. | |
| 531 if (!g_allow_os_mesa) { | |
| 532 NOTREACHED(); | |
| 533 return scoped_refptr<gfx::GLSurface>(); | |
| 534 } | |
| 535 scoped_refptr<gfx::GLSurface> surface(new DRTSurfaceOSMesa()); | |
| 536 if (!surface.get() || !surface->Initialize()) | |
| 537 return surface; | |
| 538 return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( | |
| 539 manager, stub, surface.get())); | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 // static | |
| 544 void ImageTransportSurface::SetAllowOSMesaForTesting(bool allow) { | |
| 545 g_allow_os_mesa = allow; | |
| 546 } | |
| 547 | |
| 548 } // namespace content | 345 } // namespace content |
| OLD | NEW |