srpcgen: Use 'const char*' for string parameters
[chromium-blink-merge.git] / content / common / gpu / image_transport_surface_mac.cc
blob5bcadc4f68c2aa999028b78f5898072d4a689a89
1 // Copyright (c) 2011 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.
5 #if defined(ENABLE_GPU)
7 #include "content/common/gpu/image_transport_surface.h"
9 #include "base/mac/scoped_cftyperef.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "content/common/gpu/gpu_messages.h"
12 #include "ui/gfx/gl/gl_context.h"
13 #include "ui/gfx/gl/gl_bindings.h"
14 #include "ui/gfx/gl/gl_implementation.h"
15 #include "ui/gfx/gl/gl_surface_cgl.h"
16 #include "ui/gfx/native_widget_types.h"
17 #include "ui/gfx/surface/io_surface_support_mac.h"
19 namespace {
21 // We are backed by an offscreen surface for the purposes of creating
22 // a context, but use FBOs to render to texture backed IOSurface
23 class IOSurfaceImageTransportSurface : public gfx::NoOpGLSurfaceCGL,
24 public ImageTransportSurface {
25 public:
26 IOSurfaceImageTransportSurface(GpuChannelManager* manager,
27 int32 render_view_id,
28 int32 renderer_id,
29 int32 command_buffer_id,
30 gfx::PluginWindowHandle handle);
32 // GLSurface implementation
33 virtual bool Initialize() OVERRIDE;
34 virtual void Destroy() OVERRIDE;
35 virtual bool IsOffscreen() OVERRIDE;
36 virtual bool SwapBuffers() OVERRIDE;
37 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
38 virtual std::string GetExtensions() OVERRIDE;
39 virtual gfx::Size GetSize() OVERRIDE;
40 virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE;
41 virtual unsigned int GetBackingFrameBufferObject() OVERRIDE;
43 protected:
44 // ImageTransportSurface implementation
45 virtual void OnNewSurfaceACK(uint64 surface_id,
46 TransportDIB::Handle shm_handle) OVERRIDE;
47 virtual void OnBuffersSwappedACK() OVERRIDE;
48 virtual void OnPostSubBufferACK() OVERRIDE;
49 virtual void OnResizeViewACK() OVERRIDE;
50 virtual void OnResize(gfx::Size size) OVERRIDE;
52 private:
53 virtual ~IOSurfaceImageTransportSurface() OVERRIDE;
55 uint32 fbo_id_;
56 GLuint texture_id_;
58 base::mac::ScopedCFTypeRef<CFTypeRef> io_surface_;
60 // The id of |io_surface_| or 0 if that's NULL.
61 uint64 io_surface_id_;
63 // Weak pointer to the context that this was last made current to.
64 gfx::GLContext* context_;
66 gfx::Size size_;
68 // Whether or not we've successfully made the surface current once.
69 bool made_current_;
71 scoped_ptr<ImageTransportHelper> helper_;
73 DISALLOW_COPY_AND_ASSIGN(IOSurfaceImageTransportSurface);
76 // We are backed by an offscreen surface for the purposes of creating
77 // a context, but use FBOs to render to texture backed IOSurface
78 class TransportDIBImageTransportSurface : public gfx::NoOpGLSurfaceCGL,
79 public ImageTransportSurface {
80 public:
81 TransportDIBImageTransportSurface(GpuChannelManager* manager,
82 int32 render_view_id,
83 int32 renderer_id,
84 int32 command_buffer_id,
85 gfx::PluginWindowHandle handle);
87 // GLSurface implementation
88 virtual bool Initialize() OVERRIDE;
89 virtual void Destroy() OVERRIDE;
90 virtual bool IsOffscreen() OVERRIDE;
91 virtual bool SwapBuffers() OVERRIDE;
92 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
93 virtual std::string GetExtensions() OVERRIDE;
94 virtual gfx::Size GetSize() OVERRIDE;
95 virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE;
96 virtual unsigned int GetBackingFrameBufferObject() OVERRIDE;
98 protected:
99 // ImageTransportSurface implementation
100 virtual void OnBuffersSwappedACK() OVERRIDE;
101 virtual void OnPostSubBufferACK() OVERRIDE;
102 virtual void OnNewSurfaceACK(uint64 surface_id,
103 TransportDIB::Handle shm_handle) OVERRIDE;
104 virtual void OnResizeViewACK() OVERRIDE;
105 virtual void OnResize(gfx::Size size) OVERRIDE;
107 private:
108 virtual ~TransportDIBImageTransportSurface() OVERRIDE;
110 uint32 fbo_id_;
111 GLuint render_buffer_id_;
113 scoped_ptr<TransportDIB> shared_mem_;
115 gfx::Size size_;
117 static uint32 next_id_;
119 // Whether or not we've successfully made the surface current once.
120 bool made_current_;
122 scoped_ptr<ImageTransportHelper> helper_;
124 DISALLOW_COPY_AND_ASSIGN(TransportDIBImageTransportSurface);
127 uint32 TransportDIBImageTransportSurface::next_id_ = 1;
129 void AddBooleanValue(CFMutableDictionaryRef dictionary,
130 const CFStringRef key,
131 bool value) {
132 CFDictionaryAddValue(dictionary, key,
133 (value ? kCFBooleanTrue : kCFBooleanFalse));
136 void AddIntegerValue(CFMutableDictionaryRef dictionary,
137 const CFStringRef key,
138 int32 value) {
139 base::mac::ScopedCFTypeRef<CFNumberRef> number(
140 CFNumberCreate(NULL, kCFNumberSInt32Type, &value));
141 CFDictionaryAddValue(dictionary, key, number.get());
144 IOSurfaceImageTransportSurface::IOSurfaceImageTransportSurface(
145 GpuChannelManager* manager,
146 int32 render_view_id,
147 int32 renderer_id,
148 int32 command_buffer_id,
149 gfx::PluginWindowHandle handle)
150 : gfx::NoOpGLSurfaceCGL(gfx::Size(1, 1)),
151 fbo_id_(0),
152 texture_id_(0),
153 io_surface_id_(0),
154 context_(NULL),
155 made_current_(false) {
156 helper_.reset(new ImageTransportHelper(this,
157 manager,
158 render_view_id,
159 renderer_id,
160 command_buffer_id,
161 handle));
165 IOSurfaceImageTransportSurface::~IOSurfaceImageTransportSurface() {
166 Destroy();
169 bool IOSurfaceImageTransportSurface::Initialize() {
170 // Only support IOSurfaces if the GL implementation is the native desktop GL.
171 // IO surfaces will not work with, for example, OSMesa software renderer
172 // GL contexts.
173 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL &&
174 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL)
175 return false;
177 if (!helper_->Initialize())
178 return false;
179 return NoOpGLSurfaceCGL::Initialize();
182 void IOSurfaceImageTransportSurface::Destroy() {
183 if (fbo_id_) {
184 glDeleteFramebuffersEXT(1, &fbo_id_);
185 fbo_id_ = 0;
188 if (texture_id_) {
189 glDeleteTextures(1, &texture_id_);
190 texture_id_ = 0;
193 helper_->Destroy();
194 NoOpGLSurfaceCGL::Destroy();
197 bool IOSurfaceImageTransportSurface::IsOffscreen() {
198 return false;
201 bool IOSurfaceImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) {
202 context_ = context;
204 if (made_current_)
205 return true;
207 glGenFramebuffersEXT(1, &fbo_id_);
208 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
209 OnResize(gfx::Size(1, 1));
211 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
212 if (status != GL_FRAMEBUFFER_COMPLETE) {
213 DLOG(ERROR) << "Framebuffer incomplete.";
214 return false;
217 made_current_ = true;
218 return true;
221 unsigned int IOSurfaceImageTransportSurface::GetBackingFrameBufferObject() {
222 return fbo_id_;
225 bool IOSurfaceImageTransportSurface::SwapBuffers() {
226 glFlush();
228 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
229 params.surface_id = io_surface_id_;
230 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
232 helper_->SetScheduled(false);
233 return true;
236 bool IOSurfaceImageTransportSurface::PostSubBuffer(
237 int x, int y, int width, int height) {
238 glFlush();
240 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params;
241 params.surface_id = io_surface_id_;
242 params.x = x;
243 params.y = y;
244 params.width = width;
245 params.height = height;
246 helper_->SendAcceleratedSurfacePostSubBuffer(params);
248 helper_->SetScheduled(false);
249 return true;
252 std::string IOSurfaceImageTransportSurface::GetExtensions() {
253 std::string extensions = gfx::GLSurface::GetExtensions();
254 extensions += extensions.empty() ? "" : " ";
255 extensions += "GL_CHROMIUM_front_buffer_cached ";
256 extensions += "GL_CHROMIUM_post_sub_buffer";
257 return extensions;
260 gfx::Size IOSurfaceImageTransportSurface::GetSize() {
261 return size_;
264 void IOSurfaceImageTransportSurface::OnBuffersSwappedACK() {
265 helper_->SetScheduled(true);
268 void IOSurfaceImageTransportSurface::OnPostSubBufferACK() {
269 helper_->SetScheduled(true);
272 void IOSurfaceImageTransportSurface::OnNewSurfaceACK(
273 uint64 surface_id,
274 TransportDIB::Handle /* shm_handle */) {
275 DCHECK_EQ(io_surface_id_, surface_id);
276 helper_->SetScheduled(true);
279 void IOSurfaceImageTransportSurface::OnResizeViewACK() {
280 NOTREACHED();
283 void IOSurfaceImageTransportSurface::OnResize(gfx::Size size) {
284 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
286 // Caching |context_| from OnMakeCurrent. It should still be current.
287 DCHECK(context_->IsCurrent(this));
289 size_ = size;
291 if (texture_id_) {
292 glDeleteTextures(1, &texture_id_);
293 texture_id_ = 0;
296 glGenTextures(1, &texture_id_);
298 GLint previous_texture_id = 0;
299 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id);
301 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
302 // Mac OS X and is required for IOSurface interoperability.
303 GLenum target = GL_TEXTURE_RECTANGLE_ARB;
304 glBindTexture(target, texture_id_);
305 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
306 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
307 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
308 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
310 GLint previous_fbo_id = 0;
311 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previous_fbo_id);
313 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
315 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
316 GL_COLOR_ATTACHMENT0_EXT,
317 target,
318 texture_id_,
321 // Allocate a new IOSurface, which is the GPU resource that can be
322 // shared across processes.
323 base::mac::ScopedCFTypeRef<CFMutableDictionaryRef> properties;
324 properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
326 &kCFTypeDictionaryKeyCallBacks,
327 &kCFTypeDictionaryValueCallBacks));
328 AddIntegerValue(properties,
329 io_surface_support->GetKIOSurfaceWidth(),
330 size_.width());
331 AddIntegerValue(properties,
332 io_surface_support->GetKIOSurfaceHeight(),
333 size_.height());
334 AddIntegerValue(properties,
335 io_surface_support->GetKIOSurfaceBytesPerElement(), 4);
336 AddBooleanValue(properties,
337 io_surface_support->GetKIOSurfaceIsGlobal(), true);
338 // I believe we should be able to unreference the IOSurfaces without
339 // synchronizing with the browser process because they are
340 // ultimately reference counted by the operating system.
341 io_surface_.reset(io_surface_support->IOSurfaceCreate(properties));
343 // Don't think we need to identify a plane.
344 GLuint plane = 0;
345 io_surface_support->CGLTexImageIOSurface2D(
346 static_cast<CGLContextObj>(context_->GetHandle()),
347 target,
348 GL_RGBA,
349 size_.width(),
350 size_.height(),
351 GL_BGRA,
352 GL_UNSIGNED_INT_8_8_8_8_REV,
353 io_surface_.get(),
354 plane);
356 io_surface_id_ = io_surface_support->IOSurfaceGetID(io_surface_);
357 glFlush();
359 glBindTexture(target, previous_texture_id);
360 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, previous_fbo_id);
362 GpuHostMsg_AcceleratedSurfaceNew_Params params;
363 params.width = size_.width();
364 params.height = size_.height();
365 params.surface_id = io_surface_id_;
366 params.create_transport_dib = false;
367 helper_->SendAcceleratedSurfaceNew(params);
369 helper_->SetScheduled(false);
372 TransportDIBImageTransportSurface::TransportDIBImageTransportSurface(
373 GpuChannelManager* manager,
374 int32 render_view_id,
375 int32 renderer_id,
376 int32 command_buffer_id,
377 gfx::PluginWindowHandle handle)
378 : gfx::NoOpGLSurfaceCGL(gfx::Size(1, 1)),
379 fbo_id_(0),
380 render_buffer_id_(0),
381 made_current_(false) {
382 helper_.reset(new ImageTransportHelper(this,
383 manager,
384 render_view_id,
385 renderer_id,
386 command_buffer_id,
387 handle));
391 TransportDIBImageTransportSurface::~TransportDIBImageTransportSurface() {
392 Destroy();
395 bool TransportDIBImageTransportSurface::Initialize() {
396 if (!helper_->Initialize())
397 return false;
398 return NoOpGLSurfaceCGL::Initialize();
401 void TransportDIBImageTransportSurface::Destroy() {
402 if (fbo_id_) {
403 glDeleteFramebuffersEXT(1, &fbo_id_);
404 fbo_id_ = 0;
407 if (render_buffer_id_) {
408 glDeleteRenderbuffersEXT(1, &render_buffer_id_);
409 render_buffer_id_ = 0;
412 helper_->Destroy();
413 NoOpGLSurfaceCGL::Destroy();
416 bool TransportDIBImageTransportSurface::IsOffscreen() {
417 return false;
420 bool TransportDIBImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) {
421 if (made_current_)
422 return true;
424 glGenFramebuffersEXT(1, &fbo_id_);
425 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
426 OnResize(gfx::Size(1, 1));
428 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
429 if (status != GL_FRAMEBUFFER_COMPLETE) {
430 DLOG(ERROR) << "Framebuffer incomplete.";
431 return false;
434 made_current_ = true;
435 return true;
438 unsigned int TransportDIBImageTransportSurface::GetBackingFrameBufferObject() {
439 return fbo_id_;
442 bool TransportDIBImageTransportSurface::SwapBuffers() {
443 DCHECK_NE(shared_mem_.get(), static_cast<void*>(NULL));
445 GLint previous_fbo_id = 0;
446 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &previous_fbo_id);
448 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
450 GLint current_alignment = 0;
451 glGetIntegerv(GL_PACK_ALIGNMENT, &current_alignment);
452 glPixelStorei(GL_PACK_ALIGNMENT, 4);
453 glReadPixels(0, 0,
454 size_.width(), size_.height(),
455 GL_BGRA, // This pixel format should have no conversion.
456 GL_UNSIGNED_INT_8_8_8_8_REV,
457 shared_mem_->memory());
458 glPixelStorei(GL_PACK_ALIGNMENT, current_alignment);
460 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, previous_fbo_id);
462 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
463 params.surface_id = next_id_;
464 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
466 helper_->SetScheduled(false);
467 return true;
470 bool TransportDIBImageTransportSurface::PostSubBuffer(
471 int x, int y, int width, int height) {
472 DCHECK_NE(shared_mem_.get(), static_cast<void*>(NULL));
474 GLint previous_fbo_id = 0;
475 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &previous_fbo_id);
477 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
479 GLint current_alignment = 0, current_pack_row_length = 0;
480 glGetIntegerv(GL_PACK_ALIGNMENT, &current_alignment);
481 glGetIntegerv(GL_PACK_ROW_LENGTH, &current_pack_row_length);
483 glPixelStorei(GL_PACK_ALIGNMENT, 4);
484 glPixelStorei(GL_PACK_ROW_LENGTH, size_.width());
486 unsigned char* buffer =
487 static_cast<unsigned char*>(shared_mem_->memory());
488 glReadPixels(x, y,
489 width, height,
490 GL_BGRA, // This pixel format should have no conversion.
491 GL_UNSIGNED_INT_8_8_8_8_REV,
492 &buffer[(x + y * size_.width()) * 4]);
494 glPixelStorei(GL_PACK_ALIGNMENT, current_alignment);
495 glPixelStorei(GL_PACK_ROW_LENGTH, current_pack_row_length);
497 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, previous_fbo_id);
499 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params;
500 params.surface_id = next_id_;
501 params.x = x;
502 params.y = y;
503 params.width = width;
504 params.height = height;
505 helper_->SendAcceleratedSurfacePostSubBuffer(params);
507 helper_->SetScheduled(false);
508 return true;
511 std::string TransportDIBImageTransportSurface::GetExtensions() {
512 std::string extensions = gfx::GLSurface::GetExtensions();
513 extensions += extensions.empty() ? "" : " ";
514 extensions += "GL_CHROMIUM_front_buffer_cached ";
515 extensions += "GL_CHROMIUM_post_sub_buffer";
516 return extensions;
519 gfx::Size TransportDIBImageTransportSurface::GetSize() {
520 return size_;
523 void TransportDIBImageTransportSurface::OnBuffersSwappedACK() {
524 helper_->SetScheduled(true);
527 void TransportDIBImageTransportSurface::OnPostSubBufferACK() {
528 helper_->SetScheduled(true);
531 void TransportDIBImageTransportSurface::OnNewSurfaceACK(
532 uint64 surface_id,
533 TransportDIB::Handle shm_handle) {
534 helper_->SetScheduled(true);
536 shared_mem_.reset(TransportDIB::Map(shm_handle));
537 DCHECK_NE(shared_mem_.get(), static_cast<void*>(NULL));
540 void TransportDIBImageTransportSurface::OnResizeViewACK() {
541 NOTREACHED();
544 void TransportDIBImageTransportSurface::OnResize(gfx::Size size) {
545 size_ = size;
547 if (!render_buffer_id_)
548 glGenRenderbuffersEXT(1, &render_buffer_id_);
550 GLint previous_fbo_id = 0;
551 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &previous_fbo_id);
553 GLint previous_renderbuffer_id = 0;
554 glGetIntegerv(GL_RENDERBUFFER_BINDING_EXT, &previous_renderbuffer_id);
556 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
557 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_buffer_id_);
559 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
560 GL_RGBA,
561 size_.width(), size_.height());
562 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
563 GL_COLOR_ATTACHMENT0_EXT,
564 GL_RENDERBUFFER_EXT,
565 render_buffer_id_);
567 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, previous_renderbuffer_id);
568 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, previous_fbo_id);
570 GpuHostMsg_AcceleratedSurfaceNew_Params params;
571 params.width = size_.width();
572 params.height = size_.height();
573 params.surface_id = next_id_++;
574 params.create_transport_dib = true;
575 helper_->SendAcceleratedSurfaceNew(params);
577 helper_->SetScheduled(false);
580 } // namespace
582 // static
583 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface(
584 GpuChannelManager* manager,
585 int32 render_view_id,
586 int32 renderer_id,
587 int32 command_buffer_id,
588 gfx::PluginWindowHandle handle) {
589 scoped_refptr<gfx::GLSurface> surface;
590 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
592 switch (gfx::GetGLImplementation()) {
593 case gfx::kGLImplementationDesktopGL:
594 case gfx::kGLImplementationAppleGL:
595 if (!io_surface_support) {
596 surface = new TransportDIBImageTransportSurface(manager,
597 render_view_id,
598 renderer_id,
599 command_buffer_id,
600 handle);
601 } else {
602 surface = new IOSurfaceImageTransportSurface(manager,
603 render_view_id,
604 renderer_id,
605 command_buffer_id,
606 handle);
608 break;
609 default:
610 NOTREACHED();
611 return NULL;
613 if (surface->Initialize())
614 return surface;
615 else
616 return NULL;
619 #endif // defined(USE_GPU)