Index: ui/gfx/surface/accelerated_surface_mac.cc |
diff --git a/ui/gfx/surface/accelerated_surface_mac.cc b/ui/gfx/surface/accelerated_surface_mac.cc |
deleted file mode 100644 |
index 6978c574ace06587c26e7655dba631b8b59b08ff..0000000000000000000000000000000000000000 |
--- a/ui/gfx/surface/accelerated_surface_mac.cc |
+++ /dev/null |
@@ -1,363 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "ui/gfx/surface/accelerated_surface_mac.h" |
- |
-#include "base/logging.h" |
-#include "base/mac/scoped_cftyperef.h" |
-#include "ui/gfx/gl/gl_bindings.h" |
-#include "ui/gfx/gl/gl_context.h" |
-#include "ui/gfx/gl/gl_implementation.h" |
-#include "ui/gfx/gl/gl_surface.h" |
-#include "ui/gfx/gl/scoped_make_current.h" |
-#include "ui/gfx/rect.h" |
-#include "ui/gfx/surface/io_surface_support_mac.h" |
- |
-AcceleratedSurface::AcceleratedSurface() |
- : io_surface_id_(0), |
- allocate_fbo_(false), |
- texture_(0), |
- fbo_(0) { |
-} |
- |
-AcceleratedSurface::~AcceleratedSurface() {} |
- |
-bool AcceleratedSurface::Initialize( |
- gfx::GLContext* share_context, |
- bool allocate_fbo, |
- gfx::GpuPreference gpu_preference) { |
- allocate_fbo_ = allocate_fbo; |
- |
- // Ensure GL is initialized before trying to create an offscreen GL context. |
- if (!gfx::GLSurface::InitializeOneOff()) |
- return false; |
- |
- // Drawing to IOSurfaces via OpenGL only works with Apple's GL and |
- // not with the OSMesa software renderer. |
- if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL && |
- gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL) |
- return false; |
- |
- gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface( |
- false, gfx::Size(1, 1)); |
- if (!gl_surface_.get()) { |
- Destroy(); |
- return false; |
- } |
- |
- gfx::GLShareGroup* share_group = |
- share_context ? share_context->share_group() : NULL; |
- |
- gl_context_ = gfx::GLContext::CreateGLContext( |
- share_group, |
- gl_surface_.get(), |
- gpu_preference); |
- if (!gl_context_.get()) { |
- Destroy(); |
- return false; |
- } |
- |
- // Now we're ready to handle SetSurfaceSize calls, which will |
- // allocate and/or reallocate the IOSurface and associated offscreen |
- // OpenGL structures for rendering. |
- return true; |
-} |
- |
-void AcceleratedSurface::Destroy() { |
- // The FBO and texture objects will be destroyed when the OpenGL context, |
- // and any other contexts sharing resources with it, is. We don't want to |
- // make the context current one last time here just in order to delete |
- // these objects. |
- |
- // Release the old TransportDIB in the browser. |
- if (!dib_free_callback_.is_null() && transport_dib_.get()) { |
- dib_free_callback_.Run(transport_dib_->id()); |
- } |
- transport_dib_.reset(); |
- |
- gl_context_ = NULL; |
- gl_surface_ = NULL; |
-} |
- |
-// Call after making changes to the surface which require a visual update. |
-// Makes the rendering show up in other processes. |
-void AcceleratedSurface::SwapBuffers() { |
- if (io_surface_.get() != NULL) { |
- if (allocate_fbo_) { |
- // Bind and unbind the framebuffer to make changes to the |
- // IOSurface show up in the other process. |
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); |
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_); |
- glFlush(); |
- } else { |
- // Copy the current framebuffer's contents into our "live" texture. |
- // Note that the current GL context might not be ours at this point! |
- // This is deliberate, so that surrounding code using GL can produce |
- // rendering results consumed by the AcceleratedSurface. |
- // Need to save and restore OpenGL state around this call. |
- GLint current_texture = 0; |
- GLenum target_binding = GL_TEXTURE_BINDING_RECTANGLE_ARB; |
- GLenum target = GL_TEXTURE_RECTANGLE_ARB; |
- glGetIntegerv(target_binding, ¤t_texture); |
- glBindTexture(target, texture_); |
- glCopyTexSubImage2D(target, 0, |
- 0, 0, |
- 0, 0, |
- real_surface_size_.width(), |
- real_surface_size_.height()); |
- glBindTexture(target, current_texture); |
- // This flush is absolutely essential -- it guarantees that the |
- // rendering results are seen by the other process. |
- glFlush(); |
- } |
- } else if (transport_dib_.get() != NULL) { |
- // Pre-Mac OS X 10.6, fetch the rendered image from the current frame |
- // buffer and copy it into the TransportDIB. |
- // TODO(dspringer): There are a couple of options that can speed this up. |
- // First is to use async reads into a PBO, second is to use SPI that |
- // allows many tasks to access the same CGSSurface. |
- void* pixel_memory = transport_dib_->memory(); |
- if (pixel_memory) { |
- // Note that glReadPixels does an implicit glFlush(). |
- glReadPixels(0, |
- 0, |
- real_surface_size_.width(), |
- real_surface_size_.height(), |
- GL_BGRA, // This pixel format should have no conversion. |
- GL_UNSIGNED_INT_8_8_8_8_REV, |
- pixel_memory); |
- } |
- } |
-} |
- |
-static void AddBooleanValue(CFMutableDictionaryRef dictionary, |
- const CFStringRef key, |
- bool value) { |
- CFDictionaryAddValue(dictionary, key, |
- (value ? kCFBooleanTrue : kCFBooleanFalse)); |
-} |
- |
-static void AddIntegerValue(CFMutableDictionaryRef dictionary, |
- const CFStringRef key, |
- int32 value) { |
- base::mac::ScopedCFTypeRef<CFNumberRef> number( |
- CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); |
- CFDictionaryAddValue(dictionary, key, number.get()); |
-} |
- |
-// Creates a new OpenGL texture object bound to the given texture target. |
-// Caller owns the returned texture. |
-static GLuint CreateTexture(GLenum target) { |
- GLuint texture = 0; |
- glGenTextures(1, &texture); |
- glBindTexture(target, texture); |
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
- return texture; |
-} |
- |
-void AcceleratedSurface::AllocateRenderBuffers(GLenum target, |
- const gfx::Size& size) { |
- if (!texture_) { |
- // Generate the texture object. |
- texture_ = CreateTexture(target); |
- // Generate and bind the framebuffer object. |
- glGenFramebuffersEXT(1, &fbo_); |
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_); |
- } |
- |
- // Make sure that subsequent set-up code affects the render texture. |
- glBindTexture(target, texture_); |
-} |
- |
-bool AcceleratedSurface::SetupFrameBufferObject(GLenum target) { |
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_); |
- GLenum fbo_status; |
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, |
- GL_COLOR_ATTACHMENT0_EXT, |
- target, |
- texture_, |
- 0); |
- fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); |
- return fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT; |
-} |
- |
-gfx::Size AcceleratedSurface::ClampToValidDimensions(const gfx::Size& size) { |
- return gfx::Size(std::max(size.width(), 1), std::max(size.height(), 1)); |
-} |
- |
-bool AcceleratedSurface::MakeCurrent() { |
- if (!gl_context_.get()) |
- return false; |
- return gl_context_->MakeCurrent(gl_surface_.get()); |
-} |
- |
-void AcceleratedSurface::Clear(const gfx::Rect& rect) { |
- DCHECK(gl_context_->IsCurrent(gl_surface_.get())); |
- glClearColor(0, 0, 0, 0); |
- glViewport(0, 0, rect.width(), rect.height()); |
- glMatrixMode(GL_PROJECTION); |
- glLoadIdentity(); |
- glOrtho(0, rect.width(), 0, rect.height(), -1, 1); |
- glClear(GL_COLOR_BUFFER_BIT); |
-} |
- |
-uint32 AcceleratedSurface::SetSurfaceSize(const gfx::Size& size) { |
- if (surface_size_ == size) { |
- // Return 0 to indicate to the caller that no new backing store |
- // allocation occurred. |
- return 0; |
- } |
- |
- // Only support IO surfaces if the GL implementation is the native desktop GL. |
- // IO surfaces will not work with, for example, OSMesa software renderer |
- // GL contexts. |
- if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) |
- return 0; |
- |
- IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); |
- if (!io_surface_support) |
- return 0; // Caller can try using SetWindowSizeForTransportDIB(). |
- |
- gfx::ScopedMakeCurrent make_current(gl_context_.get(), gl_surface_.get()); |
- if (!make_current.Succeeded()) |
- return 0; |
- |
- gfx::Size clamped_size = ClampToValidDimensions(size); |
- |
- // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on |
- // Mac OS X and is required for IOSurface interoperability. |
- GLenum target = GL_TEXTURE_RECTANGLE_ARB; |
- if (allocate_fbo_) { |
- AllocateRenderBuffers(target, clamped_size); |
- } else if (!texture_) { |
- // Generate the texture object. |
- texture_ = CreateTexture(target); |
- } |
- |
- // Allocate a new IOSurface, which is the GPU resource that can be |
- // shared across processes. |
- base::mac::ScopedCFTypeRef<CFMutableDictionaryRef> properties; |
- properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault, |
- 0, |
- &kCFTypeDictionaryKeyCallBacks, |
- &kCFTypeDictionaryValueCallBacks)); |
- AddIntegerValue(properties, |
- io_surface_support->GetKIOSurfaceWidth(), |
- clamped_size.width()); |
- AddIntegerValue(properties, |
- io_surface_support->GetKIOSurfaceHeight(), |
- clamped_size.height()); |
- AddIntegerValue(properties, |
- io_surface_support->GetKIOSurfaceBytesPerElement(), 4); |
- AddBooleanValue(properties, |
- io_surface_support->GetKIOSurfaceIsGlobal(), true); |
- // I believe we should be able to unreference the IOSurfaces without |
- // synchronizing with the browser process because they are |
- // ultimately reference counted by the operating system. |
- io_surface_.reset(io_surface_support->IOSurfaceCreate(properties)); |
- |
- // Don't think we need to identify a plane. |
- GLuint plane = 0; |
- CGLError error = io_surface_support->CGLTexImageIOSurface2D( |
- static_cast<CGLContextObj>(gl_context_->GetHandle()), |
- target, |
- GL_RGBA, |
- clamped_size.width(), |
- clamped_size.height(), |
- GL_BGRA, |
- GL_UNSIGNED_INT_8_8_8_8_REV, |
- io_surface_.get(), |
- plane); |
- if (error != kCGLNoError) { |
- DLOG(ERROR) << "CGL error " << error << " during CGLTexImageIOSurface2D"; |
- } |
- if (allocate_fbo_) { |
- // Set up the frame buffer object. |
- if (!SetupFrameBufferObject(target)) { |
- DLOG(ERROR) << "Failed to set up frame buffer object"; |
- } |
- } |
- surface_size_ = size; |
- real_surface_size_ = clamped_size; |
- |
- // Now send back an identifier for the IOSurface. We originally |
- // intended to send back a mach port from IOSurfaceCreateMachPort |
- // but it looks like Chrome IPC would need to be modified to |
- // properly send mach ports between processes. For the time being we |
- // make our IOSurfaces global and send back their identifiers. On |
- // the browser process side the identifier is reconstituted into an |
- // IOSurface for on-screen rendering. |
- io_surface_id_ = io_surface_support->IOSurfaceGetID(io_surface_); |
- return io_surface_id_; |
-} |
- |
-uint32 AcceleratedSurface::GetSurfaceId() { |
- return io_surface_id_; |
-} |
- |
-TransportDIB::Handle AcceleratedSurface::SetTransportDIBSize( |
- const gfx::Size& size) { |
- if (surface_size_ == size) { |
- // Return an invalid handle to indicate to the caller that no new backing |
- // store allocation occurred. |
- return TransportDIB::DefaultHandleValue(); |
- } |
- surface_size_ = size; |
- gfx::Size clamped_size = ClampToValidDimensions(size); |
- real_surface_size_ = clamped_size; |
- |
- // Release the old TransportDIB in the browser. |
- if (!dib_free_callback_.is_null() && transport_dib_.get()) { |
- dib_free_callback_.Run(transport_dib_->id()); |
- } |
- transport_dib_.reset(); |
- |
- // Ask the renderer to create a TransportDIB. |
- size_t dib_size = |
- clamped_size.width() * 4 * clamped_size.height(); // 4 bytes per pixel. |
- TransportDIB::Handle dib_handle; |
- if (!dib_alloc_callback_.is_null()) { |
- dib_alloc_callback_.Run(dib_size, &dib_handle); |
- } |
- if (!TransportDIB::is_valid_handle(dib_handle)) { |
- // If the allocator fails, it means the DIB was not created in the browser, |
- // so there is no need to run the deallocator here. |
- return TransportDIB::DefaultHandleValue(); |
- } |
- transport_dib_.reset(TransportDIB::Map(dib_handle)); |
- if (transport_dib_.get() == NULL) { |
- // TODO(dspringer): if the Map() fails, should the deallocator be run so |
- // that the DIB is deallocated in the browser? |
- return TransportDIB::DefaultHandleValue(); |
- } |
- |
- if (allocate_fbo_) { |
- DCHECK(gl_context_->IsCurrent(gl_surface_.get())); |
- // Set up the render buffers and reserve enough space on the card for the |
- // framebuffer texture. |
- GLenum target = GL_TEXTURE_RECTANGLE_ARB; |
- AllocateRenderBuffers(target, clamped_size); |
- glTexImage2D(target, |
- 0, // mipmap level 0 |
- GL_RGBA8, // internal pixel format |
- clamped_size.width(), |
- clamped_size.height(), |
- 0, // 0 border |
- GL_BGRA, // Used for consistency |
- GL_UNSIGNED_INT_8_8_8_8_REV, |
- NULL); // No data, just reserve room on the card. |
- SetupFrameBufferObject(target); |
- } |
- return transport_dib_->handle(); |
-} |
- |
-void AcceleratedSurface::SetTransportDIBAllocAndFree( |
- const base::Callback<void(size_t, TransportDIB::Handle*)>& allocator, |
- const base::Callback<void(TransportDIB::Id)>& deallocator) { |
- dib_alloc_callback_ = allocator; |
- dib_free_callback_ = deallocator; |
-} |