| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/common/gpu/image_transport_surface.h" | |
| 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" | |
| 11 #include "ui/gfx/native_widget_types.h" | |
| 12 #include "ui/gl/gl_bindings.h" | |
| 13 #include "ui/gl/gl_context.h" | |
| 14 #include "ui/gl/gl_implementation.h" | |
| 15 #include "ui/gl/gl_surface_cgl.h" | |
| 16 #include "ui/gl/gl_surface_osmesa.h" | |
| 17 | |
| 18 // Note that this must be included after gl_bindings.h to avoid conflicts. | |
| 19 #include <OpenGL/CGLIOSurface.h> | |
| 20 | |
| 21 namespace content { | |
| 22 namespace { | |
| 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, | |
| 134 GpuCommandBufferStub* stub, | |
| 135 gfx::PluginWindowHandle handle) | |
| 136 : gfx::NoOpGLSurfaceCGL(gfx::Size(1, 1)), | |
| 137 backbuffer_suggested_allocation_(true), | |
| 138 frontbuffer_suggested_allocation_(true), | |
| 139 fbo_id_(0), | |
| 140 texture_id_(0), | |
| 141 depth_stencil_renderbuffer_id_(0), | |
| 142 io_surface_handle_(0), | |
| 143 context_(NULL), | |
| 144 scale_factor_(1.f), | |
| 145 made_current_(false), | |
| 146 is_swap_buffers_pending_(false), | |
| 147 did_unschedule_(false) { | |
| 148 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); | |
| 149 } | |
| 150 | |
| 151 IOSurfaceImageTransportSurface::~IOSurfaceImageTransportSurface() { | |
| 152 } | |
| 153 | |
| 154 bool IOSurfaceImageTransportSurface::Initialize() { | |
| 155 // Only support IOSurfaces if the GL implementation is the native desktop GL. | |
| 156 // IO surfaces will not work with, for example, OSMesa software renderer | |
| 157 // GL contexts. | |
| 158 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL && | |
| 159 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL) | |
| 160 return false; | |
| 161 | |
| 162 if (!helper_->Initialize()) | |
| 163 return false; | |
| 164 | |
| 165 if (!NoOpGLSurfaceCGL::Initialize()) { | |
| 166 helper_->Destroy(); | |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 helper_->stub()->AddDestructionObserver(this); | |
| 171 return true; | |
| 172 } | |
| 173 | |
| 174 void IOSurfaceImageTransportSurface::Destroy() { | |
| 175 UnrefIOSurface(); | |
| 176 | |
| 177 helper_->Destroy(); | |
| 178 NoOpGLSurfaceCGL::Destroy(); | |
| 179 } | |
| 180 | |
| 181 bool IOSurfaceImageTransportSurface::DeferDraws() { | |
| 182 // 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 | |
| 184 // processing of the command by returning true and unschedule until the Swap | |
| 185 // Ack arrives. | |
| 186 if(did_unschedule_) | |
| 187 return true; // Still unscheduled, so just return true. | |
| 188 if (is_swap_buffers_pending_) { | |
| 189 did_unschedule_ = true; | |
| 190 helper_->SetScheduled(false); | |
| 191 return true; | |
| 192 } | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 bool IOSurfaceImageTransportSurface::IsOffscreen() { | |
| 197 return false; | |
| 198 } | |
| 199 | |
| 200 bool IOSurfaceImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { | |
| 201 context_ = context; | |
| 202 | |
| 203 if (made_current_) | |
| 204 return true; | |
| 205 | |
| 206 OnResize(gfx::Size(1, 1), 1.f); | |
| 207 | |
| 208 made_current_ = true; | |
| 209 return true; | |
| 210 } | |
| 211 | |
| 212 unsigned int IOSurfaceImageTransportSurface::GetBackingFrameBufferObject() { | |
| 213 return fbo_id_; | |
| 214 } | |
| 215 | |
| 216 bool IOSurfaceImageTransportSurface::SetBackbufferAllocation(bool allocation) { | |
| 217 if (backbuffer_suggested_allocation_ == allocation) | |
| 218 return true; | |
| 219 backbuffer_suggested_allocation_ = allocation; | |
| 220 AdjustBufferAllocation(); | |
| 221 return true; | |
| 222 } | |
| 223 | |
| 224 void IOSurfaceImageTransportSurface::SetFrontbufferAllocation(bool allocation) { | |
| 225 if (frontbuffer_suggested_allocation_ == allocation) | |
| 226 return; | |
| 227 frontbuffer_suggested_allocation_ = allocation; | |
| 228 AdjustBufferAllocation(); | |
| 229 } | |
| 230 | |
| 231 void IOSurfaceImageTransportSurface::AdjustBufferAllocation() { | |
| 232 // 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. | |
| 234 if (!backbuffer_suggested_allocation_ && | |
| 235 !frontbuffer_suggested_allocation_ && | |
| 236 io_surface_.get()) { | |
| 237 UnrefIOSurface(); | |
| 238 helper_->Suspend(); | |
| 239 } else if (backbuffer_suggested_allocation_ && !io_surface_) { | |
| 240 CreateIOSurface(); | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 bool IOSurfaceImageTransportSurface::SwapBuffers() { | |
| 245 DCHECK(backbuffer_suggested_allocation_); | |
| 246 if (!frontbuffer_suggested_allocation_) | |
| 247 return true; | |
| 248 glFlush(); | |
| 249 | |
| 250 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
| 251 params.surface_handle = io_surface_handle_; | |
| 252 params.size = GetSize(); | |
| 253 params.scale_factor = scale_factor_; | |
| 254 params.latency_info.swap(latency_info_); | |
| 255 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | |
| 256 | |
| 257 DCHECK(!is_swap_buffers_pending_); | |
| 258 is_swap_buffers_pending_ = true; | |
| 259 return true; | |
| 260 } | |
| 261 | |
| 262 bool IOSurfaceImageTransportSurface::PostSubBuffer( | |
| 263 int x, int y, int width, int height) { | |
| 264 DCHECK(backbuffer_suggested_allocation_); | |
| 265 if (!frontbuffer_suggested_allocation_) | |
| 266 return true; | |
| 267 glFlush(); | |
| 268 | |
| 269 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | |
| 270 params.surface_handle = io_surface_handle_; | |
| 271 params.x = x; | |
| 272 params.y = y; | |
| 273 params.width = width; | |
| 274 params.height = height; | |
| 275 params.surface_size = GetSize(); | |
| 276 params.surface_scale_factor = scale_factor_; | |
| 277 params.latency_info.swap(latency_info_); | |
| 278 helper_->SendAcceleratedSurfacePostSubBuffer(params); | |
| 279 | |
| 280 DCHECK(!is_swap_buffers_pending_); | |
| 281 is_swap_buffers_pending_ = true; | |
| 282 return true; | |
| 283 } | |
| 284 | |
| 285 bool IOSurfaceImageTransportSurface::SupportsPostSubBuffer() { | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 gfx::Size IOSurfaceImageTransportSurface::GetSize() { | |
| 290 return size_; | |
| 291 } | |
| 292 | |
| 293 void IOSurfaceImageTransportSurface::OnBufferPresented( | |
| 294 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { | |
| 295 DCHECK(is_swap_buffers_pending_); | |
| 296 | |
| 297 context_->share_group()->SetRendererID(params.renderer_id); | |
| 298 is_swap_buffers_pending_ = false; | |
| 299 if (did_unschedule_) { | |
| 300 did_unschedule_ = false; | |
| 301 helper_->SetScheduled(true); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 void IOSurfaceImageTransportSurface::OnResize(gfx::Size size, | |
| 306 float scale_factor) { | |
| 307 // 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. | |
| 309 TRACE_EVENT2("gpu", "IOSurfaceImageTransportSurface::OnResize", | |
| 310 "old_width", size_.width(), "new_width", size.width()); | |
| 311 // Caching |context_| from OnMakeCurrent. It should still be current. | |
| 312 DCHECK(context_->IsCurrent(this)); | |
| 313 | |
| 314 size_ = size; | |
| 315 scale_factor_ = scale_factor; | |
| 316 | |
| 317 CreateIOSurface(); | |
| 318 } | |
| 319 | |
| 320 void IOSurfaceImageTransportSurface::SetLatencyInfo( | |
| 321 const std::vector<ui::LatencyInfo>& latency_info) { | |
| 322 for (size_t i = 0; i < latency_info.size(); i++) | |
| 323 latency_info_.push_back(latency_info[i]); | |
| 324 } | |
| 325 | |
| 326 void IOSurfaceImageTransportSurface::WakeUpGpu() { | |
| 327 NOTIMPLEMENTED(); | |
| 328 } | |
| 329 | |
| 330 void IOSurfaceImageTransportSurface::OnWillDestroyStub() { | |
| 331 helper_->stub()->RemoveDestructionObserver(this); | |
| 332 Destroy(); | |
| 333 } | |
| 334 | |
| 335 void IOSurfaceImageTransportSurface::UnrefIOSurface() { | |
| 336 // If we have resources to destroy, then make sure that we have a current | |
| 337 // context which we can use to delete the resources. | |
| 338 if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) { | |
| 339 DCHECK(gfx::GLContext::GetCurrent() == context_); | |
| 340 DCHECK(context_->IsCurrent(this)); | |
| 341 DCHECK(CGLGetCurrentContext()); | |
| 342 } | |
| 343 | |
| 344 if (fbo_id_) { | |
| 345 glDeleteFramebuffersEXT(1, &fbo_id_); | |
| 346 fbo_id_ = 0; | |
| 347 } | |
| 348 | |
| 349 if (texture_id_) { | |
| 350 glDeleteTextures(1, &texture_id_); | |
| 351 texture_id_ = 0; | |
| 352 } | |
| 353 | |
| 354 if (depth_stencil_renderbuffer_id_) { | |
| 355 glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_); | |
| 356 depth_stencil_renderbuffer_id_ = 0; | |
| 357 } | |
| 358 | |
| 359 io_surface_.reset(); | |
| 360 io_surface_handle_ = 0; | |
| 361 } | |
| 362 | |
| 363 void IOSurfaceImageTransportSurface::CreateIOSurface() { | |
| 364 gfx::Size new_rounded_size(RoundUpSurfaceDimension(size_.width()), | |
| 365 RoundUpSurfaceDimension(size_.height())); | |
| 366 | |
| 367 // Only recreate surface when the rounded up size has changed. | |
| 368 if (io_surface_.get() && new_rounded_size == rounded_size_) | |
| 369 return; | |
| 370 | |
| 371 // 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. | |
| 373 TRACE_EVENT2("gpu", "IOSurfaceImageTransportSurface::CreateIOSurface", | |
| 374 "width", new_rounded_size.width(), | |
| 375 "height", new_rounded_size.height()); | |
| 376 | |
| 377 rounded_size_ = new_rounded_size; | |
| 378 | |
| 379 GLint previous_texture_id = 0; | |
| 380 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id); | |
| 381 | |
| 382 // Free the old IO Surface first to reduce memory fragmentation. | |
| 383 UnrefIOSurface(); | |
| 384 | |
| 385 glGenFramebuffersEXT(1, &fbo_id_); | |
| 386 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_); | |
| 387 | |
| 388 glGenTextures(1, &texture_id_); | |
| 389 | |
| 390 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on | |
| 391 // Mac OS X and is required for IOSurface interoperability. | |
| 392 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | |
| 393 glBindTexture(target, texture_id_); | |
| 394 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 395 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| 396 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 397 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 398 | |
| 399 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, | |
| 400 GL_COLOR_ATTACHMENT0_EXT, | |
| 401 target, | |
| 402 texture_id_, | |
| 403 0); | |
| 404 | |
| 405 | |
| 406 // Search through the provided attributes; if the caller has | |
| 407 // requested a stencil buffer, try to get one. | |
| 408 | |
| 409 int32 stencil_bits = | |
| 410 helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE); | |
| 411 if (stencil_bits > 0) { | |
| 412 // Create and bind the stencil buffer | |
| 413 bool has_packed_depth_stencil = | |
| 414 GLSurface::ExtensionsContain( | |
| 415 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)), | |
| 416 "GL_EXT_packed_depth_stencil"); | |
| 417 | |
| 418 if (has_packed_depth_stencil) { | |
| 419 glGenRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_); | |
| 420 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, | |
| 421 depth_stencil_renderbuffer_id_); | |
| 422 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, | |
| 423 rounded_size_.width(), rounded_size_.height()); | |
| 424 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, | |
| 425 GL_STENCIL_ATTACHMENT_EXT, | |
| 426 GL_RENDERBUFFER_EXT, | |
| 427 depth_stencil_renderbuffer_id_); | |
| 428 } | |
| 429 | |
| 430 // If we asked for stencil but the extension isn't present, | |
| 431 // it's OK to silently fail; subsequent code will/must check | |
| 432 // for the presence of a stencil buffer before attempting to | |
| 433 // do stencil-based operations. | |
| 434 } | |
| 435 | |
| 436 // Allocate a new IOSurface, which is the GPU resource that can be | |
| 437 // shared across processes. | |
| 438 base::ScopedCFTypeRef<CFMutableDictionaryRef> properties; | |
| 439 properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault, | |
| 440 0, | |
| 441 &kCFTypeDictionaryKeyCallBacks, | |
| 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; | |
| 475 } | |
| 476 | |
| 477 glFlush(); | |
| 478 | |
| 479 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); | |
| 480 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { | |
| 481 DLOG(ERROR) << "Framebuffer was incomplete: " << status; | |
| 482 UnrefIOSurface(); | |
| 483 return; | |
| 484 } | |
| 485 | |
| 486 glBindTexture(target, previous_texture_id); | |
| 487 // The FBO remains bound for this GL context. | |
| 488 } | |
| 489 | |
| 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 | |
| OLD | NEW |