Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: content/common/gpu/image_transport_surface_fbo_mac.mm

Issue 1416363002: Mac: Always use surfaceless mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add export Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "content/common/gpu/image_transport_surface_fbo_mac.h"
6
7 #include "base/command_line.h"
8 #include "base/trace_event/trace_event.h"
9 #include "content/common/gpu/gpu_messages.h"
10 #include "content/common/gpu/image_transport_surface_calayer_mac.h"
11 #include "content/common/gpu/image_transport_surface_iosurface_mac.h"
12 #include "content/common/gpu/image_transport_surface_overlay_mac.h"
13 #include "ui/base/cocoa/remote_layer_api.h"
14 #include "ui/base/ui_base_switches.h"
15 #include "ui/gfx/native_widget_types.h"
16 #include "ui/gl/gl_context.h"
17 #include "ui/gl/gl_implementation.h"
18 #include "ui/gl/gl_surface_osmesa.h"
19
20 namespace content {
21
22 scoped_refptr<gfx::GLSurface> ImageTransportSurfaceCreateNativeSurface(
23 GpuChannelManager* manager,
24 GpuCommandBufferStub* stub,
25 gfx::PluginWindowHandle handle) {
26 // Overlays should be used unless the remote layer API isn't present (they
27 // depend on it) or it is disabled at the command line.
28 static bool overlays_disabled_at_command_line =
29 base::CommandLine::ForCurrentProcess()->HasSwitch(
30 switches::kDisableMacOverlays);
31 if (ui::RemoteLayerAPISupported() && !overlays_disabled_at_command_line)
32 return new ImageTransportSurfaceOverlayMac(manager, stub, handle);
33 else
34 return new ImageTransportSurfaceFBO(manager, stub, handle);
35 }
36
37 ImageTransportSurfaceFBO::ImageTransportSurfaceFBO(
38 GpuChannelManager* manager,
39 GpuCommandBufferStub* stub,
40 gfx::PluginWindowHandle handle)
41 : backbuffer_suggested_allocation_(true),
42 frontbuffer_suggested_allocation_(true),
43 fbo_id_(0),
44 texture_id_(0),
45 depth_stencil_renderbuffer_id_(0),
46 has_complete_framebuffer_(false),
47 context_(NULL),
48 scale_factor_(1.f),
49 made_current_(false),
50 is_swap_buffers_send_pending_(false) {
51 if (ui::RemoteLayerAPISupported())
52 storage_provider_.reset(new CALayerStorageProvider(this));
53 else
54 storage_provider_.reset(new IOSurfaceStorageProvider(this));
55 helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
56 }
57
58 ImageTransportSurfaceFBO::~ImageTransportSurfaceFBO() {
59 }
60
61 bool ImageTransportSurfaceFBO::Initialize() {
62 // Only support IOSurfaces if the GL implementation is the native desktop GL.
63 // IO surfaces will not work with, for example, OSMesa software renderer
64 // GL contexts.
65 if (gfx::GetGLImplementation() !=
66 gfx::kGLImplementationDesktopGLCoreProfile &&
67 gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL &&
68 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL)
69 return false;
70
71 if (!helper_->Initialize())
72 return false;
73
74 helper_->stub()->AddDestructionObserver(this);
75 return true;
76 }
77
78 void ImageTransportSurfaceFBO::Destroy() {
79 DestroyFramebuffer();
80 }
81
82 bool ImageTransportSurfaceFBO::DeferDraws() {
83 storage_provider_->WillWriteToBackbuffer();
84 // We should not have a pending send when we are drawing the next frame.
85 DCHECK(!is_swap_buffers_send_pending_);
86
87 // The call to WillWriteToBackbuffer could potentially force a draw. Ensure
88 // that any changes made to the context's state are restored.
89 context_->RestoreStateIfDirtiedExternally();
90 return false;
91 }
92
93 bool ImageTransportSurfaceFBO::IsOffscreen() {
94 return false;
95 }
96
97 bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) {
98 context_ = context;
99
100 if (made_current_)
101 return true;
102
103 AllocateOrResizeFramebuffer(gfx::Size(1, 1), 1.f);
104
105 made_current_ = true;
106 return true;
107 }
108
109 void ImageTransportSurfaceFBO::NotifyWasBound() {
110 // Sometimes calling glBindFramebuffer doesn't seem to be enough to get
111 // rendered contents to show up in the color attachment. It appears that doing
112 // a glBegin/End pair with program 0 is enough to tickle the driver into
113 // actually effecting the binding.
114 // http://crbug.com/435786
115 DCHECK(has_complete_framebuffer_);
116
117 // We will restore the current program after the dummy glBegin/End pair.
118 // Ensure that we will be able to restore this state before attempting to
119 // change it.
120 GLint old_program_signed = 0;
121 glGetIntegerv(GL_CURRENT_PROGRAM, &old_program_signed);
122 GLuint old_program = static_cast<GLuint>(old_program_signed);
123 if (old_program && glIsProgram(old_program)) {
124 // A deleted program cannot be re-bound.
125 GLint delete_status = GL_FALSE;
126 glGetProgramiv(old_program, GL_DELETE_STATUS, &delete_status);
127 if (delete_status == GL_TRUE)
128 return;
129 // A program which has had the most recent link fail cannot be re-bound.
130 GLint link_status = GL_FALSE;
131 glGetProgramiv(old_program, GL_LINK_STATUS, &link_status);
132 if (link_status != GL_TRUE)
133 return;
134 }
135
136 // Issue the dummy call and then restore the state.
137 glUseProgram(0);
138 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
139 DCHECK(status == GL_FRAMEBUFFER_COMPLETE);
140 if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) {
141 // These aren't present in the core profile.
142 // TODO(ccameron): verify this workaround isn't still needed with
143 // the core profile.
144 glBegin(GL_TRIANGLES);
145 glEnd();
146 }
147 glUseProgram(old_program);
148 }
149
150 unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() {
151 return fbo_id_;
152 }
153
154 bool ImageTransportSurfaceFBO::SetBackbufferAllocation(bool allocation) {
155 if (backbuffer_suggested_allocation_ == allocation)
156 return true;
157 backbuffer_suggested_allocation_ = allocation;
158 AdjustBufferAllocation();
159 if (!allocation)
160 storage_provider_->DiscardBackbuffer();
161 return true;
162 }
163
164 void ImageTransportSurfaceFBO::SetFrontbufferAllocation(bool allocation) {
165 if (frontbuffer_suggested_allocation_ == allocation)
166 return;
167 frontbuffer_suggested_allocation_ = allocation;
168 AdjustBufferAllocation();
169 }
170
171 void ImageTransportSurfaceFBO::AdjustBufferAllocation() {
172 // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is
173 // free'd when both the browser and gpu processes have Unref'd the IOSurface.
174 if (!backbuffer_suggested_allocation_ &&
175 !frontbuffer_suggested_allocation_ &&
176 has_complete_framebuffer_) {
177 DestroyFramebuffer();
178 } else if (backbuffer_suggested_allocation_ && !has_complete_framebuffer_) {
179 AllocateOrResizeFramebuffer(pixel_size_, scale_factor_);
180 }
181 }
182
183 gfx::SwapResult ImageTransportSurfaceFBO::SwapBuffers() {
184 TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::SwapBuffers");
185 pending_swap_pixel_damage_rect_ = gfx::Rect(pixel_size_);
186 return SwapBuffersInternal(gfx::Rect(pixel_size_)) ?
187 gfx::SwapResult::SWAP_ACK : gfx::SwapResult::SWAP_FAILED;
188 }
189
190 bool ImageTransportSurfaceFBO::SwapBuffersInternal(
191 const gfx::Rect& dirty_rect) {
192 DCHECK(backbuffer_suggested_allocation_);
193 if (!frontbuffer_suggested_allocation_)
194 return true;
195
196 {
197 TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::glFlush");
198 glFlush();
199 }
200
201 // It is the responsibility of the storage provider to send the swap IPC.
202 is_swap_buffers_send_pending_ = true;
203 storage_provider_->SwapBuffers(dirty_rect);
204
205 // The call to swapBuffers could potentially result in an immediate draw.
206 // Ensure that any changes made to the context's state are restored.
207 context_->RestoreStateIfDirtiedExternally();
208 return true;
209 }
210
211 void ImageTransportSurfaceFBO::SendSwapBuffers(uint64 surface_handle,
212 const gfx::Size pixel_size,
213 float scale_factor) {
214 TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::SendSwapBuffers");
215 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
216 params.surface_handle = surface_handle;
217 params.size = pixel_size;
218 params.damage_rect = pending_swap_pixel_damage_rect_;
219 params.scale_factor = scale_factor;
220 params.latency_info.swap(latency_info_);
221 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
222 is_swap_buffers_send_pending_ = false;
223 pending_swap_pixel_damage_rect_ = gfx::Rect();
224 }
225
226 void ImageTransportSurfaceFBO::SetRendererID(int renderer_id) {
227 if (renderer_id)
228 context_->share_group()->SetRendererID(renderer_id);
229 }
230
231 const gpu::gles2::FeatureInfo* ImageTransportSurfaceFBO::GetFeatureInfo()
232 const {
233 return helper_->stub()->GetFeatureInfo();
234 }
235
236 gfx::SwapResult ImageTransportSurfaceFBO::PostSubBuffer(int x,
237 int y,
238 int width,
239 int height) {
240 TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::PostSubBuffer");
241 pending_swap_pixel_damage_rect_.Union(gfx::Rect(x, y, width, height));
242 return SwapBuffersInternal(gfx::Rect(x, y, width, height)) ?
243 gfx::SwapResult::SWAP_ACK : gfx::SwapResult::SWAP_FAILED;
244 }
245
246 bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() {
247 return true;
248 }
249
250 gfx::Size ImageTransportSurfaceFBO::GetSize() {
251 return pixel_size_;
252 }
253
254 void* ImageTransportSurfaceFBO::GetHandle() {
255 return NULL;
256 }
257
258 void* ImageTransportSurfaceFBO::GetDisplay() {
259 return NULL;
260 }
261
262 void ImageTransportSurfaceFBO::OnBufferPresented(
263 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
264 TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::OnBufferPresented");
265 SetRendererID(params.renderer_id);
266 storage_provider_->SwapBuffersAckedByBrowser(params.disable_throttling);
267 }
268
269 void ImageTransportSurfaceFBO::OnResize(gfx::Size pixel_size,
270 float scale_factor) {
271 TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::OnResize",
272 "old_size", pixel_size_.ToString(),
273 "new_size", pixel_size.ToString());
274 // Caching |context_| from OnMakeCurrent. It should still be current.
275 DCHECK(context_->IsCurrent(this));
276
277 AllocateOrResizeFramebuffer(pixel_size, scale_factor);
278 }
279
280 void ImageTransportSurfaceFBO::SetLatencyInfo(
281 const std::vector<ui::LatencyInfo>& latency_info) {
282 for (size_t i = 0; i < latency_info.size(); i++)
283 latency_info_.push_back(latency_info[i]);
284 }
285
286 void ImageTransportSurfaceFBO::OnWillDestroyStub() {
287 helper_->stub()->RemoveDestructionObserver(this);
288 Destroy();
289 }
290
291 void ImageTransportSurfaceFBO::DestroyFramebuffer() {
292 // If we have resources to destroy, then make sure that we have a current
293 // context which we can use to delete the resources.
294 if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) {
295 DCHECK(gfx::GLContext::GetCurrent() == context_);
296 DCHECK(context_->IsCurrent(this));
297 DCHECK(CGLGetCurrentContext());
298 }
299
300 if (fbo_id_) {
301 glDeleteFramebuffersEXT(1, &fbo_id_);
302 fbo_id_ = 0;
303 }
304
305 if (texture_id_) {
306 glDeleteTextures(1, &texture_id_);
307 texture_id_ = 0;
308 }
309
310 if (depth_stencil_renderbuffer_id_) {
311 glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
312 depth_stencil_renderbuffer_id_ = 0;
313 }
314
315 storage_provider_->FreeColorBufferStorage();
316
317 has_complete_framebuffer_ = false;
318 }
319
320 void ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer(
321 const gfx::Size& new_pixel_size, float new_scale_factor) {
322 gfx::Size new_rounded_pixel_size =
323 storage_provider_->GetRoundedSize(new_pixel_size);
324
325 // Only recreate the surface's storage when the rounded up size has changed,
326 // or the scale factor has changed.
327 bool needs_new_storage =
328 !has_complete_framebuffer_ ||
329 new_rounded_pixel_size != rounded_pixel_size_ ||
330 new_scale_factor != scale_factor_;
331
332 // Save the new storage parameters.
333 pixel_size_ = new_pixel_size;
334 rounded_pixel_size_ = new_rounded_pixel_size;
335 scale_factor_ = new_scale_factor;
336
337 if (!needs_new_storage) {
338 storage_provider_->FrameSizeChanged(pixel_size_, scale_factor_);
339 return;
340 }
341
342 TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::AllocateOrResizeFramebuffer",
343 "width", new_rounded_pixel_size.width(),
344 "height", new_rounded_pixel_size.height());
345
346 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
347 // Mac OS X and is required for IOSurface interoperability.
348 GLint previous_texture_id = 0;
349
350 GLenum texture_target = GL_TEXTURE_RECTANGLE_ARB;
351 GLenum texture_binding_target = GL_TEXTURE_BINDING_RECTANGLE_ARB;
352 // However, the remote core animation path on the core profile will
353 // be the preferred combination going forward.
354 if (gfx::GetGLImplementation() ==
355 gfx::kGLImplementationDesktopGLCoreProfile &&
356 ui::RemoteLayerAPISupported()) {
357 texture_target = GL_TEXTURE_2D;
358 texture_binding_target = GL_TEXTURE_BINDING_2D;
359 }
360
361 glGetIntegerv(texture_binding_target, &previous_texture_id);
362
363 // Free the old IO Surface first to reduce memory fragmentation.
364 DestroyFramebuffer();
365
366 glGenFramebuffersEXT(1, &fbo_id_);
367 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_);
368
369 glGenTextures(1, &texture_id_);
370
371 glBindTexture(texture_target, texture_id_);
372 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
373 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
374 glTexParameteri(texture_target,
375 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
376 glTexParameteri(texture_target,
377 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
378
379 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
380 GL_COLOR_ATTACHMENT0_EXT,
381 texture_target,
382 texture_id_,
383 0);
384
385 // Search through the provided attributes; if the caller has
386 // requested a stencil buffer, try to get one.
387
388 int32 stencil_bits =
389 helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE);
390 if (stencil_bits > 0) {
391 // Create and bind the stencil buffer
392 bool has_packed_depth_stencil =
393 GLSurface::ExtensionsContain(
394 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
395 "GL_EXT_packed_depth_stencil");
396
397 if (has_packed_depth_stencil) {
398 glGenRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_);
399 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,
400 depth_stencil_renderbuffer_id_);
401 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
402 rounded_pixel_size_.width(),
403 rounded_pixel_size_.height());
404 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
405 GL_STENCIL_ATTACHMENT_EXT,
406 GL_RENDERBUFFER_EXT,
407 depth_stencil_renderbuffer_id_);
408 }
409
410 // If we asked for stencil but the extension isn't present,
411 // it's OK to silently fail; subsequent code will/must check
412 // for the presence of a stencil buffer before attempting to
413 // do stencil-based operations.
414 }
415
416 bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage(
417 static_cast<CGLContextObj>(
418 context_->GetHandle()),
419 context_->GetStateWasDirtiedExternallyCallback(),
420 texture_id_, rounded_pixel_size_, scale_factor_);
421 if (!allocated_color_buffer) {
422 DLOG(ERROR) << "Failed to allocate color buffer storage.";
423 DestroyFramebuffer();
424 return;
425 }
426
427 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
428 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
429 DLOG(ERROR) << "Framebuffer was incomplete: " << status;
430 DestroyFramebuffer();
431 return;
432 }
433
434 has_complete_framebuffer_ = true;
435 storage_provider_->FrameSizeChanged(pixel_size_, scale_factor_);
436
437 glBindTexture(texture_target, previous_texture_id);
438 // The FBO remains bound for this GL context.
439 }
440
441 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/image_transport_surface_fbo_mac.h ('k') | content/common/gpu/image_transport_surface_iosurface_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698