Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / common / gpu / image_transport_surface_fbo_mac.mm
blob343ee83bfc09647526c2c700ba1e6c8632fd8f22
1 // Copyright 2014 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 #include "content/common/gpu/image_transport_surface_fbo_mac.h"
7 #include "content/common/gpu/gpu_messages.h"
8 #include "content/common/gpu/image_transport_surface_calayer_mac.h"
9 #include "content/common/gpu/image_transport_surface_iosurface_mac.h"
10 #include "ui/base/cocoa/remote_layer_api.h"
11 #include "ui/gfx/native_widget_types.h"
12 #include "ui/gl/gl_context.h"
13 #include "ui/gl/gl_implementation.h"
14 #include "ui/gl/gl_surface_osmesa.h"
16 namespace content {
18 ImageTransportSurfaceFBO::ImageTransportSurfaceFBO(
19     GpuChannelManager* manager,
20     GpuCommandBufferStub* stub,
21     gfx::PluginWindowHandle handle)
22     : backbuffer_suggested_allocation_(true),
23       frontbuffer_suggested_allocation_(true),
24       fbo_id_(0),
25       texture_id_(0),
26       depth_stencil_renderbuffer_id_(0),
27       has_complete_framebuffer_(false),
28       context_(NULL),
29       scale_factor_(1.f),
30       made_current_(false),
31       is_swap_buffers_send_pending_(false) {
32   if (ui::RemoteLayerAPISupported())
33     storage_provider_.reset(new CALayerStorageProvider(this));
34   else
35     storage_provider_.reset(new IOSurfaceStorageProvider(this));
36   helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
39 ImageTransportSurfaceFBO::~ImageTransportSurfaceFBO() {
42 bool ImageTransportSurfaceFBO::Initialize() {
43   // Only support IOSurfaces if the GL implementation is the native desktop GL.
44   // IO surfaces will not work with, for example, OSMesa software renderer
45   // GL contexts.
46   if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL &&
47       gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL)
48     return false;
50   if (!helper_->Initialize())
51     return false;
53   helper_->stub()->AddDestructionObserver(this);
54   return true;
57 void ImageTransportSurfaceFBO::Destroy() {
58   DestroyFramebuffer();
60   helper_->Destroy();
63 bool ImageTransportSurfaceFBO::DeferDraws() {
64   storage_provider_->WillWriteToBackbuffer();
65   // We should not have a pending send when we are drawing the next frame.
66   DCHECK(!is_swap_buffers_send_pending_);
67   return false;
70 bool ImageTransportSurfaceFBO::IsOffscreen() {
71   return false;
74 bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) {
75   context_ = context;
77   if (made_current_)
78     return true;
80   OnResize(gfx::Size(1, 1), 1.f);
82   made_current_ = true;
83   return true;
86 unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() {
87   return fbo_id_;
90 bool ImageTransportSurfaceFBO::SetBackbufferAllocation(bool allocation) {
91   if (backbuffer_suggested_allocation_ == allocation)
92     return true;
93   backbuffer_suggested_allocation_ = allocation;
94   AdjustBufferAllocation();
95   if (!allocation)
96     storage_provider_->DiscardBackbuffer();
97   return true;
100 void ImageTransportSurfaceFBO::SetFrontbufferAllocation(bool allocation) {
101   if (frontbuffer_suggested_allocation_ == allocation)
102     return;
103   frontbuffer_suggested_allocation_ = allocation;
104   AdjustBufferAllocation();
107 void ImageTransportSurfaceFBO::AdjustBufferAllocation() {
108   // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is
109   // free'd when both the browser and gpu processes have Unref'd the IOSurface.
110   if (!backbuffer_suggested_allocation_ &&
111       !frontbuffer_suggested_allocation_ &&
112       has_complete_framebuffer_) {
113     DestroyFramebuffer();
114     helper_->Suspend();
115   } else if (backbuffer_suggested_allocation_ && !has_complete_framebuffer_) {
116     CreateFramebuffer();
117   }
120 bool ImageTransportSurfaceFBO::SwapBuffers() {
121   DCHECK(backbuffer_suggested_allocation_);
122   if (!frontbuffer_suggested_allocation_)
123     return true;
124   glFlush();
126   // It is the responsibility of the storage provider to send the swap IPC.
127   is_swap_buffers_send_pending_ = true;
128   storage_provider_->SwapBuffers(size_, scale_factor_);
129   return true;
132 void ImageTransportSurfaceFBO::SendSwapBuffers(uint64 surface_handle,
133                                                const gfx::Size pixel_size,
134                                                float scale_factor) {
135   GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
136   params.surface_handle = surface_handle;
137   params.size = pixel_size;
138   params.scale_factor = scale_factor;
139   params.latency_info.swap(latency_info_);
140   helper_->SendAcceleratedSurfaceBuffersSwapped(params);
141   is_swap_buffers_send_pending_ = false;
144 bool ImageTransportSurfaceFBO::PostSubBuffer(
145     int x, int y, int width, int height) {
146   // Mac does not support sub-buffer swaps.
147   NOTREACHED();
148   return false;
151 bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() {
152   return true;
155 gfx::Size ImageTransportSurfaceFBO::GetSize() {
156   return size_;
159 void* ImageTransportSurfaceFBO::GetHandle() {
160   return NULL;
163 void* ImageTransportSurfaceFBO::GetDisplay() {
164   return NULL;
167 void ImageTransportSurfaceFBO::OnBufferPresented(
168     const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
169   context_->share_group()->SetRendererID(params.renderer_id);
170   storage_provider_->SwapBuffersAckedByBrowser();
173 void ImageTransportSurfaceFBO::OnResize(gfx::Size size,
174                                         float scale_factor) {
175   TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::OnResize",
176                "old_width", size_.width(), "new_width", size.width());
177   // Caching |context_| from OnMakeCurrent. It should still be current.
178   DCHECK(context_->IsCurrent(this));
180   size_ = size;
181   scale_factor_ = scale_factor;
183   CreateFramebuffer();
186 void ImageTransportSurfaceFBO::SetLatencyInfo(
187     const std::vector<ui::LatencyInfo>& latency_info) {
188   for (size_t i = 0; i < latency_info.size(); i++)
189     latency_info_.push_back(latency_info[i]);
192 void ImageTransportSurfaceFBO::WakeUpGpu() {
193   NOTIMPLEMENTED();
196 void ImageTransportSurfaceFBO::OnWillDestroyStub() {
197   helper_->stub()->RemoveDestructionObserver(this);
198   Destroy();
201 void ImageTransportSurfaceFBO::DestroyFramebuffer() {
202   // If we have resources to destroy, then make sure that we have a current
203   // context which we can use to delete the resources.
204   if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) {
205     DCHECK(gfx::GLContext::GetCurrent() == context_);
206     DCHECK(context_->IsCurrent(this));
207     DCHECK(CGLGetCurrentContext());
208   }
210   if (fbo_id_) {
211     glDeleteFramebuffersEXT(1, &fbo_id_);
212     fbo_id_ = 0;
213   }
215   if (texture_id_) {
216     glDeleteTextures(1, &texture_id_);
217     texture_id_ = 0;
218   }
220   if (depth_stencil_renderbuffer_id_) {
221     glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
222     depth_stencil_renderbuffer_id_ = 0;
223   }
225   storage_provider_->FreeColorBufferStorage();
227   has_complete_framebuffer_ = false;
230 void ImageTransportSurfaceFBO::CreateFramebuffer() {
231   gfx::Size new_rounded_size = storage_provider_->GetRoundedSize(size_);
233   // Only recreate surface when the rounded up size has changed.
234   if (has_complete_framebuffer_ && new_rounded_size == rounded_size_)
235     return;
237   TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::CreateFramebuffer",
238                "width", new_rounded_size.width(),
239                "height", new_rounded_size.height());
241   rounded_size_ = new_rounded_size;
243   // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
244   // Mac OS X and is required for IOSurface interoperability.
245   GLint previous_texture_id = 0;
246   glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id);
248   // Free the old IO Surface first to reduce memory fragmentation.
249   DestroyFramebuffer();
251   glGenFramebuffersEXT(1, &fbo_id_);
252   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
254   glGenTextures(1, &texture_id_);
256   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id_);
257   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
258   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
259   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
260                   GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
261   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
262                   GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
264   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
265                             GL_COLOR_ATTACHMENT0_EXT,
266                             GL_TEXTURE_RECTANGLE_ARB,
267                             texture_id_,
268                             0);
270   // Search through the provided attributes; if the caller has
271   // requested a stencil buffer, try to get one.
273   int32 stencil_bits =
274       helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE);
275   if (stencil_bits > 0) {
276     // Create and bind the stencil buffer
277     bool has_packed_depth_stencil =
278          GLSurface::ExtensionsContain(
279              reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
280                                             "GL_EXT_packed_depth_stencil");
282     if (has_packed_depth_stencil) {
283       glGenRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
284       glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,
285                             depth_stencil_renderbuffer_id_);
286       glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
287                               rounded_size_.width(), rounded_size_.height());
288       glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
289                                   GL_STENCIL_ATTACHMENT_EXT,
290                                   GL_RENDERBUFFER_EXT,
291                                   depth_stencil_renderbuffer_id_);
292     }
294     // If we asked for stencil but the extension isn't present,
295     // it's OK to silently fail; subsequent code will/must check
296     // for the presence of a stencil buffer before attempting to
297     // do stencil-based operations.
298   }
300   bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage(
301       static_cast<CGLContextObj>(context_->GetHandle()), texture_id_,
302       rounded_size_, scale_factor_);
303   if (!allocated_color_buffer) {
304     DLOG(ERROR) << "Failed to allocate color buffer storage.";
305     DestroyFramebuffer();
306     return;
307   }
309   GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
310   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
311     DLOG(ERROR) << "Framebuffer was incomplete: " << status;
312     DestroyFramebuffer();
313     return;
314   }
316   has_complete_framebuffer_ = true;
318   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, previous_texture_id);
319   // The FBO remains bound for this GL context.
322 }  // namespace content