Apply _RELATIVE relocations ahead of others.
[chromium-blink-merge.git] / content / common / gpu / image_transport_surface_fbo_mac.mm
blob6af794d552ee1360c5dfaee96b8bf2f473ab0555
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();
61 bool ImageTransportSurfaceFBO::DeferDraws() {
62   storage_provider_->WillWriteToBackbuffer();
63   // We should not have a pending send when we are drawing the next frame.
64   DCHECK(!is_swap_buffers_send_pending_);
65   return false;
68 bool ImageTransportSurfaceFBO::IsOffscreen() {
69   return false;
72 bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) {
73   context_ = context;
75   if (made_current_)
76     return true;
78   AllocateOrResizeFramebuffer(gfx::Size(1, 1), 1.f);
80   made_current_ = true;
81   return true;
84 unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() {
85   return fbo_id_;
88 bool ImageTransportSurfaceFBO::SetBackbufferAllocation(bool allocation) {
89   if (backbuffer_suggested_allocation_ == allocation)
90     return true;
91   backbuffer_suggested_allocation_ = allocation;
92   AdjustBufferAllocation();
93   if (!allocation)
94     storage_provider_->DiscardBackbuffer();
95   return true;
98 void ImageTransportSurfaceFBO::SetFrontbufferAllocation(bool allocation) {
99   if (frontbuffer_suggested_allocation_ == allocation)
100     return;
101   frontbuffer_suggested_allocation_ = allocation;
102   AdjustBufferAllocation();
105 void ImageTransportSurfaceFBO::AdjustBufferAllocation() {
106   // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is
107   // free'd when both the browser and gpu processes have Unref'd the IOSurface.
108   if (!backbuffer_suggested_allocation_ &&
109       !frontbuffer_suggested_allocation_ &&
110       has_complete_framebuffer_) {
111     DestroyFramebuffer();
112   } else if (backbuffer_suggested_allocation_ && !has_complete_framebuffer_) {
113     AllocateOrResizeFramebuffer(pixel_size_, scale_factor_);
114   }
117 bool ImageTransportSurfaceFBO::SwapBuffers() {
118   DCHECK(backbuffer_suggested_allocation_);
119   if (!frontbuffer_suggested_allocation_)
120     return true;
121   glFlush();
123   // It is the responsibility of the storage provider to send the swap IPC.
124   is_swap_buffers_send_pending_ = true;
125   storage_provider_->SwapBuffers(pixel_size_, scale_factor_);
126   return true;
129 void ImageTransportSurfaceFBO::SendSwapBuffers(uint64 surface_handle,
130                                                const gfx::Size pixel_size,
131                                                float scale_factor) {
132   GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
133   params.surface_handle = surface_handle;
134   params.size = pixel_size;
135   params.scale_factor = scale_factor;
136   params.latency_info.swap(latency_info_);
137   helper_->SendAcceleratedSurfaceBuffersSwapped(params);
138   is_swap_buffers_send_pending_ = false;
141 void ImageTransportSurfaceFBO::SetRendererID(int renderer_id) {
142   if (renderer_id)
143     context_->share_group()->SetRendererID(renderer_id);
146 bool ImageTransportSurfaceFBO::PostSubBuffer(
147     int x, int y, int width, int height) {
148   // Mac does not support sub-buffer swaps.
149   NOTREACHED();
150   return false;
153 bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() {
154   return true;
157 gfx::Size ImageTransportSurfaceFBO::GetSize() {
158   return pixel_size_;
161 void* ImageTransportSurfaceFBO::GetHandle() {
162   return NULL;
165 void* ImageTransportSurfaceFBO::GetDisplay() {
166   return NULL;
169 void ImageTransportSurfaceFBO::OnBufferPresented(
170     const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
171   SetRendererID(params.renderer_id);
172   storage_provider_->SwapBuffersAckedByBrowser(params.disable_throttling);
175 void ImageTransportSurfaceFBO::OnResize(gfx::Size pixel_size,
176                                         float scale_factor) {
177   TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::OnResize",
178                "old_size", pixel_size_.ToString(),
179                "new_size", pixel_size.ToString());
180   // Caching |context_| from OnMakeCurrent. It should still be current.
181   DCHECK(context_->IsCurrent(this));
183   AllocateOrResizeFramebuffer(pixel_size, scale_factor);
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::AllocateOrResizeFramebuffer(
231     const gfx::Size& new_pixel_size, float new_scale_factor) {
232   gfx::Size new_rounded_pixel_size =
233       storage_provider_->GetRoundedSize(new_pixel_size);
235   // Only recreate the surface's storage when the rounded up size has changed,
236   // or the scale factor has changed.
237   bool needs_new_storage =
238       !has_complete_framebuffer_ ||
239       new_rounded_pixel_size != rounded_pixel_size_ ||
240       new_scale_factor != scale_factor_;
242   // Save the new storage parameters.
243   pixel_size_ = new_pixel_size;
244   rounded_pixel_size_ = new_rounded_pixel_size;
245   scale_factor_ = new_scale_factor;
247   if (!needs_new_storage)
248     return;
250   TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer",
251                "width", new_rounded_pixel_size.width(),
252                "height", new_rounded_pixel_size.height());
254   // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
255   // Mac OS X and is required for IOSurface interoperability.
256   GLint previous_texture_id = 0;
257   glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id);
259   // Free the old IO Surface first to reduce memory fragmentation.
260   DestroyFramebuffer();
262   glGenFramebuffersEXT(1, &fbo_id_);
263   glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
265   glGenTextures(1, &texture_id_);
267   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id_);
268   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
270   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
271                   GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
272   glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
273                   GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
275   glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
276                             GL_COLOR_ATTACHMENT0_EXT,
277                             GL_TEXTURE_RECTANGLE_ARB,
278                             texture_id_,
279                             0);
281   // Search through the provided attributes; if the caller has
282   // requested a stencil buffer, try to get one.
284   int32 stencil_bits =
285       helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE);
286   if (stencil_bits > 0) {
287     // Create and bind the stencil buffer
288     bool has_packed_depth_stencil =
289          GLSurface::ExtensionsContain(
290              reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
291                                             "GL_EXT_packed_depth_stencil");
293     if (has_packed_depth_stencil) {
294       glGenRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
295       glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,
296                             depth_stencil_renderbuffer_id_);
297       glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
298                               rounded_pixel_size_.width(),
299                               rounded_pixel_size_.height());
300       glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
301                                   GL_STENCIL_ATTACHMENT_EXT,
302                                   GL_RENDERBUFFER_EXT,
303                                   depth_stencil_renderbuffer_id_);
304     }
306     // If we asked for stencil but the extension isn't present,
307     // it's OK to silently fail; subsequent code will/must check
308     // for the presence of a stencil buffer before attempting to
309     // do stencil-based operations.
310   }
312   bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage(
313       static_cast<CGLContextObj>(context_->GetHandle()), texture_id_,
314       rounded_pixel_size_, scale_factor_);
315   if (!allocated_color_buffer) {
316     DLOG(ERROR) << "Failed to allocate color buffer storage.";
317     DestroyFramebuffer();
318     return;
319   }
321   GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
322   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
323     DLOG(ERROR) << "Framebuffer was incomplete: " << status;
324     DestroyFramebuffer();
325     return;
326   }
328   has_complete_framebuffer_ = true;
330   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, previous_texture_id);
331   // The FBO remains bound for this GL context.
334 }  // namespace content