summaryrefslogtreecommitdiff
path: root/content/common/gpu/image_transport_surface_fbo_mac.mm
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-08-19 13:00:08 +0100
committerTorne (Richard Coles) <torne@google.com>2014-08-19 13:00:08 +0100
commit6e8cce623b6e4fe0c9e4af605d675dd9d0338c38 (patch)
tree8d824ad26fac42e008142b86aa9631b2be7e4705 /content/common/gpu/image_transport_surface_fbo_mac.mm
parent4f7316adb45db5ec3c9c1181ba9510c004566df8 (diff)
downloadchromium_org-6e8cce623b6e4fe0c9e4af605d675dd9d0338c38.tar.gz
Merge from Chromium at DEPS revision 290040
This commit was generated by merge_to_master.py. Change-Id: I694ec52d1e0b553f163c2faf4373d63270ab1aac
Diffstat (limited to 'content/common/gpu/image_transport_surface_fbo_mac.mm')
-rw-r--r--content/common/gpu/image_transport_surface_fbo_mac.mm338
1 files changed, 338 insertions, 0 deletions
diff --git a/content/common/gpu/image_transport_surface_fbo_mac.mm b/content/common/gpu/image_transport_surface_fbo_mac.mm
new file mode 100644
index 0000000000..c62205c470
--- /dev/null
+++ b/content/common/gpu/image_transport_surface_fbo_mac.mm
@@ -0,0 +1,338 @@
+// Copyright 2014 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 "content/common/gpu/image_transport_surface_fbo_mac.h"
+
+#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/image_transport_surface_calayer_mac.h"
+#include "content/common/gpu/image_transport_surface_iosurface_mac.h"
+#include "ui/base/cocoa/remote_layer_api.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface_osmesa.h"
+
+namespace content {
+
+ImageTransportSurfaceFBO::ImageTransportSurfaceFBO(
+ GpuChannelManager* manager,
+ GpuCommandBufferStub* stub,
+ gfx::PluginWindowHandle handle)
+ : backbuffer_suggested_allocation_(true),
+ frontbuffer_suggested_allocation_(true),
+ fbo_id_(0),
+ texture_id_(0),
+ depth_stencil_renderbuffer_id_(0),
+ has_complete_framebuffer_(false),
+ context_(NULL),
+ scale_factor_(1.f),
+ made_current_(false),
+ is_swap_buffers_pending_(false),
+ did_unschedule_(false) {
+ if (ui::RemoteLayerAPISupported())
+ storage_provider_.reset(new CALayerStorageProvider(this));
+ else
+ storage_provider_.reset(new IOSurfaceStorageProvider(this));
+ helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
+}
+
+ImageTransportSurfaceFBO::~ImageTransportSurfaceFBO() {
+}
+
+bool ImageTransportSurfaceFBO::Initialize() {
+ // Only support IOSurfaces 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 &&
+ gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL)
+ return false;
+
+ if (!helper_->Initialize())
+ return false;
+
+ helper_->stub()->AddDestructionObserver(this);
+ return true;
+}
+
+void ImageTransportSurfaceFBO::Destroy() {
+ DestroyFramebuffer();
+
+ helper_->Destroy();
+}
+
+bool ImageTransportSurfaceFBO::DeferDraws() {
+ // The command buffer hit a draw/clear command that could clobber the
+ // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort
+ // processing of the command by returning true and unschedule until the Swap
+ // Ack arrives.
+ if(did_unschedule_)
+ return true; // Still unscheduled, so just return true.
+ if (is_swap_buffers_pending_) {
+ did_unschedule_ = true;
+ helper_->SetScheduled(false);
+ return true;
+ }
+ return false;
+}
+
+bool ImageTransportSurfaceFBO::IsOffscreen() {
+ return false;
+}
+
+bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) {
+ context_ = context;
+
+ if (made_current_)
+ return true;
+
+ OnResize(gfx::Size(1, 1), 1.f);
+
+ made_current_ = true;
+ return true;
+}
+
+unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() {
+ return fbo_id_;
+}
+
+bool ImageTransportSurfaceFBO::SetBackbufferAllocation(bool allocation) {
+ if (backbuffer_suggested_allocation_ == allocation)
+ return true;
+ backbuffer_suggested_allocation_ = allocation;
+ AdjustBufferAllocation();
+ return true;
+}
+
+void ImageTransportSurfaceFBO::SetFrontbufferAllocation(bool allocation) {
+ if (frontbuffer_suggested_allocation_ == allocation)
+ return;
+ frontbuffer_suggested_allocation_ = allocation;
+ AdjustBufferAllocation();
+}
+
+void ImageTransportSurfaceFBO::AdjustBufferAllocation() {
+ // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is
+ // free'd when both the browser and gpu processes have Unref'd the IOSurface.
+ if (!backbuffer_suggested_allocation_ &&
+ !frontbuffer_suggested_allocation_ &&
+ has_complete_framebuffer_) {
+ DestroyFramebuffer();
+ helper_->Suspend();
+ } else if (backbuffer_suggested_allocation_ && !has_complete_framebuffer_) {
+ CreateFramebuffer();
+ }
+}
+
+bool ImageTransportSurfaceFBO::SwapBuffers() {
+ DCHECK(backbuffer_suggested_allocation_);
+ if (!frontbuffer_suggested_allocation_)
+ return true;
+ glFlush();
+
+ GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
+ params.surface_handle = storage_provider_->GetSurfaceHandle();
+ params.size = GetSize();
+ params.scale_factor = scale_factor_;
+ params.latency_info.swap(latency_info_);
+ helper_->SendAcceleratedSurfaceBuffersSwapped(params);
+
+ DCHECK(!is_swap_buffers_pending_);
+ is_swap_buffers_pending_ = true;
+
+ storage_provider_->WillSwapBuffers();
+ return true;
+}
+
+bool ImageTransportSurfaceFBO::PostSubBuffer(
+ int x, int y, int width, int height) {
+ // Mac does not support sub-buffer swaps.
+ NOTREACHED();
+ return false;
+}
+
+bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() {
+ return true;
+}
+
+gfx::Size ImageTransportSurfaceFBO::GetSize() {
+ return size_;
+}
+
+void* ImageTransportSurfaceFBO::GetHandle() {
+ return NULL;
+}
+
+void* ImageTransportSurfaceFBO::GetDisplay() {
+ return NULL;
+}
+
+void ImageTransportSurfaceFBO::OnBufferPresented(
+ const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
+ context_->share_group()->SetRendererID(params.renderer_id);
+ storage_provider_->CanFreeSwappedBuffer();
+}
+
+void ImageTransportSurfaceFBO::UnblockContextAfterPendingSwap() {
+ DCHECK(is_swap_buffers_pending_);
+ is_swap_buffers_pending_ = false;
+ if (did_unschedule_) {
+ did_unschedule_ = false;
+ helper_->SetScheduled(true);
+ }
+}
+
+void ImageTransportSurfaceFBO::OnResize(gfx::Size size,
+ float scale_factor) {
+ // This trace event is used in gpu_feature_browsertest.cc - the test will need
+ // to be updated if this event is changed or moved.
+ TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::OnResize",
+ "old_width", size_.width(), "new_width", size.width());
+ // Caching |context_| from OnMakeCurrent. It should still be current.
+ DCHECK(context_->IsCurrent(this));
+
+ size_ = size;
+ scale_factor_ = scale_factor;
+
+ CreateFramebuffer();
+}
+
+void ImageTransportSurfaceFBO::SetLatencyInfo(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+ for (size_t i = 0; i < latency_info.size(); i++)
+ latency_info_.push_back(latency_info[i]);
+}
+
+void ImageTransportSurfaceFBO::WakeUpGpu() {
+ NOTIMPLEMENTED();
+}
+
+void ImageTransportSurfaceFBO::OnWillDestroyStub() {
+ helper_->stub()->RemoveDestructionObserver(this);
+ Destroy();
+}
+
+void ImageTransportSurfaceFBO::DestroyFramebuffer() {
+ // If we have resources to destroy, then make sure that we have a current
+ // context which we can use to delete the resources.
+ if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) {
+ DCHECK(gfx::GLContext::GetCurrent() == context_);
+ DCHECK(context_->IsCurrent(this));
+ DCHECK(CGLGetCurrentContext());
+ }
+
+ if (fbo_id_) {
+ glDeleteFramebuffersEXT(1, &fbo_id_);
+ fbo_id_ = 0;
+ }
+
+ if (texture_id_) {
+ glDeleteTextures(1, &texture_id_);
+ texture_id_ = 0;
+ }
+
+ if (depth_stencil_renderbuffer_id_) {
+ glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
+ depth_stencil_renderbuffer_id_ = 0;
+ }
+
+ storage_provider_->FreeColorBufferStorage();
+
+ has_complete_framebuffer_ = false;
+}
+
+void ImageTransportSurfaceFBO::CreateFramebuffer() {
+ gfx::Size new_rounded_size = storage_provider_->GetRoundedSize(size_);
+
+ // Only recreate surface when the rounded up size has changed.
+ if (has_complete_framebuffer_ && new_rounded_size == rounded_size_)
+ return;
+
+ // This trace event is used in gpu_feature_browsertest.cc - the test will need
+ // to be updated if this event is changed or moved.
+ TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::CreateFramebuffer",
+ "width", new_rounded_size.width(),
+ "height", new_rounded_size.height());
+
+ rounded_size_ = new_rounded_size;
+
+ // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
+ // Mac OS X and is required for IOSurface interoperability.
+ GLint previous_texture_id = 0;
+ glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id);
+
+ // Free the old IO Surface first to reduce memory fragmentation.
+ DestroyFramebuffer();
+
+ glGenFramebuffersEXT(1, &fbo_id_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
+
+ glGenTextures(1, &texture_id_);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id_);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_RECTANGLE_ARB,
+ texture_id_,
+ 0);
+
+ // Search through the provided attributes; if the caller has
+ // requested a stencil buffer, try to get one.
+
+ int32 stencil_bits =
+ helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE);
+ if (stencil_bits > 0) {
+ // Create and bind the stencil buffer
+ bool has_packed_depth_stencil =
+ GLSurface::ExtensionsContain(
+ reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
+ "GL_EXT_packed_depth_stencil");
+
+ if (has_packed_depth_stencil) {
+ glGenRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,
+ depth_stencil_renderbuffer_id_);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
+ rounded_size_.width(), rounded_size_.height());
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
+ GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT,
+ depth_stencil_renderbuffer_id_);
+ }
+
+ // If we asked for stencil but the extension isn't present,
+ // it's OK to silently fail; subsequent code will/must check
+ // for the presence of a stencil buffer before attempting to
+ // do stencil-based operations.
+ }
+
+ bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage(
+ static_cast<CGLContextObj>(context_->GetHandle()), texture_id_,
+ rounded_size_, scale_factor_);
+ if (!allocated_color_buffer) {
+ DLOG(ERROR) << "Failed to allocate color buffer storage.";
+ DestroyFramebuffer();
+ return;
+ }
+
+ GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ DLOG(ERROR) << "Framebuffer was incomplete: " << status;
+ DestroyFramebuffer();
+ return;
+ }
+
+ has_complete_framebuffer_ = true;
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, previous_texture_id);
+ // The FBO remains bound for this GL context.
+}
+
+} // namespace content