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

Side by Side Diff: content/common/gpu/image_transport_surface_calayer_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_calayer_mac.h"
6
7 #include <IOSurface/IOSurface.h>
8 #include <OpenGL/CGLRenderers.h>
9 #include <OpenGL/CGLIOSurface.h>
10
11 #include "base/command_line.h"
12 #include "base/mac/sdk_forward_declarations.h"
13 #include "base/trace_event/trace_event.h"
14 #include "gpu/config/gpu_info_collector.h"
15 #include "ui/accelerated_widget_mac/surface_handle_types.h"
16 #include "ui/base/cocoa/animation_utils.h"
17 #include "ui/gfx/geometry/dip_util.h"
18 #include "ui/gfx/geometry/size_conversions.h"
19 #include "ui/gl/gl_switches.h"
20 #include "ui/gl/gpu_switching_manager.h"
21 #include "ui/gl/scoped_api.h"
22
23 namespace {
24 const size_t kFramesToKeepCAContextAfterDiscard = 2;
25 const size_t kCanDrawFalsesBeforeSwitchFromAsync = 4;
26 const base::TimeDelta kMinDeltaToSwitchToAsync =
27 base::TimeDelta::FromSecondsD(1. / 15.);
28
29
30 } // namespace
31
32 @interface ImageTransportCAOpenGLLayer : CAOpenGLLayer {
33 content::CALayerStorageProvider* storageProvider_;
34 base::Closure didDrawCallback_;
35
36 // Used to determine if we should use setNeedsDisplay or setAsynchronous to
37 // animate. If the last swap time happened very recently, then
38 // setAsynchronous is used (which allows smooth animation, but comes with the
39 // penalty of the canDrawInCGLContext function waking up the process every
40 // vsync).
41 base::TimeTicks lastSynchronousSwapTime_;
42
43 // A counter that is incremented whenever LayerCanDraw returns false. If this
44 // reaches a threshold, then |layer_| is switched to synchronous drawing to
45 // save CPU work.
46 uint32 canDrawReturnedFalseCount_;
47
48 gfx::Size pixelSize_;
49 }
50
51 - (id)initWithStorageProvider:(content::CALayerStorageProvider*)storageProvider
52 pixelSize:(gfx::Size)pixelSize
53 scaleFactor:(float)scaleFactor;
54 - (void)requestDrawNewFrame;
55 - (void)drawPendingFrameImmediately;
56 - (void)resetStorageProvider;
57 @end
58
59 @implementation ImageTransportCAOpenGLLayer
60
61 - (id)initWithStorageProvider:
62 (content::CALayerStorageProvider*)storageProvider
63 pixelSize:(gfx::Size)pixelSize
64 scaleFactor:(float)scaleFactor {
65 if (self = [super init]) {
66 gfx::Size dipSize = gfx::ConvertSizeToDIP(scaleFactor, pixelSize);
67 [self setContentsScale:scaleFactor];
68 [self setFrame:CGRectMake(0, 0, dipSize.width(), dipSize.height())];
69 storageProvider_ = storageProvider;
70 pixelSize_ = pixelSize;
71 }
72 return self;
73 }
74
75 - (void)requestDrawNewFrame {
76 // This tracing would be more natural to do with a pseudo-thread for each
77 // layer, rather than a counter.
78 // http://crbug.com/366300
79 // A trace value of 2 indicates that there is a pending swap ack. See
80 // canDrawInCGLContext for other value meanings.
81 TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", self, 2);
82
83 if (![self isAsynchronous]) {
84 // Switch to asynchronous drawing only if we get two frames in rapid
85 // succession.
86 base::TimeTicks this_swap_time = base::TimeTicks::Now();
87 base::TimeDelta delta = this_swap_time - lastSynchronousSwapTime_;
88 if (delta <= kMinDeltaToSwitchToAsync) {
89 lastSynchronousSwapTime_ = base::TimeTicks();
90 [self setAsynchronous:YES];
91 } else {
92 lastSynchronousSwapTime_ = this_swap_time;
93 [self setNeedsDisplay];
94 }
95 }
96 }
97
98 - (void)drawPendingFrameImmediately {
99 DCHECK(storageProvider_->LayerHasPendingDraw());
100 if ([self isAsynchronous])
101 [self setAsynchronous:NO];
102 [self setNeedsDisplay];
103 [self displayIfNeeded];
104 }
105
106 - (void)resetStorageProvider {
107 storageProvider_ = NULL;
108 }
109
110 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
111 if (!storageProvider_)
112 return NULL;
113 return CGLRetainPixelFormat(CGLGetPixelFormat(
114 storageProvider_->LayerShareGroupContext()));
115 }
116
117 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
118 if (!storageProvider_)
119 return NULL;
120 CGLContextObj context = NULL;
121 CGLError error = CGLCreateContext(
122 pixelFormat, storageProvider_->LayerShareGroupContext(), &context);
123 if (error != kCGLNoError)
124 LOG(ERROR) << "CGLCreateContext failed with CGL error: " << error;
125 return context;
126 }
127
128 - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
129 pixelFormat:(CGLPixelFormatObj)pixelFormat
130 forLayerTime:(CFTimeInterval)timeInterval
131 displayTime:(const CVTimeStamp*)timeStamp {
132 TRACE_EVENT0("gpu", "CALayerStorageProvider::LayerCanDraw");
133
134 if (!storageProvider_)
135 return NO;
136
137 if (storageProvider_->LayerHasPendingDraw()) {
138 // If there is a draw pending then increase the signal from 2 to 3, to
139 // indicate that there is a swap pending, and CoreAnimation has asked to
140 // draw it.
141 TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", self, 3);
142
143 canDrawReturnedFalseCount_ = 0;
144 return YES;
145 } else {
146 // If there is not a draw pending, then give an instantaneous blip up from
147 // 0 to 1, indicating that CoreAnimation was ready to draw a frame but we
148 // were not (or didn't have new content to draw).
149 TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", self, 1);
150 TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", self, 0);
151
152 if ([self isAsynchronous]) {
153 // If we are in asynchronous mode, we will be getting callbacks at every
154 // vsync, asking us if we have anything to draw. If we get many of these
155 // in a row, ask that we stop getting these callback for now, so that we
156 // don't waste CPU cycles.
157 if (canDrawReturnedFalseCount_ >= kCanDrawFalsesBeforeSwitchFromAsync)
158 [self setAsynchronous:NO];
159 else
160 canDrawReturnedFalseCount_ += 1;
161 }
162 return NO;
163 }
164 }
165
166 - (void)drawInCGLContext:(CGLContextObj)glContext
167 pixelFormat:(CGLPixelFormatObj)pixelFormat
168 forLayerTime:(CFTimeInterval)timeInterval
169 displayTime:(const CVTimeStamp*)timeStamp {
170 // While in this callback, CoreAnimation has set |glContext| to be current.
171 // Ensure that the GL calls that we make are made against the native GL API.
172 gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
173
174 if (storageProvider_) {
175 storageProvider_->LayerDoDraw(gfx::Rect(pixelSize_), false);
176 storageProvider_->LayerUnblockBrowserIfNeeded();
177 // A trace value of 0 indicates that there is no longer a pending swap ack.
178 TRACE_COUNTER_ID1("gpu", "CALayerPendingSwap", self, 0);
179 } else {
180 glClearColor(1, 1, 1, 1);
181 glClear(GL_COLOR_BUFFER_BIT);
182 }
183 [super drawInCGLContext:glContext
184 pixelFormat:pixelFormat
185 forLayerTime:timeInterval
186 displayTime:timeStamp];
187 }
188
189 @end
190
191 namespace content {
192
193 CALayerStorageProvider::CALayerStorageProvider(
194 ImageTransportSurfaceFBO* transport_surface)
195 : transport_surface_(transport_surface),
196 gpu_vsync_disabled_(base::CommandLine::ForCurrentProcess()->HasSwitch(
197 switches::kDisableGpuVsync)),
198 throttling_disabled_(false),
199 has_pending_ack_(false),
200 fbo_texture_(0),
201 fbo_scale_factor_(1),
202 program_(0),
203 vertex_shader_(0),
204 fragment_shader_(0),
205 position_location_(0),
206 tex_location_(0),
207 vertex_buffer_(0),
208 vertex_array_(0),
209 recreate_layer_after_gpu_switch_(false),
210 pending_draw_weak_factory_(this) {
211 ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
212 }
213
214 CALayerStorageProvider::~CALayerStorageProvider() {
215 ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
216 }
217
218 gfx::Size CALayerStorageProvider::GetRoundedSize(gfx::Size size) {
219 return size;
220 }
221
222 bool CALayerStorageProvider::AllocateColorBufferStorage(
223 CGLContextObj context, const base::Closure& context_dirtied_callback,
224 GLuint texture, gfx::Size pixel_size, float scale_factor) {
225 // Allocate an ordinary OpenGL texture to back the FBO.
226 GLenum error;
227 while ((error = glGetError()) != GL_NO_ERROR) {
228 LOG(ERROR) << "OpenGL error hit but ignored before allocating buffer "
229 << "storage: " << error;
230 }
231
232 if (gfx::GetGLImplementation() ==
233 gfx::kGLImplementationDesktopGLCoreProfile) {
234 glTexImage2D(GL_TEXTURE_2D,
235 0,
236 GL_RGBA,
237 pixel_size.width(),
238 pixel_size.height(),
239 0,
240 GL_RGBA,
241 GL_UNSIGNED_BYTE,
242 NULL);
243 glFlush();
244
245 if (!vertex_shader_) {
246 const char* source =
247 "#version 150\n"
248 "in vec4 position;\n"
249 "out vec2 texcoord;\n"
250 "void main() {\n"
251 " texcoord = vec2(position.x, position.y);\n"
252 " gl_Position = vec4(2*position.x-1, 2*position.y-1,\n"
253 " position.z, position.w);\n"
254 "}\n";
255 vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
256 glShaderSource(vertex_shader_, 1, &source, NULL);
257 glCompileShader(vertex_shader_);
258 #if DCHECK_IS_ON()
259 GLint status = GL_FALSE;
260 glGetShaderiv(vertex_shader_, GL_COMPILE_STATUS, &status);
261 DCHECK(status == GL_TRUE);
262 #endif
263 }
264 if (!fragment_shader_) {
265 const char* source =
266 "#version 150\n"
267 "uniform sampler2D tex;\n"
268 "in vec2 texcoord;\n"
269 "out vec4 frag_color;\n"
270 "void main() {\n"
271 " frag_color = texture(tex, texcoord);\n"
272 "}\n";
273 fragment_shader_ = glCreateShader(GL_FRAGMENT_SHADER);
274 glShaderSource(fragment_shader_, 1, &source, NULL);
275 glCompileShader(fragment_shader_);
276 #if DCHECK_IS_ON()
277 GLint status = GL_FALSE;
278 glGetShaderiv(fragment_shader_, GL_COMPILE_STATUS, &status);
279 DCHECK(status == GL_TRUE);
280 #endif
281 }
282 if (!program_) {
283 program_ = glCreateProgram();
284 glAttachShader(program_, vertex_shader_);
285 glAttachShader(program_, fragment_shader_);
286 glBindFragDataLocation(program_, 0, "frag_color");
287 glLinkProgram(program_);
288 #if DCHECK_IS_ON()
289 GLint status = GL_FALSE;
290 glGetProgramiv(program_, GL_LINK_STATUS, &status);
291 DCHECK(status == GL_TRUE);
292 #endif
293 position_location_ = glGetAttribLocation(program_, "position");
294 tex_location_ = glGetUniformLocation(program_, "tex");
295 }
296 if (!vertex_buffer_) {
297 GLfloat vertex_data[24] = {
298 0, 0, 0, 1,
299 1, 0, 0, 1,
300 1, 1, 0, 1,
301 1, 1, 0, 1,
302 0, 1, 0, 1,
303 0, 0, 0, 1,
304 };
305 glGenBuffersARB(1, &vertex_buffer_);
306 // If the allocation path used GLContext::RestoreStateIfDirtiedExternally
307 // as the draw path does, this manual state restoration would not be
308 // necessary.
309 GLint bound_buffer = 0;
310 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bound_buffer);
311 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
312 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data),
313 vertex_data, GL_STATIC_DRAW);
314 glBindBuffer(GL_ARRAY_BUFFER, bound_buffer);
315 }
316 if (!vertex_array_) {
317 // If the allocation path used GLContext::RestoreStateIfDirtiedExternally
318 // as the draw path does, this manual state restoration would not be
319 // necessary.
320 GLint bound_vao = 0;
321 glGetIntegerv(GL_VERTEX_ARRAY_BINDING_OES, &bound_vao);
322 glGenVertexArraysOES(1, &vertex_array_);
323 glBindVertexArrayOES(vertex_array_);
324 {
325 glEnableVertexAttribArray(position_location_);
326 GLint bound_buffer = 0;
327 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &bound_buffer);
328 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
329 glVertexAttribPointer(position_location_, 4, GL_FLOAT, GL_FALSE, 0, 0);
330 glBindBuffer(GL_ARRAY_BUFFER, bound_buffer);
331 }
332 glBindVertexArrayOES(bound_vao);
333 }
334 } else {
335 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
336 0,
337 GL_RGBA,
338 pixel_size.width(),
339 pixel_size.height(),
340 0,
341 GL_RGBA,
342 GL_UNSIGNED_BYTE,
343 NULL);
344 glFlush();
345 }
346
347 bool hit_error = false;
348 while ((error = glGetError()) != GL_NO_ERROR) {
349 LOG(ERROR) << "OpenGL error hit while trying to allocate buffer storage: "
350 << error;
351 hit_error = true;
352 }
353 if (hit_error)
354 return false;
355
356 // Set the parameters that will be used to allocate the CALayer to draw the
357 // texture into.
358 share_group_context_.reset(CGLRetainContext(context));
359 share_group_context_dirtied_callback_ = context_dirtied_callback;
360 fbo_texture_ = texture;
361 fbo_pixel_size_ = pixel_size;
362 fbo_scale_factor_ = scale_factor;
363 return true;
364 }
365
366 void CALayerStorageProvider::FreeColorBufferStorage() {
367 if (gfx::GetGLImplementation() ==
368 gfx::kGLImplementationDesktopGLCoreProfile) {
369 if (vertex_shader_)
370 glDeleteShader(vertex_shader_);
371 if (fragment_shader_)
372 glDeleteShader(fragment_shader_);
373 if (program_)
374 glDeleteProgram(program_);
375 if (vertex_buffer_)
376 glDeleteBuffersARB(1, &vertex_buffer_);
377 if (vertex_array_)
378 glDeleteVertexArraysOES(1, &vertex_array_);
379 vertex_shader_ = 0;
380 fragment_shader_ = 0;
381 program_ = 0;
382 vertex_buffer_ = 0;
383 vertex_array_ = 0;
384 }
385
386 // Note that |context_| still holds a reference to |layer_|, and will until
387 // a new frame is swapped in.
388 ResetLayer();
389
390 share_group_context_.reset();
391 share_group_context_dirtied_callback_ = base::Closure();
392 fbo_texture_ = 0;
393 fbo_pixel_size_ = gfx::Size();
394 }
395
396 void CALayerStorageProvider::FrameSizeChanged(const gfx::Size& pixel_size,
397 float scale_factor) {
398 DCHECK_EQ(fbo_pixel_size_.ToString(), pixel_size.ToString());
399 DCHECK_EQ(fbo_scale_factor_, scale_factor);
400 }
401
402 void CALayerStorageProvider::SwapBuffers(const gfx::Rect& dirty_rect) {
403 TRACE_EVENT0("gpu", "CALayerStorageProvider::SwapBuffers");
404 DCHECK(!has_pending_ack_);
405
406 // Recreate the CALayer on the new GPU if a GPU switch has occurred. Note
407 // that the CAContext will retain a reference to the old CALayer until the
408 // call to -[CAContext setLayer:] replaces the old CALayer with the new one.
409 if (recreate_layer_after_gpu_switch_) {
410 ResetLayer();
411 recreate_layer_after_gpu_switch_ = false;
412 }
413
414 // Set the pending draw flag only after potentially destroying the old layer
415 // (otherwise destroying it will un-set the flag).
416 has_pending_ack_ = true;
417
418 // Allocate a CAContext to use to transport the CALayer to the browser
419 // process, if needed.
420 if (!context_) {
421 base::scoped_nsobject<NSDictionary> dict([[NSDictionary alloc] init]);
422 CGSConnectionID connection_id = CGSMainConnectionID();
423 context_.reset([CAContext contextWithCGSConnection:connection_id
424 options:dict]);
425 [context_ retain];
426 }
427
428 // Create the appropriate CALayer (if needed) and request that it draw.
429 bool should_draw_immediately = gpu_vsync_disabled_ || throttling_disabled_;
430 CreateLayerAndRequestDraw(should_draw_immediately, dirty_rect);
431
432 // CoreAnimation may not call the function to un-block the browser in a
433 // timely manner (or ever). Post a task to force the draw and un-block
434 // the browser (at the next cycle through the run-loop if drawing is to
435 // be immediate, and at a timeout of 1/6th of a second otherwise).
436 if (has_pending_ack_) {
437 base::MessageLoop::current()->PostDelayedTask(
438 FROM_HERE,
439 base::Bind(&CALayerStorageProvider::DrawImmediatelyAndUnblockBrowser,
440 pending_draw_weak_factory_.GetWeakPtr()),
441 should_draw_immediately ? base::TimeDelta() :
442 base::TimeDelta::FromSeconds(1) / 6);
443 }
444 }
445
446 void CALayerStorageProvider::CreateLayerAndRequestDraw(
447 bool should_draw_immediately, const gfx::Rect& dirty_rect) {
448 if (!ca_opengl_layer_) {
449 ca_opengl_layer_.reset([[ImageTransportCAOpenGLLayer alloc]
450 initWithStorageProvider:this
451 pixelSize:fbo_pixel_size_
452 scaleFactor:fbo_scale_factor_]);
453 }
454
455 // -[CAOpenGLLayer drawInCGLContext] won't get called until we're in the
456 // visible layer hierarchy, so call setLayer: immediately, to make this
457 // happen.
458 [context_ setLayer:ca_opengl_layer_];
459
460 // Tell CoreAnimation to draw our frame. Note that sometimes, calling
461 // -[CAContext setLayer:] will result in the layer getting an immediate
462 // draw. If that happend, we're done.
463 if (!should_draw_immediately && has_pending_ack_) {
464 [ca_opengl_layer_ requestDrawNewFrame];
465 }
466 }
467
468 void CALayerStorageProvider::DrawImmediatelyAndUnblockBrowser() {
469 DCHECK(has_pending_ack_);
470
471 if (ca_opengl_layer_) {
472 // Beware that sometimes, the setNeedsDisplay+displayIfNeeded pairs have no
473 // effect. This can happen if the NSView that this layer is attached to
474 // isn't in the window hierarchy (e.g, tab capture of a backgrounded tab).
475 // In this case, the frame will never be seen, so drop it.
476 [ca_opengl_layer_ drawPendingFrameImmediately];
477 }
478
479 UnblockBrowserIfNeeded();
480 }
481
482 void CALayerStorageProvider::WillWriteToBackbuffer() {
483 // The browser should always throttle itself so that there are no pending
484 // draws when the output surface is written to, but in the event of things
485 // like context lost, or changing context, this will not be true. If there
486 // exists a pending draw, flush it immediately to maintain a consistent
487 // state.
488 if (has_pending_ack_)
489 DrawImmediatelyAndUnblockBrowser();
490 }
491
492 void CALayerStorageProvider::DiscardBackbuffer() {
493 // If this surface's backbuffer is discarded, it is because this surface has
494 // been made non-visible. Ensure that the previous contents are not briefly
495 // flashed when this is made visible by creating a new CALayer and CAContext
496 // at the next swap.
497 ResetLayer();
498
499 // If we remove all references to the CAContext in this process, it will be
500 // blanked-out in the browser process (even if the browser process is inside
501 // a disable screen updates block). Ensure that the context is kept around
502 // until a fixed number of frames (determined empirically) have been acked.
503 // http://crbug.com/425819
504 while (previously_discarded_contexts_.size() <
505 kFramesToKeepCAContextAfterDiscard) {
506 previously_discarded_contexts_.push_back(
507 base::scoped_nsobject<CAContext>());
508 }
509 previously_discarded_contexts_.push_back(context_);
510
511 context_.reset();
512 }
513
514 void CALayerStorageProvider::SwapBuffersAckedByBrowser(
515 bool disable_throttling) {
516 TRACE_EVENT0("gpu", "CALayerStorageProvider::SwapBuffersAckedByBrowser");
517 throttling_disabled_ = disable_throttling;
518 if (!previously_discarded_contexts_.empty())
519 previously_discarded_contexts_.pop_front();
520 }
521
522 CGLContextObj CALayerStorageProvider::LayerShareGroupContext() {
523 return share_group_context_;
524 }
525
526 base::Closure CALayerStorageProvider::LayerShareGroupContextDirtiedCallback() {
527 return share_group_context_dirtied_callback_;
528 }
529
530 void CALayerStorageProvider::LayerDoDraw(
531 const gfx::Rect& dirty_rect, bool flipped) {
532 TRACE_EVENT0("gpu", "CALayerStorageProvider::LayerDoDraw");
533 if (gfx::GetGLImplementation() ==
534 gfx::kGLImplementationDesktopGLCoreProfile) {
535 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
536 glClearColor(1, 0, 1, 1);
537 glClear(GL_COLOR_BUFFER_BIT);
538 glDisable(GL_BLEND);
539 glDisable(GL_CULL_FACE);
540 glDisable(GL_DEPTH_TEST);
541 glDisable(GL_STENCIL_TEST);
542 glDisable(GL_SCISSOR_TEST);
543
544 DCHECK(glIsProgram(program_));
545 glUseProgram(program_);
546 glBindVertexArrayOES(vertex_array_);
547
548 glActiveTexture(GL_TEXTURE0);
549 glBindTexture(GL_TEXTURE_2D, fbo_texture_);
550 glUniform1i(tex_location_, 0);
551
552 glDisable(GL_CULL_FACE);
553 glDrawArrays(GL_TRIANGLES, 0, 6);
554 glBindVertexArrayOES(0);
555 glUseProgram(0);
556 } else {
557 GLint viewport[4] = {0, 0, 0, 0};
558 glGetIntegerv(GL_VIEWPORT, viewport);
559 gfx::Size viewport_size(viewport[2], viewport[3]);
560
561 // Set the coordinate system to be one-to-one with pixels.
562 glMatrixMode(GL_PROJECTION);
563 glLoadIdentity();
564 if (flipped)
565 glOrtho(0, viewport_size.width(), viewport_size.height(), 0, -1, 1);
566 else
567 glOrtho(0, viewport_size.width(), 0, viewport_size.height(), -1, 1);
568 glMatrixMode(GL_MODELVIEW);
569 glLoadIdentity();
570
571 // Reset drawing state and draw a fullscreen quad.
572 glUseProgram(0);
573 glDisable(GL_BLEND);
574 glDisable(GL_CULL_FACE);
575 glDisable(GL_DEPTH_TEST);
576 glDisable(GL_STENCIL_TEST);
577 glDisable(GL_SCISSOR_TEST);
578 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
579 glColor4f(1, 1, 1, 1);
580 glActiveTexture(GL_TEXTURE0);
581 glEnable(GL_TEXTURE_RECTANGLE_ARB);
582 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_texture_);
583 glBegin(GL_QUADS);
584 {
585 glTexCoord2f(dirty_rect.x(), dirty_rect.y());
586 glVertex2f(dirty_rect.x(), dirty_rect.y());
587
588 glTexCoord2f(dirty_rect.x(), dirty_rect.bottom());
589 glVertex2f(dirty_rect.x(), dirty_rect.bottom());
590
591 glTexCoord2f(dirty_rect.right(), dirty_rect.bottom());
592 glVertex2f(dirty_rect.right(), dirty_rect.bottom());
593
594 glTexCoord2f(dirty_rect.right(), dirty_rect.y());
595 glVertex2f(dirty_rect.right(), dirty_rect.y());
596 }
597 glEnd();
598 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
599 glDisable(GL_TEXTURE_RECTANGLE_ARB);
600 }
601
602 GLint current_renderer_id = 0;
603 if (CGLGetParameter(CGLGetCurrentContext(),
604 kCGLCPCurrentRendererID,
605 &current_renderer_id) == kCGLNoError) {
606 current_renderer_id &= kCGLRendererIDMatchingMask;
607 transport_surface_->SetRendererID(current_renderer_id);
608 }
609
610 GLenum error;
611 while ((error = glGetError()) != GL_NO_ERROR) {
612 LOG(ERROR) << "OpenGL error hit while drawing frame: " << error;
613 }
614 }
615
616 void CALayerStorageProvider::LayerUnblockBrowserIfNeeded() {
617 UnblockBrowserIfNeeded();
618 }
619
620 bool CALayerStorageProvider::LayerHasPendingDraw() const {
621 return has_pending_ack_;
622 }
623
624 void CALayerStorageProvider::OnGpuSwitched() {
625 recreate_layer_after_gpu_switch_ = true;
626 }
627
628 void CALayerStorageProvider::UnblockBrowserIfNeeded() {
629 if (!has_pending_ack_)
630 return;
631 pending_draw_weak_factory_.InvalidateWeakPtrs();
632 has_pending_ack_ = false;
633 transport_surface_->SendSwapBuffers(
634 ui::SurfaceHandleFromCAContextID([context_ contextId]),
635 fbo_pixel_size_,
636 fbo_scale_factor_);
637 }
638
639 void CALayerStorageProvider::ResetLayer() {
640 if (ca_opengl_layer_) {
641 [ca_opengl_layer_ resetStorageProvider];
642 // If we are providing back-pressure by waiting for a draw, that draw will
643 // now never come, so release the pressure now.
644 UnblockBrowserIfNeeded();
645 ca_opengl_layer_.reset();
646 }
647 }
648
649 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/image_transport_surface_calayer_mac.h ('k') | content/common/gpu/image_transport_surface_fbo_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698