gl_renderer.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright 2010 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 "cc/output/gl_renderer.h"
6
7#include <algorithm>
8#include <limits>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/debug/trace_event.h"
14#include "base/logging.h"
15#include "base/strings/string_split.h"
16#include "base/strings/string_util.h"
17#include "base/strings/stringprintf.h"
18#include "build/build_config.h"
19#include "cc/base/math_util.h"
20#include "cc/layers/video_layer_impl.h"
21#include "cc/output/compositor_frame.h"
22#include "cc/output/compositor_frame_metadata.h"
23#include "cc/output/context_provider.h"
24#include "cc/output/copy_output_request.h"
25#include "cc/output/geometry_binding.h"
26#include "cc/output/gl_frame_data.h"
27#include "cc/output/output_surface.h"
28#include "cc/output/render_surface_filters.h"
29#include "cc/quads/picture_draw_quad.h"
30#include "cc/quads/render_pass.h"
31#include "cc/quads/stream_video_draw_quad.h"
32#include "cc/quads/texture_draw_quad.h"
33#include "cc/resources/layer_quad.h"
34#include "cc/resources/scoped_resource.h"
35#include "cc/resources/sync_point_helper.h"
36#include "cc/resources/texture_mailbox_deleter.h"
37#include "cc/trees/damage_tracker.h"
38#include "cc/trees/proxy.h"
39#include "cc/trees/single_thread_proxy.h"
40#include "gpu/GLES2/gl2extchromium.h"
41#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
42#include "third_party/khronos/GLES2/gl2.h"
43#include "third_party/khronos/GLES2/gl2ext.h"
44#include "third_party/skia/include/core/SkBitmap.h"
45#include "third_party/skia/include/core/SkColor.h"
46#include "third_party/skia/include/core/SkColorFilter.h"
47#include "third_party/skia/include/core/SkSurface.h"
48#include "third_party/skia/include/gpu/GrContext.h"
49#include "third_party/skia/include/gpu/GrTexture.h"
50#include "third_party/skia/include/gpu/SkGpuDevice.h"
51#include "third_party/skia/include/gpu/SkGrTexturePixelRef.h"
52#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
53#include "ui/gfx/quad_f.h"
54#include "ui/gfx/rect_conversions.h"
55
56using WebKit::WebGraphicsContext3D;
57
58namespace cc {
59
60namespace {
61
62// TODO(epenner): This should probably be moved to output surface.
63//
64// This implements a simple fence based on client side swaps.
65// This is to isolate the ResourceProvider from 'frames' which
66// it shouldn't need to care about, while still allowing us to
67// enforce good texture recycling behavior strictly throughout
68// the compositor (don't recycle a texture while it's in use).
69class SimpleSwapFence : public ResourceProvider::Fence {
70 public:
71  SimpleSwapFence() : has_passed_(false) {}
72  virtual bool HasPassed() OVERRIDE { return has_passed_; }
73  void SetHasPassed() { has_passed_ = true; }
74 private:
75  virtual ~SimpleSwapFence() {}
76  bool has_passed_;
77};
78
79bool NeedsIOSurfaceReadbackWorkaround() {
80#if defined(OS_MACOSX)
81  // This isn't strictly required in DumpRenderTree-mode when Mesa is used,
82  // but it doesn't seem to hurt.
83  return true;
84#else
85  return false;
86#endif
87}
88
89Float4 UVTransform(const TextureDrawQuad* quad) {
90  gfx::PointF uv0 = quad->uv_top_left;
91  gfx::PointF uv1 = quad->uv_bottom_right;
92  Float4 xform = { { uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y() } };
93  if (quad->flipped) {
94    xform.data[1] = 1.0f - xform.data[1];
95    xform.data[3] = -xform.data[3];
96  }
97  return xform;
98}
99
100Float4 PremultipliedColor(SkColor color) {
101  const float factor = 1.0f / 255.0f;
102  const float alpha = SkColorGetA(color) * factor;
103
104  Float4 result = { {
105      SkColorGetR(color) * factor * alpha,
106      SkColorGetG(color) * factor * alpha,
107      SkColorGetB(color) * factor * alpha,
108      alpha
109  } };
110  return result;
111}
112
113// Smallest unit that impact anti-aliasing output. We use this to
114// determine when anti-aliasing is unnecessary.
115const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
116
117}  // anonymous namespace
118
119struct GLRenderer::PendingAsyncReadPixels {
120  PendingAsyncReadPixels() : buffer(0) {}
121
122  scoped_ptr<CopyOutputRequest> copy_request;
123  base::CancelableClosure finished_read_pixels_callback;
124  unsigned buffer;
125
126 private:
127  DISALLOW_COPY_AND_ASSIGN(PendingAsyncReadPixels);
128};
129
130scoped_ptr<GLRenderer> GLRenderer::Create(
131    RendererClient* client,
132    const LayerTreeSettings* settings,
133    OutputSurface* output_surface,
134    ResourceProvider* resource_provider,
135    TextureMailboxDeleter* texture_mailbox_deleter,
136    int highp_threshold_min,
137    bool use_skia_gpu_backend) {
138  scoped_ptr<GLRenderer> renderer(new GLRenderer(client,
139                                                 settings,
140                                                 output_surface,
141                                                 resource_provider,
142                                                 texture_mailbox_deleter,
143                                                 highp_threshold_min));
144  if (!renderer->Initialize())
145    return scoped_ptr<GLRenderer>();
146  if (use_skia_gpu_backend) {
147    renderer->InitializeGrContext();
148    DCHECK(renderer->CanUseSkiaGPUBackend())
149        << "Requested Skia GPU backend, but can't use it.";
150  }
151
152  return renderer.Pass();
153}
154
155GLRenderer::GLRenderer(RendererClient* client,
156                       const LayerTreeSettings* settings,
157                       OutputSurface* output_surface,
158                       ResourceProvider* resource_provider,
159                       TextureMailboxDeleter* texture_mailbox_deleter,
160                       int highp_threshold_min)
161    : DirectRenderer(client, settings, output_surface, resource_provider),
162      offscreen_framebuffer_id_(0),
163      shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)),
164      context_(output_surface->context_provider()->Context3d()),
165      texture_mailbox_deleter_(texture_mailbox_deleter),
166      is_backbuffer_discarded_(false),
167      discard_backbuffer_when_not_visible_(false),
168      is_using_bind_uniform_(false),
169      visible_(true),
170      is_scissor_enabled_(false),
171      stencil_shadow_(false),
172      blend_shadow_(false),
173      highp_threshold_min_(highp_threshold_min),
174      highp_threshold_cache_(0),
175      offscreen_context_labelled_(false),
176      on_demand_tile_raster_resource_id_(0) {
177  DCHECK(context_);
178}
179
180bool GLRenderer::Initialize() {
181  if (!context_->makeContextCurrent())
182    return false;
183
184  std::string unique_context_name =
185      base::StringPrintf("%s-%p", settings_->compositor_name.c_str(), context_);
186  context_->pushGroupMarkerEXT(unique_context_name.c_str());
187
188  ContextProvider::Capabilities context_caps =
189    output_surface_->context_provider()->ContextCapabilities();
190
191  capabilities_.using_partial_swap =
192      settings_->partial_swap_enabled && context_caps.post_sub_buffer;
193
194  capabilities_.using_set_visibility = context_caps.set_visibility;
195
196  DCHECK(!context_caps.iosurface || context_caps.texture_rectangle);
197
198  capabilities_.using_egl_image = context_caps.egl_image_external;
199
200  capabilities_.max_texture_size = resource_provider_->max_texture_size();
201  capabilities_.best_texture_format = resource_provider_->best_texture_format();
202
203  // The updater can access textures while the GLRenderer is using them.
204  capabilities_.allow_partial_texture_updates = true;
205
206  // Check for texture fast paths. Currently we always use MO8 textures,
207  // so we only need to avoid POT textures if we have an NPOT fast-path.
208  capabilities_.avoid_pow2_textures = context_caps.fast_npot_mo8_textures;
209
210  capabilities_.using_offscreen_context3d = true;
211
212  capabilities_.using_map_image =
213      settings_->use_map_image && context_caps.map_image;
214
215  capabilities_.using_discard_framebuffer =
216      context_caps.discard_framebuffer;
217
218  is_using_bind_uniform_ = context_caps.bind_uniform_location;
219
220  if (!InitializeSharedObjects())
221    return false;
222
223  // Make sure the viewport and context gets initialized, even if it is to zero.
224  ViewportChanged();
225  return true;
226}
227
228void GLRenderer::InitializeGrContext() {
229  skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(
230      context_->createGrGLInterface());
231  if (!interface)
232    return;
233
234  gr_context_ = skia::AdoptRef(GrContext::Create(
235      kOpenGL_GrBackend,
236      reinterpret_cast<GrBackendContext>(interface.get())));
237  ReinitializeGrCanvas();
238}
239
240GLRenderer::~GLRenderer() {
241  while (!pending_async_read_pixels_.empty()) {
242    PendingAsyncReadPixels* pending_read = pending_async_read_pixels_.back();
243    pending_read->finished_read_pixels_callback.Cancel();
244    pending_async_read_pixels_.pop_back();
245  }
246
247  CleanupSharedObjects();
248}
249
250const RendererCapabilities& GLRenderer::Capabilities() const {
251  return capabilities_;
252}
253
254WebGraphicsContext3D* GLRenderer::Context() { return context_; }
255
256void GLRenderer::DebugGLCall(WebGraphicsContext3D* context,
257                             const char* command,
258                             const char* file,
259                             int line) {
260  unsigned error = context->getError();
261  if (error != GL_NO_ERROR)
262    LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line
263               << "\n\tcommand: " << command << ", error "
264               << static_cast<int>(error) << "\n";
265}
266
267void GLRenderer::SetVisible(bool visible) {
268  if (visible_ == visible)
269    return;
270  visible_ = visible;
271
272  EnforceMemoryPolicy();
273
274  // TODO(jamesr): Replace setVisibilityCHROMIUM() with an extension to
275  // explicitly manage front/backbuffers
276  // crbug.com/116049
277  if (capabilities_.using_set_visibility)
278    context_->setVisibilityCHROMIUM(visible);
279}
280
281void GLRenderer::SendManagedMemoryStats(size_t bytes_visible,
282                                        size_t bytes_visible_and_nearby,
283                                        size_t bytes_allocated) {
284  WebKit::WebGraphicsManagedMemoryStats stats;
285  stats.bytesVisible = bytes_visible;
286  stats.bytesVisibleAndNearby = bytes_visible_and_nearby;
287  stats.bytesAllocated = bytes_allocated;
288  stats.backbufferRequested = !is_backbuffer_discarded_;
289  context_->sendManagedMemoryStatsCHROMIUM(&stats);
290}
291
292void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
293
294void GLRenderer::ViewportChanged() {
295  ReinitializeGrCanvas();
296}
297
298void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
299  // It's unsafe to clear when we have a stencil test because glClear ignores
300  // stencil.
301  if (output_surface_->HasExternalStencilTest() &&
302      frame->current_render_pass == frame->root_render_pass) {
303    DCHECK(!frame->current_render_pass->has_transparent_background);
304    return;
305  }
306
307  if (capabilities_.using_discard_framebuffer) {
308    bool using_default_framebuffer =
309        !current_framebuffer_lock_ &&
310        output_surface_->capabilities().uses_default_gl_framebuffer;
311    GLenum attachments[] = {static_cast<GLenum>(
312        using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)};
313    context_->discardFramebufferEXT(
314        GL_FRAMEBUFFER, arraysize(attachments), attachments);
315  }
316
317  // On DEBUG builds, opaque render passes are cleared to blue to easily see
318  // regions that were not drawn on the screen.
319  if (frame->current_render_pass->has_transparent_background)
320    GLC(context_, context_->clearColor(0, 0, 0, 0));
321  else
322    GLC(context_, context_->clearColor(0, 0, 1, 1));
323
324  bool always_clear = false;
325#ifndef NDEBUG
326  always_clear = true;
327#endif
328  if (always_clear || frame->current_render_pass->has_transparent_background) {
329    GLbitfield clear_bits = GL_COLOR_BUFFER_BIT;
330    // Only the Skia GPU backend uses the stencil buffer.  No need to clear it
331    // otherwise.
332    if (always_clear || CanUseSkiaGPUBackend()) {
333      GLC(context_, context_->clearStencil(0));
334      clear_bits |= GL_STENCIL_BUFFER_BIT;
335    }
336    context_->clear(clear_bits);
337  }
338}
339
340void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) {
341  if (client_->DeviceViewport().IsEmpty())
342    return;
343
344  TRACE_EVENT0("cc", "GLRenderer::DrawLayers");
345
346  MakeContextCurrent();
347
348  ReinitializeGLState();
349}
350
351void GLRenderer::DoNoOp() {
352  GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0));
353  GLC(context_, context_->flush());
354}
355
356void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
357  DCHECK(quad->rect.Contains(quad->visible_rect));
358  if (quad->material != DrawQuad::TEXTURE_CONTENT) {
359    FlushTextureQuadCache();
360  }
361
362  switch (quad->material) {
363    case DrawQuad::INVALID:
364      NOTREACHED();
365      break;
366    case DrawQuad::CHECKERBOARD:
367      DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
368      break;
369    case DrawQuad::DEBUG_BORDER:
370      DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
371      break;
372    case DrawQuad::IO_SURFACE_CONTENT:
373      DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad));
374      break;
375    case DrawQuad::PICTURE_CONTENT:
376      DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad));
377      break;
378    case DrawQuad::RENDER_PASS:
379      DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
380      break;
381    case DrawQuad::SOLID_COLOR:
382      DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
383      break;
384    case DrawQuad::STREAM_VIDEO_CONTENT:
385      DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad));
386      break;
387    case DrawQuad::TEXTURE_CONTENT:
388      EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
389      break;
390    case DrawQuad::TILED_CONTENT:
391      DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
392      break;
393    case DrawQuad::YUV_VIDEO_CONTENT:
394      DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad));
395      break;
396  }
397}
398
399void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
400                                      const CheckerboardDrawQuad* quad) {
401  SetBlendEnabled(quad->ShouldDrawWithBlending());
402
403  const TileCheckerboardProgram* program = GetTileCheckerboardProgram();
404  DCHECK(program && (program->initialized() || IsContextLost()));
405  SetUseProgram(program->program());
406
407  SkColor color = quad->color;
408  GLC(Context(),
409      Context()->uniform4f(program->fragment_shader().color_location(),
410                           SkColorGetR(color) * (1.0f / 255.0f),
411                           SkColorGetG(color) * (1.0f / 255.0f),
412                           SkColorGetB(color) * (1.0f / 255.0f),
413                           1));
414
415  const int checkerboard_width = 16;
416  float frequency = 1.0f / checkerboard_width;
417
418  gfx::Rect tile_rect = quad->rect;
419  float tex_offset_x = tile_rect.x() % checkerboard_width;
420  float tex_offset_y = tile_rect.y() % checkerboard_width;
421  float tex_scale_x = tile_rect.width();
422  float tex_scale_y = tile_rect.height();
423  GLC(Context(),
424      Context()->uniform4f(program->fragment_shader().tex_transform_location(),
425                           tex_offset_x,
426                           tex_offset_y,
427                           tex_scale_x,
428                           tex_scale_y));
429
430  GLC(Context(),
431      Context()->uniform1f(program->fragment_shader().frequency_location(),
432                           frequency));
433
434  SetShaderOpacity(quad->opacity(),
435                   program->fragment_shader().alpha_location());
436  DrawQuadGeometry(frame,
437                   quad->quadTransform(),
438                   quad->rect,
439                   program->vertex_shader().matrix_location());
440}
441
442void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
443                                     const DebugBorderDrawQuad* quad) {
444  SetBlendEnabled(quad->ShouldDrawWithBlending());
445
446  static float gl_matrix[16];
447  const DebugBorderProgram* program = GetDebugBorderProgram();
448  DCHECK(program && (program->initialized() || IsContextLost()));
449  SetUseProgram(program->program());
450
451  // Use the full quad_rect for debug quads to not move the edges based on
452  // partial swaps.
453  gfx::Rect layer_rect = quad->rect;
454  gfx::Transform render_matrix = quad->quadTransform();
455  render_matrix.Translate(0.5f * layer_rect.width() + layer_rect.x(),
456                          0.5f * layer_rect.height() + layer_rect.y());
457  render_matrix.Scale(layer_rect.width(), layer_rect.height());
458  GLRenderer::ToGLMatrix(&gl_matrix[0],
459                         frame->projection_matrix * render_matrix);
460  GLC(Context(),
461      Context()->uniformMatrix4fv(
462          program->vertex_shader().matrix_location(), 1, false, &gl_matrix[0]));
463
464  SkColor color = quad->color;
465  float alpha = SkColorGetA(color) * (1.0f / 255.0f);
466
467  GLC(Context(),
468      Context()->uniform4f(program->fragment_shader().color_location(),
469                           (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
470                           (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
471                           (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
472                           alpha));
473
474  GLC(Context(), Context()->lineWidth(quad->width));
475
476  // The indices for the line are stored in the same array as the triangle
477  // indices.
478  GLC(Context(),
479      Context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0));
480}
481
482static inline SkBitmap ApplyFilters(GLRenderer* renderer,
483                                    ContextProvider* offscreen_contexts,
484                                    const FilterOperations& filters,
485                                    ScopedResource* source_texture_resource) {
486  if (filters.IsEmpty())
487    return SkBitmap();
488
489  if (!offscreen_contexts || !offscreen_contexts->GrContext())
490    return SkBitmap();
491
492  ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
493                                           source_texture_resource->id());
494
495  // Flush the compositor context to ensure that textures there are available
496  // in the shared context.  Do this after locking/creating the compositor
497  // texture.
498  renderer->resource_provider()->Flush();
499
500  // Make sure skia uses the correct GL context.
501  offscreen_contexts->Context3d()->makeContextCurrent();
502
503  // Lazily label this context.
504  renderer->LazyLabelOffscreenContext(offscreen_contexts);
505
506  SkBitmap source =
507      RenderSurfaceFilters::Apply(filters,
508                                  lock.texture_id(),
509                                  source_texture_resource->size(),
510                                  offscreen_contexts->GrContext());
511
512  // Flush skia context so that all the rendered stuff appears on the
513  // texture.
514  offscreen_contexts->GrContext()->flush();
515
516  // Flush the GL context so rendering results from this context are
517  // visible in the compositor's context.
518  offscreen_contexts->Context3d()->flush();
519
520  // Use the compositor's GL context again.
521  renderer->Context()->makeContextCurrent();
522  return source;
523}
524
525static SkBitmap ApplyImageFilter(GLRenderer* renderer,
526                                 ContextProvider* offscreen_contexts,
527                                 gfx::Point origin,
528                                 SkImageFilter* filter,
529                                 ScopedResource* source_texture_resource) {
530  if (!filter)
531    return SkBitmap();
532
533  if (!offscreen_contexts || !offscreen_contexts->GrContext())
534    return SkBitmap();
535
536  ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
537                                           source_texture_resource->id());
538
539  // Flush the compositor context to ensure that textures there are available
540  // in the shared context.  Do this after locking/creating the compositor
541  // texture.
542  renderer->resource_provider()->Flush();
543
544  // Make sure skia uses the correct GL context.
545  offscreen_contexts->Context3d()->makeContextCurrent();
546
547  // Lazily label this context.
548  renderer->LazyLabelOffscreenContext(offscreen_contexts);
549
550  // Wrap the source texture in a Ganesh platform texture.
551  GrBackendTextureDesc backend_texture_description;
552  backend_texture_description.fWidth = source_texture_resource->size().width();
553  backend_texture_description.fHeight =
554      source_texture_resource->size().height();
555  backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
556  backend_texture_description.fTextureHandle = lock.texture_id();
557  backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
558  skia::RefPtr<GrTexture> texture =
559      skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
560          backend_texture_description));
561
562  // Place the platform texture inside an SkBitmap.
563  SkBitmap source;
564  source.setConfig(SkBitmap::kARGB_8888_Config,
565                   source_texture_resource->size().width(),
566                   source_texture_resource->size().height());
567  skia::RefPtr<SkGrPixelRef> pixel_ref =
568      skia::AdoptRef(new SkGrPixelRef(texture.get()));
569  source.setPixelRef(pixel_ref.get());
570
571  // Create a scratch texture for backing store.
572  GrTextureDesc desc;
573  desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
574  desc.fSampleCnt = 0;
575  desc.fWidth = source.width();
576  desc.fHeight = source.height();
577  desc.fConfig = kSkia8888_GrPixelConfig;
578  desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
579  GrAutoScratchTexture scratch_texture(
580      offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
581  skia::RefPtr<GrTexture> backing_store =
582      skia::AdoptRef(scratch_texture.detach());
583
584  // Create a device and canvas using that backing store.
585  SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
586  SkCanvas canvas(&device);
587
588  // Draw the source bitmap through the filter to the canvas.
589  SkPaint paint;
590  paint.setImageFilter(filter);
591  canvas.clear(SK_ColorTRANSPARENT);
592
593  // TODO(senorblanco): in addition to the origin translation here, the canvas
594  // should also be scaled to accomodate device pixel ratio and pinch zoom. See
595  // crbug.com/281516 and crbug.com/281518.
596  canvas.translate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
597  canvas.drawSprite(source, 0, 0, &paint);
598
599  // Flush skia context so that all the rendered stuff appears on the
600  // texture.
601  offscreen_contexts->GrContext()->flush();
602
603  // Flush the GL context so rendering results from this context are
604  // visible in the compositor's context.
605  offscreen_contexts->Context3d()->flush();
606
607  // Use the compositor's GL context again.
608  renderer->Context()->makeContextCurrent();
609
610  return device.accessBitmap(false);
611}
612
613scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
614    DrawingFrame* frame,
615    const RenderPassDrawQuad* quad,
616    const gfx::Transform& contents_device_transform,
617    const gfx::Transform& contents_device_transform_inverse) {
618  // This method draws a background filter, which applies a filter to any pixels
619  // behind the quad and seen through its background.  The algorithm works as
620  // follows:
621  // 1. Compute a bounding box around the pixels that will be visible through
622  // the quad.
623  // 2. Read the pixels in the bounding box into a buffer R.
624  // 3. Apply the background filter to R, so that it is applied in the pixels'
625  // coordinate space.
626  // 4. Apply the quad's inverse transform to map the pixels in R into the
627  // quad's content space. This implicitly clips R by the content bounds of the
628  // quad since the destination texture has bounds matching the quad's content.
629  // 5. Draw the background texture for the contents using the same transform as
630  // used to draw the contents itself. This is done without blending to replace
631  // the current background pixels with the new filtered background.
632  // 6. Draw the contents of the quad over drop of the new background with
633  // blending, as per usual. The filtered background pixels will show through
634  // any non-opaque pixels in this draws.
635  //
636  // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
637
638  // TODO(danakj): When this algorithm changes, update
639  // LayerTreeHost::PrioritizeTextures() accordingly.
640
641  FilterOperations filters =
642      RenderSurfaceFilters::Optimize(quad->background_filters);
643  DCHECK(!filters.IsEmpty());
644
645  // TODO(danakj): We only allow background filters on an opaque render surface
646  // because other surfaces may contain translucent pixels, and the contents
647  // behind those translucent pixels wouldn't have the filter applied.
648  if (frame->current_render_pass->has_transparent_background)
649    return scoped_ptr<ScopedResource>();
650  DCHECK(!frame->current_texture);
651
652  // TODO(danakj): Do a single readback for both the surface and replica and
653  // cache the filtered results (once filter textures are not reused).
654  gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
655      contents_device_transform, SharedGeometryQuad().BoundingBox()));
656
657  int top, right, bottom, left;
658  filters.GetOutsets(&top, &right, &bottom, &left);
659  window_rect.Inset(-left, -top, -right, -bottom);
660
661  window_rect.Intersect(
662      MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
663
664  scoped_ptr<ScopedResource> device_background_texture =
665      ScopedResource::create(resource_provider_);
666  if (!device_background_texture->Allocate(window_rect.size(),
667                                           GL_RGB,
668                                           ResourceProvider::TextureUsageAny)) {
669    return scoped_ptr<ScopedResource>();
670  } else {
671    ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
672                                             device_background_texture->id());
673    GetFramebufferTexture(lock.texture_id(),
674                          device_background_texture->format(),
675                          window_rect);
676  }
677
678  SkBitmap filtered_device_background =
679      ApplyFilters(this,
680                   frame->offscreen_context_provider,
681                   filters,
682                   device_background_texture.get());
683  if (!filtered_device_background.getTexture())
684    return scoped_ptr<ScopedResource>();
685
686  GrTexture* texture =
687      reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
688  int filtered_device_background_texture_id = texture->getTextureHandle();
689
690  scoped_ptr<ScopedResource> background_texture =
691      ScopedResource::create(resource_provider_);
692  if (!background_texture->Allocate(quad->rect.size(),
693                                    GL_RGBA,
694                                    ResourceProvider::TextureUsageFramebuffer))
695    return scoped_ptr<ScopedResource>();
696
697  const RenderPass* target_render_pass = frame->current_render_pass;
698  bool using_background_texture =
699      UseScopedTexture(frame, background_texture.get(), quad->rect);
700
701  if (using_background_texture) {
702    // Copy the readback pixels from device to the background texture for the
703    // surface.
704    gfx::Transform device_to_framebuffer_transform;
705    device_to_framebuffer_transform.Translate(
706        quad->rect.width() * 0.5f + quad->rect.x(),
707        quad->rect.height() * 0.5f + quad->rect.y());
708    device_to_framebuffer_transform.Scale(quad->rect.width(),
709                                          quad->rect.height());
710    device_to_framebuffer_transform.PreconcatTransform(
711        contents_device_transform_inverse);
712
713#ifndef NDEBUG
714    GLC(Context(), Context()->clearColor(0, 0, 1, 1));
715    Context()->clear(GL_COLOR_BUFFER_BIT);
716#endif
717
718    // The filtered_deveice_background_texture is oriented the same as the frame
719    // buffer. The transform we are copying with has a vertical flip, as well as
720    // the |device_to_framebuffer_transform|, which cancel each other out. So do
721    // not flip the contents in the shader to maintain orientation.
722    bool flip_vertically = false;
723
724    CopyTextureToFramebuffer(frame,
725                             filtered_device_background_texture_id,
726                             window_rect,
727                             device_to_framebuffer_transform,
728                             flip_vertically);
729  }
730
731  UseRenderPass(frame, target_render_pass);
732
733  if (!using_background_texture)
734    return scoped_ptr<ScopedResource>();
735  return background_texture.Pass();
736}
737
738void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
739                                    const RenderPassDrawQuad* quad) {
740  SetBlendEnabled(quad->ShouldDrawWithBlending());
741
742  CachedResource* contents_texture =
743      render_pass_textures_.get(quad->render_pass_id);
744  if (!contents_texture || !contents_texture->id())
745    return;
746
747  gfx::Transform quad_rect_matrix;
748  QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
749  gfx::Transform contents_device_transform =
750      frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
751  contents_device_transform.FlattenTo2d();
752
753  // Can only draw surface if device matrix is invertible.
754  gfx::Transform contents_device_transform_inverse(
755      gfx::Transform::kSkipInitialization);
756  if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
757    return;
758
759  scoped_ptr<ScopedResource> background_texture;
760  if (!quad->background_filters.IsEmpty()) {
761    // The pixels from the filtered background should completely replace the
762    // current pixel values.
763    bool disable_blending = blend_enabled();
764    if (disable_blending)
765      SetBlendEnabled(false);
766
767    background_texture = DrawBackgroundFilters(
768        frame,
769        quad,
770        contents_device_transform,
771        contents_device_transform_inverse);
772
773    if (disable_blending)
774      SetBlendEnabled(true);
775  }
776
777  // TODO(senorblanco): Cache this value so that we don't have to do it for both
778  // the surface and its replica.  Apply filters to the contents texture.
779  SkBitmap filter_bitmap;
780  SkScalar color_matrix[20];
781  bool use_color_matrix = false;
782  if (quad->filter) {
783    skia::RefPtr<SkColorFilter> cf;
784
785    {
786      SkColorFilter* colorfilter_rawptr = NULL;
787      quad->filter->asColorFilter(&colorfilter_rawptr);
788      cf = skia::AdoptRef(colorfilter_rawptr);
789    }
790
791    if (cf && cf->asColorMatrix(color_matrix) && !quad->filter->getInput(0)) {
792      // We have a single color matrix as a filter; apply it locally
793      // in the compositor.
794      use_color_matrix = true;
795    } else {
796      filter_bitmap = ApplyImageFilter(this,
797                                       frame->offscreen_context_provider,
798                                       quad->rect.origin(),
799                                       quad->filter.get(),
800                                       contents_texture);
801    }
802  } else if (!quad->filters.IsEmpty()) {
803    FilterOperations optimized_filters =
804        RenderSurfaceFilters::Optimize(quad->filters);
805
806    if ((optimized_filters.size() == 1) &&
807        (optimized_filters.at(0).type() == FilterOperation::COLOR_MATRIX)) {
808      memcpy(
809          color_matrix, optimized_filters.at(0).matrix(), sizeof(color_matrix));
810      use_color_matrix = true;
811    } else {
812      filter_bitmap = ApplyFilters(this,
813                                   frame->offscreen_context_provider,
814                                   optimized_filters,
815                                   contents_texture);
816    }
817  }
818
819  // Draw the background texture if there is one.
820  if (background_texture) {
821    DCHECK(background_texture->size() == quad->rect.size());
822    ResourceProvider::ScopedReadLockGL lock(resource_provider_,
823                                            background_texture->id());
824
825    // The background_texture is oriented the same as the frame buffer. The
826    // transform we are copying with has a vertical flip, so flip the contents
827    // in the shader to maintain orientation
828    bool flip_vertically = true;
829
830    CopyTextureToFramebuffer(frame,
831                             lock.texture_id(),
832                             quad->rect,
833                             quad->quadTransform(),
834                             flip_vertically);
835  }
836
837  bool clipped = false;
838  gfx::QuadF device_quad = MathUtil::MapQuad(
839      contents_device_transform, SharedGeometryQuad(), &clipped);
840  LayerQuad device_layer_bounds(gfx::QuadF(device_quad.BoundingBox()));
841  LayerQuad device_layer_edges(device_quad);
842
843  // Use anti-aliasing programs only when necessary.
844  bool use_aa = !clipped &&
845      (!device_quad.IsRectilinear() ||
846       !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(),
847                                         kAntiAliasingEpsilon));
848  if (use_aa) {
849    device_layer_bounds.InflateAntiAliasingDistance();
850    device_layer_edges.InflateAntiAliasingDistance();
851  }
852
853  scoped_ptr<ResourceProvider::ScopedReadLockGL> mask_resource_lock;
854  unsigned mask_texture_id = 0;
855  if (quad->mask_resource_id) {
856    mask_resource_lock.reset(new ResourceProvider::ScopedReadLockGL(
857        resource_provider_, quad->mask_resource_id));
858    mask_texture_id = mask_resource_lock->texture_id();
859  }
860
861  // TODO(danakj): use the background_texture and blend the background in with
862  // this draw instead of having a separate copy of the background texture.
863
864  scoped_ptr<ResourceProvider::ScopedReadLockGL> contents_resource_lock;
865  if (filter_bitmap.getTexture()) {
866    GrTexture* texture =
867        reinterpret_cast<GrTexture*>(filter_bitmap.getTexture());
868    DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context()));
869    Context()->bindTexture(GL_TEXTURE_2D, texture->getTextureHandle());
870  } else {
871    contents_resource_lock = make_scoped_ptr(
872        new ResourceProvider::ScopedSamplerGL(resource_provider_,
873                                              contents_texture->id(),
874                                              GL_TEXTURE_2D,
875                                              GL_LINEAR));
876  }
877
878  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
879      context_, &highp_threshold_cache_, highp_threshold_min_,
880      quad->shared_quad_state->visible_content_rect.bottom_right());
881
882  int shader_quad_location = -1;
883  int shader_edge_location = -1;
884  int shader_viewport_location = -1;
885  int shader_mask_sampler_location = -1;
886  int shader_mask_tex_coord_scale_location = -1;
887  int shader_mask_tex_coord_offset_location = -1;
888  int shader_matrix_location = -1;
889  int shader_alpha_location = -1;
890  int shader_color_matrix_location = -1;
891  int shader_color_offset_location = -1;
892  int shader_tex_transform_location = -1;
893
894  if (use_aa && mask_texture_id && !use_color_matrix) {
895    const RenderPassMaskProgramAA* program =
896        GetRenderPassMaskProgramAA(tex_coord_precision);
897    SetUseProgram(program->program());
898    GLC(Context(),
899        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
900
901    shader_quad_location = program->vertex_shader().quad_location();
902    shader_edge_location = program->vertex_shader().edge_location();
903    shader_viewport_location = program->vertex_shader().viewport_location();
904    shader_mask_sampler_location =
905        program->fragment_shader().mask_sampler_location();
906    shader_mask_tex_coord_scale_location =
907        program->fragment_shader().mask_tex_coord_scale_location();
908    shader_mask_tex_coord_offset_location =
909        program->fragment_shader().mask_tex_coord_offset_location();
910    shader_matrix_location = program->vertex_shader().matrix_location();
911    shader_alpha_location = program->fragment_shader().alpha_location();
912    shader_tex_transform_location =
913        program->vertex_shader().tex_transform_location();
914  } else if (!use_aa && mask_texture_id && !use_color_matrix) {
915    const RenderPassMaskProgram* program =
916        GetRenderPassMaskProgram(tex_coord_precision);
917    SetUseProgram(program->program());
918    GLC(Context(),
919        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
920
921    shader_mask_sampler_location =
922        program->fragment_shader().mask_sampler_location();
923    shader_mask_tex_coord_scale_location =
924        program->fragment_shader().mask_tex_coord_scale_location();
925    shader_mask_tex_coord_offset_location =
926        program->fragment_shader().mask_tex_coord_offset_location();
927    shader_matrix_location = program->vertex_shader().matrix_location();
928    shader_alpha_location = program->fragment_shader().alpha_location();
929    shader_tex_transform_location =
930        program->vertex_shader().tex_transform_location();
931  } else if (use_aa && !mask_texture_id && !use_color_matrix) {
932    const RenderPassProgramAA* program =
933        GetRenderPassProgramAA(tex_coord_precision);
934    SetUseProgram(program->program());
935    GLC(Context(),
936        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
937
938    shader_quad_location = program->vertex_shader().quad_location();
939    shader_edge_location = program->vertex_shader().edge_location();
940    shader_viewport_location = program->vertex_shader().viewport_location();
941    shader_matrix_location = program->vertex_shader().matrix_location();
942    shader_alpha_location = program->fragment_shader().alpha_location();
943    shader_tex_transform_location =
944        program->vertex_shader().tex_transform_location();
945  } else if (use_aa && mask_texture_id && use_color_matrix) {
946    const RenderPassMaskColorMatrixProgramAA* program =
947        GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision);
948    SetUseProgram(program->program());
949    GLC(Context(),
950        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
951
952    shader_matrix_location = program->vertex_shader().matrix_location();
953    shader_quad_location = program->vertex_shader().quad_location();
954    shader_tex_transform_location =
955        program->vertex_shader().tex_transform_location();
956    shader_edge_location = program->vertex_shader().edge_location();
957    shader_viewport_location = program->vertex_shader().viewport_location();
958    shader_alpha_location = program->fragment_shader().alpha_location();
959    shader_mask_sampler_location =
960        program->fragment_shader().mask_sampler_location();
961    shader_mask_tex_coord_scale_location =
962        program->fragment_shader().mask_tex_coord_scale_location();
963    shader_mask_tex_coord_offset_location =
964        program->fragment_shader().mask_tex_coord_offset_location();
965    shader_color_matrix_location =
966        program->fragment_shader().color_matrix_location();
967    shader_color_offset_location =
968        program->fragment_shader().color_offset_location();
969  } else if (use_aa && !mask_texture_id && use_color_matrix) {
970    const RenderPassColorMatrixProgramAA* program =
971        GetRenderPassColorMatrixProgramAA(tex_coord_precision);
972    SetUseProgram(program->program());
973    GLC(Context(),
974        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
975
976    shader_matrix_location = program->vertex_shader().matrix_location();
977    shader_quad_location = program->vertex_shader().quad_location();
978    shader_tex_transform_location =
979        program->vertex_shader().tex_transform_location();
980    shader_edge_location = program->vertex_shader().edge_location();
981    shader_viewport_location = program->vertex_shader().viewport_location();
982    shader_alpha_location = program->fragment_shader().alpha_location();
983    shader_color_matrix_location =
984        program->fragment_shader().color_matrix_location();
985    shader_color_offset_location =
986        program->fragment_shader().color_offset_location();
987  } else if (!use_aa && mask_texture_id && use_color_matrix) {
988    const RenderPassMaskColorMatrixProgram* program =
989        GetRenderPassMaskColorMatrixProgram(tex_coord_precision);
990    SetUseProgram(program->program());
991    GLC(Context(),
992        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
993
994    shader_matrix_location = program->vertex_shader().matrix_location();
995    shader_tex_transform_location =
996        program->vertex_shader().tex_transform_location();
997    shader_mask_sampler_location =
998        program->fragment_shader().mask_sampler_location();
999    shader_mask_tex_coord_scale_location =
1000        program->fragment_shader().mask_tex_coord_scale_location();
1001    shader_mask_tex_coord_offset_location =
1002        program->fragment_shader().mask_tex_coord_offset_location();
1003    shader_alpha_location = program->fragment_shader().alpha_location();
1004    shader_color_matrix_location =
1005        program->fragment_shader().color_matrix_location();
1006    shader_color_offset_location =
1007        program->fragment_shader().color_offset_location();
1008  } else if (!use_aa && !mask_texture_id && use_color_matrix) {
1009    const RenderPassColorMatrixProgram* program =
1010        GetRenderPassColorMatrixProgram(tex_coord_precision);
1011    SetUseProgram(program->program());
1012    GLC(Context(),
1013        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1014
1015    shader_matrix_location = program->vertex_shader().matrix_location();
1016    shader_tex_transform_location =
1017        program->vertex_shader().tex_transform_location();
1018    shader_alpha_location = program->fragment_shader().alpha_location();
1019    shader_color_matrix_location =
1020        program->fragment_shader().color_matrix_location();
1021    shader_color_offset_location =
1022        program->fragment_shader().color_offset_location();
1023  } else {
1024    const RenderPassProgram* program =
1025        GetRenderPassProgram(tex_coord_precision);
1026    SetUseProgram(program->program());
1027    GLC(Context(),
1028        Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1029
1030    shader_matrix_location = program->vertex_shader().matrix_location();
1031    shader_alpha_location = program->fragment_shader().alpha_location();
1032    shader_tex_transform_location =
1033        program->vertex_shader().tex_transform_location();
1034  }
1035  float tex_scale_x =
1036      quad->rect.width() / static_cast<float>(contents_texture->size().width());
1037  float tex_scale_y = quad->rect.height() /
1038                      static_cast<float>(contents_texture->size().height());
1039  DCHECK_LE(tex_scale_x, 1.0f);
1040  DCHECK_LE(tex_scale_y, 1.0f);
1041
1042  DCHECK(shader_tex_transform_location != -1 || IsContextLost());
1043  // Flip the content vertically in the shader, as the RenderPass input
1044  // texture is already oriented the same way as the framebuffer, but the
1045  // projection transform does a flip.
1046  GLC(Context(), Context()->uniform4f(shader_tex_transform_location,
1047                                      0.0f,
1048                                      tex_scale_y,
1049                                      tex_scale_x,
1050                                      -tex_scale_y));
1051
1052  scoped_ptr<ResourceProvider::ScopedReadLockGL> shader_mask_sampler_lock;
1053  if (shader_mask_sampler_location != -1) {
1054    DCHECK_NE(shader_mask_tex_coord_scale_location, 1);
1055    DCHECK_NE(shader_mask_tex_coord_offset_location, 1);
1056    GLC(Context(), Context()->uniform1i(shader_mask_sampler_location, 1));
1057
1058    float mask_tex_scale_x = quad->mask_uv_rect.width() / tex_scale_x;
1059    float mask_tex_scale_y = quad->mask_uv_rect.height() / tex_scale_y;
1060
1061    // Mask textures are oriented vertically flipped relative to the framebuffer
1062    // and the RenderPass contents texture, so we flip the tex coords from the
1063    // RenderPass texture to find the mask texture coords.
1064    GLC(Context(),
1065        Context()->uniform2f(shader_mask_tex_coord_offset_location,
1066                             quad->mask_uv_rect.x(),
1067                             quad->mask_uv_rect.y() + mask_tex_scale_y));
1068    GLC(Context(),
1069        Context()->uniform2f(shader_mask_tex_coord_scale_location,
1070                             mask_tex_scale_x,
1071                             -mask_tex_scale_y));
1072    shader_mask_sampler_lock = make_scoped_ptr(
1073        new ResourceProvider::ScopedSamplerGL(resource_provider_,
1074                                              quad->mask_resource_id,
1075                                              GL_TEXTURE_2D,
1076                                              GL_TEXTURE1,
1077                                              GL_LINEAR));
1078  }
1079
1080  if (shader_edge_location != -1) {
1081    float edge[24];
1082    device_layer_edges.ToFloatArray(edge);
1083    device_layer_bounds.ToFloatArray(&edge[12]);
1084    GLC(Context(), Context()->uniform3fv(shader_edge_location, 8, edge));
1085  }
1086
1087  if (shader_viewport_location != -1) {
1088    float viewport[4] = {
1089      static_cast<float>(viewport_.x()),
1090      static_cast<float>(viewport_.y()),
1091      static_cast<float>(viewport_.width()),
1092      static_cast<float>(viewport_.height()),
1093    };
1094    GLC(Context(),
1095        Context()->uniform4fv(shader_viewport_location, 1, viewport));
1096  }
1097
1098  if (shader_color_matrix_location != -1) {
1099    float matrix[16];
1100    for (int i = 0; i < 4; ++i) {
1101      for (int j = 0; j < 4; ++j)
1102        matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]);
1103    }
1104    GLC(Context(),
1105        Context()->uniformMatrix4fv(
1106            shader_color_matrix_location, 1, false, matrix));
1107  }
1108  static const float kScale = 1.0f / 255.0f;
1109  if (shader_color_offset_location != -1) {
1110    float offset[4];
1111    for (int i = 0; i < 4; ++i)
1112      offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale;
1113
1114    GLC(Context(),
1115        Context()->uniform4fv(shader_color_offset_location, 1, offset));
1116  }
1117
1118  // Map device space quad to surface space. contents_device_transform has no 3d
1119  // component since it was flattened, so we don't need to project.
1120  gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse,
1121                                              device_layer_edges.ToQuadF(),
1122                                              &clipped);
1123
1124  SetShaderOpacity(quad->opacity(), shader_alpha_location);
1125  SetShaderQuadF(surface_quad, shader_quad_location);
1126  DrawQuadGeometry(
1127      frame, quad->quadTransform(), quad->rect, shader_matrix_location);
1128
1129  // Flush the compositor context before the filter bitmap goes out of
1130  // scope, so the draw gets processed before the filter texture gets deleted.
1131  if (filter_bitmap.getTexture())
1132    context_->flush();
1133}
1134
1135struct SolidColorProgramUniforms {
1136  unsigned program;
1137  unsigned matrix_location;
1138  unsigned viewport_location;
1139  unsigned quad_location;
1140  unsigned edge_location;
1141  unsigned color_location;
1142};
1143
1144template<class T>
1145static void SolidColorUniformLocation(T program,
1146                                      SolidColorProgramUniforms* uniforms) {
1147  uniforms->program = program->program();
1148  uniforms->matrix_location = program->vertex_shader().matrix_location();
1149  uniforms->viewport_location = program->vertex_shader().viewport_location();
1150  uniforms->quad_location = program->vertex_shader().quad_location();
1151  uniforms->edge_location = program->vertex_shader().edge_location();
1152  uniforms->color_location = program->fragment_shader().color_location();
1153}
1154
1155// static
1156bool GLRenderer::SetupQuadForAntialiasing(
1157    const gfx::Transform& device_transform,
1158    const DrawQuad* quad,
1159    gfx::QuadF* local_quad,
1160    float edge[24]) {
1161  gfx::Rect tile_rect = quad->visible_rect;
1162
1163  bool clipped = false;
1164  gfx::QuadF device_layer_quad = MathUtil::MapQuad(
1165      device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped);
1166
1167  bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear();
1168  bool is_nearest_rect_within_epsilon = is_axis_aligned_in_target &&
1169      gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(),
1170                                       kAntiAliasingEpsilon);
1171  // AAing clipped quads is not supported by the code yet.
1172  bool use_aa = !clipped && !is_nearest_rect_within_epsilon && quad->IsEdge();
1173  if (!use_aa)
1174    return false;
1175
1176  LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox()));
1177  device_layer_bounds.InflateAntiAliasingDistance();
1178
1179  LayerQuad device_layer_edges(device_layer_quad);
1180  device_layer_edges.InflateAntiAliasingDistance();
1181
1182  device_layer_edges.ToFloatArray(edge);
1183  device_layer_bounds.ToFloatArray(&edge[12]);
1184
1185  gfx::PointF bottom_right = tile_rect.bottom_right();
1186  gfx::PointF bottom_left = tile_rect.bottom_left();
1187  gfx::PointF top_left = tile_rect.origin();
1188  gfx::PointF top_right = tile_rect.top_right();
1189
1190  // Map points to device space.
1191  bottom_right = MathUtil::MapPoint(device_transform, bottom_right, &clipped);
1192  DCHECK(!clipped);
1193  bottom_left = MathUtil::MapPoint(device_transform, bottom_left, &clipped);
1194  DCHECK(!clipped);
1195  top_left = MathUtil::MapPoint(device_transform, top_left, &clipped);
1196  DCHECK(!clipped);
1197  top_right = MathUtil::MapPoint(device_transform, top_right, &clipped);
1198  DCHECK(!clipped);
1199
1200  LayerQuad::Edge bottom_edge(bottom_right, bottom_left);
1201  LayerQuad::Edge left_edge(bottom_left, top_left);
1202  LayerQuad::Edge top_edge(top_left, top_right);
1203  LayerQuad::Edge right_edge(top_right, bottom_right);
1204
1205  // Only apply anti-aliasing to edges not clipped by culling or scissoring.
1206  if (quad->IsTopEdge() && tile_rect.y() == quad->rect.y())
1207    top_edge = device_layer_edges.top();
1208  if (quad->IsLeftEdge() && tile_rect.x() == quad->rect.x())
1209    left_edge = device_layer_edges.left();
1210  if (quad->IsRightEdge() && tile_rect.right() == quad->rect.right())
1211    right_edge = device_layer_edges.right();
1212  if (quad->IsBottomEdge() && tile_rect.bottom() == quad->rect.bottom())
1213    bottom_edge = device_layer_edges.bottom();
1214
1215  float sign = gfx::QuadF(tile_rect).IsCounterClockwise() ? -1 : 1;
1216  bottom_edge.scale(sign);
1217  left_edge.scale(sign);
1218  top_edge.scale(sign);
1219  right_edge.scale(sign);
1220
1221  // Create device space quad.
1222  LayerQuad device_quad(left_edge, top_edge, right_edge, bottom_edge);
1223
1224  // Map device space quad to local space. device_transform has no 3d
1225  // component since it was flattened, so we don't need to project.  We should
1226  // have already checked that the transform was uninvertible above.
1227  gfx::Transform inverse_device_transform(
1228      gfx::Transform::kSkipInitialization);
1229  bool did_invert = device_transform.GetInverse(&inverse_device_transform);
1230  DCHECK(did_invert);
1231  *local_quad = MathUtil::MapQuad(
1232      inverse_device_transform, device_quad.ToQuadF(), &clipped);
1233  // We should not DCHECK(!clipped) here, because anti-aliasing inflation may
1234  // cause device_quad to become clipped. To our knowledge this scenario does
1235  // not need to be handled differently than the unclipped case.
1236
1237  return true;
1238}
1239
1240void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame,
1241                                    const SolidColorDrawQuad* quad) {
1242  gfx::Rect tile_rect = quad->visible_rect;
1243
1244  SkColor color = quad->color;
1245  float opacity = quad->opacity();
1246  float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
1247
1248  // Early out if alpha is small enough that quad doesn't contribute to output.
1249  if (alpha < std::numeric_limits<float>::epsilon() &&
1250      quad->ShouldDrawWithBlending())
1251    return;
1252
1253  gfx::Transform device_transform =
1254      frame->window_matrix * frame->projection_matrix * quad->quadTransform();
1255  device_transform.FlattenTo2d();
1256  if (!device_transform.IsInvertible())
1257    return;
1258
1259  gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect));
1260  float edge[24];
1261  bool use_aa =
1262      settings_->allow_antialiasing && !quad->force_anti_aliasing_off &&
1263      SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge);
1264
1265  SolidColorProgramUniforms uniforms;
1266  if (use_aa)
1267    SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms);
1268  else
1269    SolidColorUniformLocation(GetSolidColorProgram(), &uniforms);
1270  SetUseProgram(uniforms.program);
1271
1272  GLC(Context(),
1273      Context()->uniform4f(uniforms.color_location,
1274                           (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
1275                           (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
1276                           (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
1277                           alpha));
1278  if (use_aa) {
1279    float viewport[4] = {
1280      static_cast<float>(viewport_.x()),
1281      static_cast<float>(viewport_.y()),
1282      static_cast<float>(viewport_.width()),
1283      static_cast<float>(viewport_.height()),
1284    };
1285    GLC(Context(),
1286        Context()->uniform4fv(uniforms.viewport_location, 1, viewport));
1287    GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge));
1288  }
1289
1290  // Enable blending when the quad properties require it or if we decided
1291  // to use antialiasing.
1292  SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
1293
1294  // Normalize to tile_rect.
1295  local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
1296
1297  SetShaderQuadF(local_quad, uniforms.quad_location);
1298
1299  // The transform and vertex data are used to figure out the extents that the
1300  // un-antialiased quad should have and which vertex this is and the float
1301  // quad passed in via uniform is the actual geometry that gets used to draw
1302  // it. This is why this centered rect is used and not the original quad_rect.
1303  gfx::RectF centered_rect(gfx::PointF(-0.5f * tile_rect.width(),
1304                                       -0.5f * tile_rect.height()),
1305                           tile_rect.size());
1306  DrawQuadGeometry(frame, quad->quadTransform(),
1307                   centered_rect, uniforms.matrix_location);
1308}
1309
1310struct TileProgramUniforms {
1311  unsigned program;
1312  unsigned matrix_location;
1313  unsigned viewport_location;
1314  unsigned quad_location;
1315  unsigned edge_location;
1316  unsigned vertex_tex_transform_location;
1317  unsigned sampler_location;
1318  unsigned fragment_tex_transform_location;
1319  unsigned alpha_location;
1320};
1321
1322template <class T>
1323static void TileUniformLocation(T program, TileProgramUniforms* uniforms) {
1324  uniforms->program = program->program();
1325  uniforms->matrix_location = program->vertex_shader().matrix_location();
1326  uniforms->viewport_location = program->vertex_shader().viewport_location();
1327  uniforms->quad_location = program->vertex_shader().quad_location();
1328  uniforms->edge_location = program->vertex_shader().edge_location();
1329  uniforms->vertex_tex_transform_location =
1330      program->vertex_shader().vertex_tex_transform_location();
1331
1332  uniforms->sampler_location = program->fragment_shader().sampler_location();
1333  uniforms->alpha_location = program->fragment_shader().alpha_location();
1334  uniforms->fragment_tex_transform_location =
1335      program->fragment_shader().fragment_tex_transform_location();
1336}
1337
1338void GLRenderer::DrawTileQuad(const DrawingFrame* frame,
1339                              const TileDrawQuad* quad) {
1340  DrawContentQuad(frame, quad, quad->resource_id);
1341}
1342
1343void GLRenderer::DrawContentQuad(const DrawingFrame* frame,
1344                                 const ContentDrawQuadBase* quad,
1345                                 ResourceProvider::ResourceId resource_id) {
1346  gfx::Rect tile_rect = quad->visible_rect;
1347
1348  gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional(
1349      quad->tex_coord_rect, quad->rect, tile_rect);
1350  float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width();
1351  float tex_to_geom_scale_y =
1352      quad->rect.height() / quad->tex_coord_rect.height();
1353
1354  gfx::RectF clamp_geom_rect(tile_rect);
1355  gfx::RectF clamp_tex_rect(tex_coord_rect);
1356  // Clamp texture coordinates to avoid sampling outside the layer
1357  // by deflating the tile region half a texel or half a texel
1358  // minus epsilon for one pixel layers. The resulting clamp region
1359  // is mapped to the unit square by the vertex shader and mapped
1360  // back to normalized texture coordinates by the fragment shader
1361  // after being clamped to 0-1 range.
1362  float tex_clamp_x = std::min(
1363      0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon);
1364  float tex_clamp_y = std::min(
1365      0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon);
1366  float geom_clamp_x = std::min(
1367      tex_clamp_x * tex_to_geom_scale_x,
1368      0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon);
1369  float geom_clamp_y = std::min(
1370      tex_clamp_y * tex_to_geom_scale_y,
1371      0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon);
1372  clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y);
1373  clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y);
1374
1375  // Map clamping rectangle to unit square.
1376  float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width();
1377  float vertex_tex_translate_y =
1378      -clamp_geom_rect.y() / clamp_geom_rect.height();
1379  float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width();
1380  float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height();
1381
1382  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1383      context_, &highp_threshold_cache_, highp_threshold_min_,
1384      quad->texture_size);
1385
1386  // Map to normalized texture coordinates.
1387  gfx::Size texture_size = quad->texture_size;
1388  float fragment_tex_translate_x = clamp_tex_rect.x() / texture_size.width();
1389  float fragment_tex_translate_y = clamp_tex_rect.y() / texture_size.height();
1390  float fragment_tex_scale_x = clamp_tex_rect.width() / texture_size.width();
1391  float fragment_tex_scale_y = clamp_tex_rect.height() / texture_size.height();
1392
1393  gfx::Transform device_transform =
1394      frame->window_matrix * frame->projection_matrix * quad->quadTransform();
1395  device_transform.FlattenTo2d();
1396  if (!device_transform.IsInvertible())
1397    return;
1398
1399  gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect));
1400  float edge[24];
1401  bool use_aa = settings_->allow_antialiasing && SetupQuadForAntialiasing(
1402      device_transform, quad, &local_quad, edge);
1403
1404  TileProgramUniforms uniforms;
1405  if (use_aa) {
1406    if (quad->swizzle_contents) {
1407      TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision),
1408                          &uniforms);
1409    } else {
1410      TileUniformLocation(GetTileProgramAA(tex_coord_precision), &uniforms);
1411    }
1412  } else {
1413    if (quad->ShouldDrawWithBlending()) {
1414      if (quad->swizzle_contents) {
1415        TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision),
1416                            &uniforms);
1417      } else {
1418        TileUniformLocation(GetTileProgram(tex_coord_precision), &uniforms);
1419      }
1420    } else {
1421      if (quad->swizzle_contents) {
1422        TileUniformLocation(GetTileProgramSwizzleOpaque(tex_coord_precision),
1423                            &uniforms);
1424      } else {
1425        TileUniformLocation(GetTileProgramOpaque(tex_coord_precision),
1426                            &uniforms);
1427      }
1428    }
1429  }
1430
1431  SetUseProgram(uniforms.program);
1432  GLC(Context(), Context()->uniform1i(uniforms.sampler_location, 0));
1433  bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
1434  GLenum filter = (use_aa || scaled ||
1435                   !quad->quadTransform().IsIdentityOrIntegerTranslation())
1436                  ? GL_LINEAR
1437                  : GL_NEAREST;
1438  ResourceProvider::ScopedSamplerGL quad_resource_lock(
1439      resource_provider_, resource_id, GL_TEXTURE_2D, filter);
1440
1441  if (use_aa) {
1442    float viewport[4] = {
1443      static_cast<float>(viewport_.x()),
1444      static_cast<float>(viewport_.y()),
1445      static_cast<float>(viewport_.width()),
1446      static_cast<float>(viewport_.height()),
1447    };
1448    GLC(Context(),
1449        Context()->uniform4fv(uniforms.viewport_location, 1, viewport));
1450    GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge));
1451
1452    GLC(Context(),
1453        Context()->uniform4f(uniforms.vertex_tex_transform_location,
1454                             vertex_tex_translate_x,
1455                             vertex_tex_translate_y,
1456                             vertex_tex_scale_x,
1457                             vertex_tex_scale_y));
1458    GLC(Context(),
1459        Context()->uniform4f(uniforms.fragment_tex_transform_location,
1460                             fragment_tex_translate_x,
1461                             fragment_tex_translate_y,
1462                             fragment_tex_scale_x,
1463                             fragment_tex_scale_y));
1464  } else {
1465    // Move fragment shader transform to vertex shader. We can do this while
1466    // still producing correct results as fragment_tex_transform_location
1467    // should always be non-negative when tiles are transformed in a way
1468    // that could result in sampling outside the layer.
1469    vertex_tex_scale_x *= fragment_tex_scale_x;
1470    vertex_tex_scale_y *= fragment_tex_scale_y;
1471    vertex_tex_translate_x *= fragment_tex_scale_x;
1472    vertex_tex_translate_y *= fragment_tex_scale_y;
1473    vertex_tex_translate_x += fragment_tex_translate_x;
1474    vertex_tex_translate_y += fragment_tex_translate_y;
1475
1476    GLC(Context(),
1477        Context()->uniform4f(uniforms.vertex_tex_transform_location,
1478                             vertex_tex_translate_x,
1479                             vertex_tex_translate_y,
1480                             vertex_tex_scale_x,
1481                             vertex_tex_scale_y));
1482  }
1483
1484  // Enable blending when the quad properties require it or if we decided
1485  // to use antialiasing.
1486  SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
1487
1488  // Normalize to tile_rect.
1489  local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
1490
1491  SetShaderOpacity(quad->opacity(), uniforms.alpha_location);
1492  SetShaderQuadF(local_quad, uniforms.quad_location);
1493
1494  // The transform and vertex data are used to figure out the extents that the
1495  // un-antialiased quad should have and which vertex this is and the float
1496  // quad passed in via uniform is the actual geometry that gets used to draw
1497  // it. This is why this centered rect is used and not the original quad_rect.
1498  gfx::RectF centered_rect(
1499      gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
1500      tile_rect.size());
1501  DrawQuadGeometry(
1502      frame, quad->quadTransform(), centered_rect, uniforms.matrix_location);
1503}
1504
1505void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
1506                                  const YUVVideoDrawQuad* quad) {
1507  SetBlendEnabled(quad->ShouldDrawWithBlending());
1508
1509  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1510      context_, &highp_threshold_cache_, highp_threshold_min_,
1511      quad->shared_quad_state->visible_content_rect.bottom_right());
1512
1513  bool use_alpha_plane = quad->a_plane_resource_id != 0;
1514
1515  ResourceProvider::ScopedSamplerGL y_plane_lock(
1516      resource_provider_,
1517      quad->y_plane_resource_id,
1518      GL_TEXTURE_2D,
1519      GL_TEXTURE1,
1520      GL_LINEAR);
1521  ResourceProvider::ScopedSamplerGL u_plane_lock(
1522      resource_provider_,
1523      quad->u_plane_resource_id,
1524      GL_TEXTURE_2D,
1525      GL_TEXTURE2,
1526      GL_LINEAR);
1527  ResourceProvider::ScopedSamplerGL v_plane_lock(
1528      resource_provider_,
1529      quad->v_plane_resource_id,
1530      GL_TEXTURE_2D,
1531      GL_TEXTURE3,
1532      GL_LINEAR);
1533  scoped_ptr<ResourceProvider::ScopedSamplerGL> a_plane_lock;
1534  if (use_alpha_plane) {
1535    a_plane_lock.reset(new ResourceProvider::ScopedSamplerGL(
1536        resource_provider_,
1537        quad->a_plane_resource_id,
1538        GL_TEXTURE_2D,
1539        GL_TEXTURE4,
1540        GL_LINEAR));
1541  }
1542
1543  int tex_scale_location = -1;
1544  int matrix_location = -1;
1545  int y_texture_location = -1;
1546  int u_texture_location = -1;
1547  int v_texture_location = -1;
1548  int a_texture_location = -1;
1549  int yuv_matrix_location = -1;
1550  int yuv_adj_location = -1;
1551  int alpha_location = -1;
1552  if (use_alpha_plane) {
1553    const VideoYUVAProgram* program = GetVideoYUVAProgram(tex_coord_precision);
1554    DCHECK(program && (program->initialized() || IsContextLost()));
1555    SetUseProgram(program->program());
1556    tex_scale_location = program->vertex_shader().tex_scale_location();
1557    matrix_location = program->vertex_shader().matrix_location();
1558    y_texture_location = program->fragment_shader().y_texture_location();
1559    u_texture_location = program->fragment_shader().u_texture_location();
1560    v_texture_location = program->fragment_shader().v_texture_location();
1561    a_texture_location = program->fragment_shader().a_texture_location();
1562    yuv_matrix_location = program->fragment_shader().yuv_matrix_location();
1563    yuv_adj_location = program->fragment_shader().yuv_adj_location();
1564    alpha_location = program->fragment_shader().alpha_location();
1565  } else {
1566    const VideoYUVProgram* program = GetVideoYUVProgram(tex_coord_precision);
1567    DCHECK(program && (program->initialized() || IsContextLost()));
1568    SetUseProgram(program->program());
1569    tex_scale_location = program->vertex_shader().tex_scale_location();
1570    matrix_location = program->vertex_shader().matrix_location();
1571    y_texture_location = program->fragment_shader().y_texture_location();
1572    u_texture_location = program->fragment_shader().u_texture_location();
1573    v_texture_location = program->fragment_shader().v_texture_location();
1574    yuv_matrix_location = program->fragment_shader().yuv_matrix_location();
1575    yuv_adj_location = program->fragment_shader().yuv_adj_location();
1576    alpha_location = program->fragment_shader().alpha_location();
1577  }
1578
1579  GLC(Context(),
1580      Context()->uniform2f(tex_scale_location,
1581                           quad->tex_scale.width(),
1582                           quad->tex_scale.height()));
1583  GLC(Context(), Context()->uniform1i(y_texture_location, 1));
1584  GLC(Context(), Context()->uniform1i(u_texture_location, 2));
1585  GLC(Context(), Context()->uniform1i(v_texture_location, 3));
1586  if (use_alpha_plane)
1587    GLC(Context(), Context()->uniform1i(a_texture_location, 4));
1588
1589  // These values are magic numbers that are used in the transformation from YUV
1590  // to RGB color values.  They are taken from the following webpage:
1591  // http://www.fourcc.org/fccyvrgb.php
1592  float yuv_to_rgb[9] = {
1593      1.164f, 1.164f, 1.164f,
1594      0.0f, -.391f, 2.018f,
1595      1.596f, -.813f, 0.0f,
1596  };
1597  GLC(Context(),
1598      Context()->uniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb));
1599
1600  // These values map to 16, 128, and 128 respectively, and are computed
1601  // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
1602  // They are used in the YUV to RGBA conversion formula:
1603  //   Y - 16   : Gives 16 values of head and footroom for overshooting
1604  //   U - 128  : Turns unsigned U into signed U [-128,127]
1605  //   V - 128  : Turns unsigned V into signed V [-128,127]
1606  float yuv_adjust[3] = { -0.0625f, -0.5f, -0.5f, };
1607  GLC(Context(), Context()->uniform3fv(yuv_adj_location, 1, yuv_adjust));
1608
1609
1610  SetShaderOpacity(quad->opacity(), alpha_location);
1611  DrawQuadGeometry(frame, quad->quadTransform(), quad->rect, matrix_location);
1612}
1613
1614void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame,
1615                                     const StreamVideoDrawQuad* quad) {
1616  SetBlendEnabled(quad->ShouldDrawWithBlending());
1617
1618  static float gl_matrix[16];
1619
1620  DCHECK(capabilities_.using_egl_image);
1621
1622  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1623      context_, &highp_threshold_cache_, highp_threshold_min_,
1624      quad->shared_quad_state->visible_content_rect.bottom_right());
1625
1626  const VideoStreamTextureProgram* program =
1627      GetVideoStreamTextureProgram(tex_coord_precision);
1628  SetUseProgram(program->program());
1629
1630  ToGLMatrix(&gl_matrix[0], quad->matrix);
1631  GLC(Context(),
1632      Context()->uniformMatrix4fv(
1633          program->vertex_shader().tex_matrix_location(), 1, false, gl_matrix));
1634
1635  ResourceProvider::ScopedReadLockGL lock(resource_provider_,
1636                                          quad->resource_id);
1637  DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context()));
1638  GLC(Context(),
1639      Context()->bindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id()));
1640
1641  GLC(Context(),
1642      Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1643
1644  SetShaderOpacity(quad->opacity(),
1645                   program->fragment_shader().alpha_location());
1646  DrawQuadGeometry(frame,
1647                   quad->quadTransform(),
1648                   quad->rect,
1649                   program->vertex_shader().matrix_location());
1650}
1651
1652void GLRenderer::DrawPictureQuadDirectToBackbuffer(
1653    const DrawingFrame* frame,
1654    const PictureDrawQuad* quad) {
1655  DCHECK(CanUseSkiaGPUBackend());
1656  DCHECK_EQ(quad->opacity(), 1.f) << "Need to composite to a bitmap or a "
1657                                     "render surface for non-1 opacity quads";
1658
1659  // TODO(enne): This should be done more lazily / efficiently.
1660  gr_context_->resetContext();
1661
1662  // Reset the canvas matrix to identity because the clip rect is in target
1663  // space.
1664  SkMatrix sk_identity;
1665  sk_identity.setIdentity();
1666  sk_canvas_->setMatrix(sk_identity);
1667
1668  if (is_scissor_enabled_) {
1669    sk_canvas_->clipRect(gfx::RectToSkRect(scissor_rect_),
1670                         SkRegion::kReplace_Op);
1671  } else {
1672    sk_canvas_->clipRect(gfx::RectToSkRect(client_->DeviceViewport()),
1673                         SkRegion::kReplace_Op);
1674  }
1675
1676  gfx::Transform contents_device_transform = frame->window_matrix *
1677    frame->projection_matrix * quad->quadTransform();
1678  contents_device_transform.Translate(quad->rect.x(),
1679                                      quad->rect.y());
1680  contents_device_transform.FlattenTo2d();
1681  SkMatrix sk_device_matrix;
1682  gfx::TransformToFlattenedSkMatrix(contents_device_transform,
1683                                    &sk_device_matrix);
1684  sk_canvas_->setMatrix(sk_device_matrix);
1685
1686  quad->picture_pile->RasterDirect(
1687      sk_canvas_.get(), quad->content_rect, quad->contents_scale, NULL);
1688
1689  // Flush any drawing buffers that have been deferred.
1690  sk_canvas_->flush();
1691
1692  // TODO(enne): This should be done more lazily / efficiently.
1693  ReinitializeGLState();
1694}
1695
1696void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
1697                                 const PictureDrawQuad* quad) {
1698  if (quad->can_draw_direct_to_backbuffer && CanUseSkiaGPUBackend()) {
1699    DrawPictureQuadDirectToBackbuffer(frame, quad);
1700    return;
1701  }
1702
1703  if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() ||
1704      on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) {
1705    on_demand_tile_raster_bitmap_.setConfig(
1706        SkBitmap::kARGB_8888_Config,
1707        quad->texture_size.width(),
1708        quad->texture_size.height());
1709    on_demand_tile_raster_bitmap_.allocPixels();
1710
1711    if (on_demand_tile_raster_resource_id_)
1712      resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
1713
1714    on_demand_tile_raster_resource_id_ = resource_provider_->CreateGLTexture(
1715        quad->texture_size,
1716        GL_RGBA,
1717        GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
1718        GL_CLAMP_TO_EDGE,
1719        ResourceProvider::TextureUsageAny);
1720  }
1721
1722  SkBitmapDevice device(on_demand_tile_raster_bitmap_);
1723  SkCanvas canvas(&device);
1724
1725  quad->picture_pile->RasterToBitmap(&canvas, quad->content_rect,
1726                                     quad->contents_scale, NULL);
1727
1728  resource_provider_->SetPixels(
1729      on_demand_tile_raster_resource_id_,
1730      reinterpret_cast<uint8_t*>(on_demand_tile_raster_bitmap_.getPixels()),
1731      gfx::Rect(quad->texture_size),
1732      gfx::Rect(quad->texture_size),
1733      gfx::Vector2d());
1734
1735  DrawContentQuad(frame, quad, on_demand_tile_raster_resource_id_);
1736}
1737
1738struct TextureProgramBinding {
1739  template <class Program>
1740  void Set(Program* program, WebKit::WebGraphicsContext3D* context) {
1741    DCHECK(program && (program->initialized() || context->isContextLost()));
1742    program_id = program->program();
1743    sampler_location = program->fragment_shader().sampler_location();
1744    matrix_location = program->vertex_shader().matrix_location();
1745    background_color_location =
1746        program->fragment_shader().background_color_location();
1747  }
1748  int program_id;
1749  int sampler_location;
1750  int matrix_location;
1751  int background_color_location;
1752};
1753
1754struct TexTransformTextureProgramBinding : TextureProgramBinding {
1755  template <class Program>
1756  void Set(Program* program, WebKit::WebGraphicsContext3D* context) {
1757    TextureProgramBinding::Set(program, context);
1758    tex_transform_location = program->vertex_shader().tex_transform_location();
1759    vertex_opacity_location =
1760        program->vertex_shader().vertex_opacity_location();
1761  }
1762  int tex_transform_location;
1763  int vertex_opacity_location;
1764};
1765
1766void GLRenderer::FlushTextureQuadCache() {
1767  // Check to see if we have anything to draw.
1768  if (draw_cache_.program_id == 0)
1769    return;
1770
1771  // Set the correct blending mode.
1772  SetBlendEnabled(draw_cache_.needs_blending);
1773
1774  // Bind the program to the GL state.
1775  SetUseProgram(draw_cache_.program_id);
1776
1777  // Bind the correct texture sampler location.
1778  GLC(Context(), Context()->uniform1i(draw_cache_.sampler_location, 0));
1779
1780  // Assume the current active textures is 0.
1781  ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_,
1782                                                 draw_cache_.resource_id);
1783  DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context()));
1784  GLC(Context(),
1785      Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id()));
1786
1787  COMPILE_ASSERT(
1788      sizeof(Float4) == 4 * sizeof(float),  // NOLINT(runtime/sizeof)
1789      struct_is_densely_packed);
1790  COMPILE_ASSERT(
1791      sizeof(Float16) == 16 * sizeof(float),  // NOLINT(runtime/sizeof)
1792      struct_is_densely_packed);
1793
1794  // Upload the tranforms for both points and uvs.
1795  GLC(context_,
1796      context_->uniformMatrix4fv(
1797          static_cast<int>(draw_cache_.matrix_location),
1798          static_cast<int>(draw_cache_.matrix_data.size()),
1799          false,
1800          reinterpret_cast<float*>(&draw_cache_.matrix_data.front())));
1801  GLC(context_,
1802      context_->uniform4fv(
1803          static_cast<int>(draw_cache_.uv_xform_location),
1804          static_cast<int>(draw_cache_.uv_xform_data.size()),
1805          reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front())));
1806
1807  if (draw_cache_.background_color != SK_ColorTRANSPARENT) {
1808    Float4 background_color = PremultipliedColor(draw_cache_.background_color);
1809    GLC(context_,
1810        context_->uniform4fv(
1811            draw_cache_.background_color_location, 1, background_color.data));
1812  }
1813
1814  GLC(context_,
1815      context_->uniform1fv(
1816          static_cast<int>(draw_cache_.vertex_opacity_location),
1817          static_cast<int>(draw_cache_.vertex_opacity_data.size()),
1818          static_cast<float*>(&draw_cache_.vertex_opacity_data.front())));
1819
1820  // Draw the quads!
1821  GLC(context_,
1822      context_->drawElements(GL_TRIANGLES,
1823                             6 * draw_cache_.matrix_data.size(),
1824                             GL_UNSIGNED_SHORT,
1825                             0));
1826
1827  // Clear the cache.
1828  draw_cache_.program_id = 0;
1829  draw_cache_.uv_xform_data.resize(0);
1830  draw_cache_.vertex_opacity_data.resize(0);
1831  draw_cache_.matrix_data.resize(0);
1832}
1833
1834void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
1835                                    const TextureDrawQuad* quad) {
1836  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1837      context_, &highp_threshold_cache_, highp_threshold_min_,
1838      quad->shared_quad_state->visible_content_rect.bottom_right());
1839
1840  // Choose the correct texture program binding
1841  TexTransformTextureProgramBinding binding;
1842  if (quad->premultiplied_alpha) {
1843    if (quad->background_color == SK_ColorTRANSPARENT) {
1844      binding.Set(GetTextureProgram(tex_coord_precision), Context());
1845    } else {
1846      binding.Set(GetTextureBackgroundProgram(tex_coord_precision), Context());
1847    }
1848  } else {
1849    if (quad->background_color == SK_ColorTRANSPARENT) {
1850      binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision),
1851                  Context());
1852    } else {
1853      binding.Set(
1854          GetNonPremultipliedTextureBackgroundProgram(tex_coord_precision),
1855          Context());
1856    }
1857  }
1858
1859  int resource_id = quad->resource_id;
1860
1861  if (draw_cache_.program_id != binding.program_id ||
1862      draw_cache_.resource_id != resource_id ||
1863      draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
1864      draw_cache_.background_color != quad->background_color ||
1865      draw_cache_.matrix_data.size() >= 8) {
1866    FlushTextureQuadCache();
1867    draw_cache_.program_id = binding.program_id;
1868    draw_cache_.resource_id = resource_id;
1869    draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
1870    draw_cache_.background_color = quad->background_color;
1871
1872    draw_cache_.uv_xform_location = binding.tex_transform_location;
1873    draw_cache_.background_color_location = binding.background_color_location;
1874    draw_cache_.vertex_opacity_location = binding.vertex_opacity_location;
1875    draw_cache_.matrix_location = binding.matrix_location;
1876    draw_cache_.sampler_location = binding.sampler_location;
1877  }
1878
1879  // Generate the uv-transform
1880  draw_cache_.uv_xform_data.push_back(UVTransform(quad));
1881
1882  // Generate the vertex opacity
1883  const float opacity = quad->opacity();
1884  draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
1885  draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity);
1886  draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity);
1887  draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity);
1888
1889  // Generate the transform matrix
1890  gfx::Transform quad_rect_matrix;
1891  QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
1892  quad_rect_matrix = frame->projection_matrix * quad_rect_matrix;
1893
1894  Float16 m;
1895  quad_rect_matrix.matrix().asColMajorf(m.data);
1896  draw_cache_.matrix_data.push_back(m);
1897}
1898
1899void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame,
1900                                   const IOSurfaceDrawQuad* quad) {
1901  SetBlendEnabled(quad->ShouldDrawWithBlending());
1902
1903  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1904      context_,  &highp_threshold_cache_, highp_threshold_min_,
1905      quad->shared_quad_state->visible_content_rect.bottom_right());
1906
1907  TexTransformTextureProgramBinding binding;
1908  binding.Set(GetTextureIOSurfaceProgram(tex_coord_precision), Context());
1909
1910  SetUseProgram(binding.program_id);
1911  GLC(Context(), Context()->uniform1i(binding.sampler_location, 0));
1912  if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) {
1913    GLC(Context(),
1914        Context()->uniform4f(binding.tex_transform_location,
1915                             0,
1916                             quad->io_surface_size.height(),
1917                             quad->io_surface_size.width(),
1918                             quad->io_surface_size.height() * -1.0f));
1919  } else {
1920    GLC(Context(),
1921        Context()->uniform4f(binding.tex_transform_location,
1922                             0,
1923                             0,
1924                             quad->io_surface_size.width(),
1925                             quad->io_surface_size.height()));
1926  }
1927
1928  const float vertex_opacity[] = { quad->opacity(), quad->opacity(),
1929                                   quad->opacity(), quad->opacity() };
1930  GLC(Context(),
1931      Context()->uniform1fv(
1932          binding.vertex_opacity_location, 4, vertex_opacity));
1933
1934  ResourceProvider::ScopedReadLockGL lock(resource_provider_,
1935                                          quad->io_surface_resource_id);
1936  DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context()));
1937  GLC(Context(),
1938      Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB,
1939                             lock.texture_id()));
1940
1941  DrawQuadGeometry(
1942      frame, quad->quadTransform(), quad->rect, binding.matrix_location);
1943
1944  GLC(Context(), Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, 0));
1945}
1946
1947void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
1948  current_framebuffer_lock_.reset();
1949  swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect));
1950
1951  GLC(context_, context_->disable(GL_BLEND));
1952  blend_shadow_ = false;
1953}
1954
1955void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); }
1956
1957bool GLRenderer::FlippedFramebuffer() const { return true; }
1958
1959void GLRenderer::EnsureScissorTestEnabled() {
1960  if (is_scissor_enabled_)
1961    return;
1962
1963  FlushTextureQuadCache();
1964  GLC(context_, context_->enable(GL_SCISSOR_TEST));
1965  is_scissor_enabled_ = true;
1966}
1967
1968void GLRenderer::EnsureScissorTestDisabled() {
1969  if (!is_scissor_enabled_)
1970    return;
1971
1972  FlushTextureQuadCache();
1973  GLC(context_, context_->disable(GL_SCISSOR_TEST));
1974  is_scissor_enabled_ = false;
1975}
1976
1977void GLRenderer::CopyCurrentRenderPassToBitmap(
1978    DrawingFrame* frame,
1979    scoped_ptr<CopyOutputRequest> request) {
1980  gfx::Rect copy_rect = frame->current_render_pass->output_rect;
1981  if (request->has_area()) {
1982    // Intersect with the request's area, positioned with its origin at the
1983    // origin of the full copy_rect.
1984    copy_rect.Intersect(request->area() - copy_rect.OffsetFromOrigin());
1985  }
1986  GetFramebufferPixelsAsync(copy_rect, request.Pass());
1987}
1988
1989void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) {
1990  transform.matrix().asColMajorf(gl_matrix);
1991}
1992
1993void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) {
1994  if (quad_location == -1)
1995    return;
1996
1997  float gl_quad[8];
1998  gl_quad[0] = quad.p1().x();
1999  gl_quad[1] = quad.p1().y();
2000  gl_quad[2] = quad.p2().x();
2001  gl_quad[3] = quad.p2().y();
2002  gl_quad[4] = quad.p3().x();
2003  gl_quad[5] = quad.p3().y();
2004  gl_quad[6] = quad.p4().x();
2005  gl_quad[7] = quad.p4().y();
2006  GLC(context_, context_->uniform2fv(quad_location, 4, gl_quad));
2007}
2008
2009void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) {
2010  if (alpha_location != -1)
2011    GLC(context_, context_->uniform1f(alpha_location, opacity));
2012}
2013
2014void GLRenderer::SetStencilEnabled(bool enabled) {
2015  if (enabled == stencil_shadow_)
2016    return;
2017
2018  if (enabled)
2019    GLC(context_, context_->enable(GL_STENCIL_TEST));
2020  else
2021    GLC(context_, context_->disable(GL_STENCIL_TEST));
2022  stencil_shadow_ = enabled;
2023}
2024
2025void GLRenderer::SetBlendEnabled(bool enabled) {
2026  if (enabled == blend_shadow_)
2027    return;
2028
2029  if (enabled)
2030    GLC(context_, context_->enable(GL_BLEND));
2031  else
2032    GLC(context_, context_->disable(GL_BLEND));
2033  blend_shadow_ = enabled;
2034}
2035
2036void GLRenderer::SetUseProgram(unsigned program) {
2037  if (program == program_shadow_)
2038    return;
2039  GLC(context_, context_->useProgram(program));
2040  program_shadow_ = program;
2041}
2042
2043void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame,
2044                                  const gfx::Transform& draw_transform,
2045                                  const gfx::RectF& quad_rect,
2046                                  int matrix_location) {
2047  gfx::Transform quad_rect_matrix;
2048  QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
2049  static float gl_matrix[16];
2050  ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix);
2051  GLC(context_,
2052      context_->uniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0]));
2053
2054  GLC(context_, context_->drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
2055}
2056
2057void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
2058                                          int texture_id,
2059                                          gfx::Rect rect,
2060                                          const gfx::Transform& draw_matrix,
2061                                          bool flip_vertically) {
2062  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
2063      context_, &highp_threshold_cache_, highp_threshold_min_,
2064      rect.bottom_right());
2065
2066  const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision);
2067  SetUseProgram(program->program());
2068
2069  GLC(Context(), Context()->uniform1i(
2070      program->fragment_shader().sampler_location(), 0));
2071
2072  if (flip_vertically) {
2073    GLC(Context(), Context()->uniform4f(
2074        program->vertex_shader().tex_transform_location(),
2075        0.f,
2076        1.f,
2077        1.f,
2078        -1.f));
2079  } else {
2080    GLC(Context(), Context()->uniform4f(
2081        program->vertex_shader().tex_transform_location(),
2082        0.f,
2083        0.f,
2084        1.f,
2085        1.f));
2086  }
2087
2088  SetShaderOpacity(1.f, program->fragment_shader().alpha_location());
2089  DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(Context()));
2090  GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, texture_id));
2091  DrawQuadGeometry(
2092      frame, draw_matrix, rect, program->vertex_shader().matrix_location());
2093}
2094
2095void GLRenderer::Finish() {
2096  TRACE_EVENT0("cc", "GLRenderer::finish");
2097  context_->finish();
2098}
2099
2100void GLRenderer::SwapBuffers() {
2101  DCHECK(visible_);
2102  DCHECK(!is_backbuffer_discarded_);
2103
2104  TRACE_EVENT0("cc", "GLRenderer::SwapBuffers");
2105  // We're done! Time to swapbuffers!
2106
2107  CompositorFrame compositor_frame;
2108  compositor_frame.metadata = client_->MakeCompositorFrameMetadata();
2109  compositor_frame.gl_frame_data = make_scoped_ptr(new GLFrameData);
2110  compositor_frame.gl_frame_data->size = output_surface_->SurfaceSize();
2111  if (capabilities_.using_partial_swap) {
2112    // If supported, we can save significant bandwidth by only swapping the
2113    // damaged/scissored region (clamped to the viewport)
2114    swap_buffer_rect_.Intersect(client_->DeviceViewport());
2115    int flipped_y_pos_of_rect_bottom =
2116        client_->DeviceViewport().height() - swap_buffer_rect_.y() -
2117        swap_buffer_rect_.height();
2118    compositor_frame.gl_frame_data->sub_buffer_rect =
2119        gfx::Rect(swap_buffer_rect_.x(),
2120                  flipped_y_pos_of_rect_bottom,
2121                  swap_buffer_rect_.width(),
2122                  swap_buffer_rect_.height());
2123  } else {
2124    compositor_frame.gl_frame_data->sub_buffer_rect =
2125        gfx::Rect(output_surface_->SurfaceSize());
2126  }
2127  output_surface_->SwapBuffers(&compositor_frame);
2128
2129  swap_buffer_rect_ = gfx::Rect();
2130
2131  // We don't have real fences, so we mark read fences as passed
2132  // assuming a double-buffered GPU pipeline. A texture can be
2133  // written to after one full frame has past since it was last read.
2134  if (last_swap_fence_.get())
2135    static_cast<SimpleSwapFence*>(last_swap_fence_.get())->SetHasPassed();
2136  last_swap_fence_ = resource_provider_->GetReadLockFence();
2137  resource_provider_->SetReadLockFence(new SimpleSwapFence());
2138}
2139
2140void GLRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) {
2141  discard_backbuffer_when_not_visible_ = discard;
2142  EnforceMemoryPolicy();
2143}
2144
2145void GLRenderer::EnforceMemoryPolicy() {
2146  if (!visible_) {
2147    TRACE_EVENT0("cc", "GLRenderer::EnforceMemoryPolicy dropping resources");
2148    ReleaseRenderPassTextures();
2149    if (discard_backbuffer_when_not_visible_)
2150      DiscardBackbuffer();
2151    resource_provider_->ReleaseCachedData();
2152    GLC(context_, context_->flush());
2153  }
2154}
2155
2156void GLRenderer::DiscardBackbuffer() {
2157  if (is_backbuffer_discarded_)
2158    return;
2159
2160  output_surface_->DiscardBackbuffer();
2161
2162  is_backbuffer_discarded_ = true;
2163
2164  // Damage tracker needs a full reset every time framebuffer is discarded.
2165  client_->SetFullRootLayerDamage();
2166}
2167
2168void GLRenderer::EnsureBackbuffer() {
2169  if (!is_backbuffer_discarded_)
2170    return;
2171
2172  output_surface_->EnsureBackbuffer();
2173  is_backbuffer_discarded_ = false;
2174}
2175
2176void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
2177  if (!pixels || rect.IsEmpty())
2178    return;
2179
2180  // This function assumes that it is reading the root frame buffer.
2181  DCHECK(!current_framebuffer_lock_);
2182
2183  scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels);
2184  pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
2185                                    pending_read.Pass());
2186
2187  // This is a syncronous call since the callback is null.
2188  gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
2189  DoGetFramebufferPixels(static_cast<uint8*>(pixels),
2190                         window_rect,
2191                         AsyncGetFramebufferPixelsCleanupCallback());
2192}
2193
2194void GLRenderer::GetFramebufferPixelsAsync(
2195    gfx::Rect rect, scoped_ptr<CopyOutputRequest> request) {
2196  DCHECK(!request->IsEmpty());
2197  if (request->IsEmpty())
2198    return;
2199  if (rect.IsEmpty())
2200    return;
2201
2202  DCHECK(gfx::Rect(current_surface_size_).Contains(rect)) <<
2203      "current_surface_size_: " << current_surface_size_.ToString() <<
2204      " rect: " << rect.ToString();
2205
2206  gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
2207
2208  if (!request->force_bitmap_result()) {
2209    unsigned int texture_id = context_->createTexture();
2210    GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2211    GLC(context_, context_->texParameteri(
2212        GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2213    GLC(context_, context_->texParameteri(
2214        GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2215    GLC(context_, context_->texParameteri(
2216        GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2217    GLC(context_, context_->texParameteri(
2218        GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2219    GetFramebufferTexture(texture_id, GL_RGBA, window_rect);
2220
2221    gpu::Mailbox mailbox;
2222    unsigned sync_point = 0;
2223    GLC(context_, context_->genMailboxCHROMIUM(mailbox.name));
2224    if (mailbox.IsZero()) {
2225      context_->deleteTexture(texture_id);
2226      request->SendEmptyResult();
2227      return;
2228    }
2229
2230    GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2231    GLC(context_, context_->produceTextureCHROMIUM(
2232        GL_TEXTURE_2D, mailbox.name));
2233    GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2234    sync_point = context_->insertSyncPoint();
2235    scoped_ptr<TextureMailbox> texture_mailbox = make_scoped_ptr(
2236        new TextureMailbox(mailbox,
2237                           texture_mailbox_deleter_->GetReleaseCallback(
2238                               output_surface_->context_provider(), texture_id),
2239                           GL_TEXTURE_2D,
2240                           sync_point));
2241    request->SendTextureResult(window_rect.size(), texture_mailbox.Pass());
2242    return;
2243  }
2244
2245  DCHECK(request->force_bitmap_result());
2246
2247  scoped_ptr<SkBitmap> bitmap(new SkBitmap);
2248  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
2249                    window_rect.width(),
2250                    window_rect.height());
2251  bitmap->allocPixels();
2252
2253  scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
2254
2255  // Save a pointer to the pixels, the bitmap is owned by the cleanup_callback.
2256  uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
2257
2258  AsyncGetFramebufferPixelsCleanupCallback cleanup_callback = base::Bind(
2259      &GLRenderer::PassOnSkBitmap,
2260      base::Unretained(this),
2261      base::Passed(&bitmap),
2262      base::Passed(&lock));
2263
2264  scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels);
2265  pending_read->copy_request = request.Pass();
2266  pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
2267                                    pending_read.Pass());
2268
2269  // This is an asyncronous call since the callback is not null.
2270  DoGetFramebufferPixels(pixels, window_rect, cleanup_callback);
2271}
2272
2273void GLRenderer::DoGetFramebufferPixels(
2274    uint8* dest_pixels,
2275    gfx::Rect window_rect,
2276    const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback) {
2277  DCHECK_GE(window_rect.x(), 0);
2278  DCHECK_GE(window_rect.y(), 0);
2279  DCHECK_LE(window_rect.right(), current_surface_size_.width());
2280  DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
2281
2282  bool is_async = !cleanup_callback.is_null();
2283
2284  MakeContextCurrent();
2285
2286  bool do_workaround = NeedsIOSurfaceReadbackWorkaround();
2287
2288  unsigned temporary_texture = 0;
2289  unsigned temporary_fbo = 0;
2290
2291  if (do_workaround) {
2292    // On Mac OS X, calling glReadPixels() against an FBO whose color attachment
2293    // is an IOSurface-backed texture causes corruption of future glReadPixels()
2294    // calls, even those on different OpenGL contexts. It is believed that this
2295    // is the root cause of top crasher
2296    // http://crbug.com/99393. <rdar://problem/10949687>
2297
2298    temporary_texture = context_->createTexture();
2299    GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture));
2300    GLC(context_, context_->texParameteri(
2301        GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2302    GLC(context_, context_->texParameteri(
2303        GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2304    GLC(context_, context_->texParameteri(
2305        GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2306    GLC(context_, context_->texParameteri(
2307        GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2308    // Copy the contents of the current (IOSurface-backed) framebuffer into a
2309    // temporary texture.
2310    GetFramebufferTexture(temporary_texture,
2311                          GL_RGBA,
2312                          gfx::Rect(current_surface_size_));
2313    temporary_fbo = context_->createFramebuffer();
2314    // Attach this texture to an FBO, and perform the readback from that FBO.
2315    GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
2316    GLC(context_, context_->framebufferTexture2D(GL_FRAMEBUFFER,
2317                                                 GL_COLOR_ATTACHMENT0,
2318                                                 GL_TEXTURE_2D,
2319                                                 temporary_texture,
2320                                                 0));
2321
2322    DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
2323              context_->checkFramebufferStatus(GL_FRAMEBUFFER));
2324  }
2325
2326  unsigned buffer = context_->createBuffer();
2327  GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
2328                                     buffer));
2329  GLC(context_, context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
2330                                     4 * window_rect.size().GetArea(),
2331                                     NULL,
2332                                     GL_STREAM_READ));
2333
2334  WebKit::WebGLId query = 0;
2335  if (is_async) {
2336    query = context_->createQueryEXT();
2337    GLC(context_, context_->beginQueryEXT(
2338        GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM,
2339        query));
2340  }
2341
2342  GLC(context_,
2343      context_->readPixels(window_rect.x(),
2344                           window_rect.y(),
2345                           window_rect.width(),
2346                           window_rect.height(),
2347                           GL_RGBA,
2348                           GL_UNSIGNED_BYTE,
2349                           NULL));
2350
2351  GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
2352                                     0));
2353
2354  if (do_workaround) {
2355    // Clean up.
2356    GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0));
2357    GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2358    GLC(context_, context_->deleteFramebuffer(temporary_fbo));
2359    GLC(context_, context_->deleteTexture(temporary_texture));
2360  }
2361
2362  base::Closure finished_callback =
2363      base::Bind(&GLRenderer::FinishedReadback,
2364                 base::Unretained(this),
2365                 cleanup_callback,
2366                 buffer,
2367                 query,
2368                 dest_pixels,
2369                 window_rect.size());
2370  // Save the finished_callback so it can be cancelled.
2371  pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset(
2372      finished_callback);
2373
2374  // Save the buffer to verify the callbacks happen in the expected order.
2375  pending_async_read_pixels_.front()->buffer = buffer;
2376
2377  if (is_async) {
2378    GLC(context_, context_->endQueryEXT(
2379        GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM));
2380    SyncPointHelper::SignalQuery(
2381        context_,
2382        query,
2383        finished_callback);
2384  } else {
2385    resource_provider_->Finish();
2386    finished_callback.Run();
2387  }
2388
2389  EnforceMemoryPolicy();
2390}
2391
2392void GLRenderer::FinishedReadback(
2393    const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
2394    unsigned source_buffer,
2395    unsigned query,
2396    uint8* dest_pixels,
2397    gfx::Size size) {
2398  DCHECK(!pending_async_read_pixels_.empty());
2399
2400  if (query != 0) {
2401    GLC(context_, context_->deleteQueryEXT(query));
2402  }
2403
2404  PendingAsyncReadPixels* current_read = pending_async_read_pixels_.back();
2405  // Make sure we service the readbacks in order.
2406  DCHECK_EQ(source_buffer, current_read->buffer);
2407
2408  uint8* src_pixels = NULL;
2409
2410  if (source_buffer != 0) {
2411    GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
2412                                       source_buffer));
2413    src_pixels = static_cast<uint8*>(
2414        context_->mapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
2415                                    GL_READ_ONLY));
2416
2417    if (src_pixels) {
2418      size_t row_bytes = size.width() * 4;
2419      int num_rows = size.height();
2420      size_t total_bytes = num_rows * row_bytes;
2421      for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
2422        // Flip Y axis.
2423        size_t src_y = total_bytes - dest_y - row_bytes;
2424        // Swizzle OpenGL -> Skia byte order.
2425        for (size_t x = 0; x < row_bytes; x += 4) {
2426          dest_pixels[dest_y + x + SK_R32_SHIFT/8] = src_pixels[src_y + x + 0];
2427          dest_pixels[dest_y + x + SK_G32_SHIFT/8] = src_pixels[src_y + x + 1];
2428          dest_pixels[dest_y + x + SK_B32_SHIFT/8] = src_pixels[src_y + x + 2];
2429          dest_pixels[dest_y + x + SK_A32_SHIFT/8] = src_pixels[src_y + x + 3];
2430        }
2431      }
2432
2433      GLC(context_, context_->unmapBufferCHROMIUM(
2434          GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM));
2435    }
2436    GLC(context_, context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
2437                                       0));
2438    GLC(context_, context_->deleteBuffer(source_buffer));
2439  }
2440
2441  // TODO(danakj): This can go away when synchronous readback is no more and its
2442  // contents can just move here.
2443  if (!cleanup_callback.is_null())
2444    cleanup_callback.Run(current_read->copy_request.Pass(), src_pixels != NULL);
2445
2446  pending_async_read_pixels_.pop_back();
2447}
2448
2449void GLRenderer::PassOnSkBitmap(
2450    scoped_ptr<SkBitmap> bitmap,
2451    scoped_ptr<SkAutoLockPixels> lock,
2452    scoped_ptr<CopyOutputRequest> request,
2453    bool success) {
2454  DCHECK(request->force_bitmap_result());
2455
2456  lock.reset();
2457  if (success)
2458    request->SendBitmapResult(bitmap.Pass());
2459}
2460
2461void GLRenderer::GetFramebufferTexture(unsigned texture_id,
2462                                       unsigned texture_format,
2463                                       gfx::Rect window_rect) {
2464  DCHECK(texture_id);
2465  DCHECK_GE(window_rect.x(), 0);
2466  DCHECK_GE(window_rect.y(), 0);
2467  DCHECK_LE(window_rect.right(), current_surface_size_.width());
2468  DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
2469
2470  GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2471  GLC(context_,
2472      context_->copyTexImage2D(GL_TEXTURE_2D,
2473                               0,
2474                               texture_format,
2475                               window_rect.x(),
2476                               window_rect.y(),
2477                               window_rect.width(),
2478                               window_rect.height(),
2479                               0));
2480  GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2481}
2482
2483bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
2484                                  const ScopedResource* texture,
2485                                  gfx::Rect viewport_rect) {
2486  DCHECK(texture->id());
2487  frame->current_render_pass = NULL;
2488  frame->current_texture = texture;
2489
2490  return BindFramebufferToTexture(frame, texture, viewport_rect);
2491}
2492
2493void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
2494  current_framebuffer_lock_.reset();
2495  output_surface_->BindFramebuffer();
2496
2497  if (output_surface_->HasExternalStencilTest()) {
2498    SetStencilEnabled(true);
2499    GLC(context_, context_->stencilFunc(GL_EQUAL, 1, 1));
2500  } else {
2501    SetStencilEnabled(false);
2502  }
2503}
2504
2505bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
2506                                          const ScopedResource* texture,
2507                                          gfx::Rect target_rect) {
2508  DCHECK(texture->id());
2509
2510  current_framebuffer_lock_.reset();
2511
2512  SetStencilEnabled(false);
2513  GLC(context_,
2514      context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_));
2515  current_framebuffer_lock_ =
2516      make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL(
2517          resource_provider_, texture->id()));
2518  unsigned texture_id = current_framebuffer_lock_->texture_id();
2519  GLC(context_,
2520      context_->framebufferTexture2D(
2521          GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0));
2522
2523  DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
2524         GL_FRAMEBUFFER_COMPLETE || IsContextLost());
2525
2526  InitializeViewport(frame,
2527                     target_rect,
2528                     gfx::Rect(target_rect.size()),
2529                     target_rect.size());
2530  return true;
2531}
2532
2533void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
2534  EnsureScissorTestEnabled();
2535
2536  // Don't unnecessarily ask the context to change the scissor, because it
2537  // may cause undesired GPU pipeline flushes.
2538  if (scissor_rect == scissor_rect_)
2539    return;
2540
2541  scissor_rect_ = scissor_rect;
2542  FlushTextureQuadCache();
2543  GLC(context_,
2544      context_->scissor(scissor_rect.x(),
2545                        scissor_rect.y(),
2546                        scissor_rect.width(),
2547                        scissor_rect.height()));
2548}
2549
2550void GLRenderer::SetDrawViewport(gfx::Rect window_space_viewport) {
2551  viewport_ = window_space_viewport;
2552  GLC(context_, context_->viewport(window_space_viewport.x(),
2553                                   window_space_viewport.y(),
2554                                   window_space_viewport.width(),
2555                                   window_space_viewport.height()));
2556}
2557
2558bool GLRenderer::MakeContextCurrent() { return context_->makeContextCurrent(); }
2559
2560bool GLRenderer::InitializeSharedObjects() {
2561  TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects");
2562  MakeContextCurrent();
2563
2564  // Create an FBO for doing offscreen rendering.
2565  GLC(context_, offscreen_framebuffer_id_ = context_->createFramebuffer());
2566
2567  // We will always need these programs to render, so create the programs
2568  // eagerly so that the shader compilation can start while we do other work.
2569  // Other programs are created lazily on first access.
2570  shared_geometry_ = make_scoped_ptr(
2571      new GeometryBinding(context_, QuadVertexRect()));
2572  render_pass_program_ = make_scoped_ptr(
2573      new RenderPassProgram(context_, TexCoordPrecisionMedium));
2574  render_pass_program_highp_ = make_scoped_ptr(
2575      new RenderPassProgram(context_, TexCoordPrecisionHigh));
2576  tile_program_ = make_scoped_ptr(
2577      new TileProgram(context_, TexCoordPrecisionMedium));
2578  tile_program_opaque_ = make_scoped_ptr(
2579      new TileProgramOpaque(context_, TexCoordPrecisionMedium));
2580  tile_program_highp_ = make_scoped_ptr(
2581      new TileProgram(context_, TexCoordPrecisionHigh));
2582  tile_program_opaque_highp_ = make_scoped_ptr(
2583      new TileProgramOpaque(context_, TexCoordPrecisionHigh));
2584
2585  GLC(context_, context_->flush());
2586
2587  return true;
2588}
2589
2590const GLRenderer::TileCheckerboardProgram*
2591GLRenderer::GetTileCheckerboardProgram() {
2592  if (!tile_checkerboard_program_)
2593    tile_checkerboard_program_ = make_scoped_ptr(
2594        new TileCheckerboardProgram(context_, TexCoordPrecisionNA));
2595  if (!tile_checkerboard_program_->initialized()) {
2596    TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
2597    tile_checkerboard_program_->Initialize(context_, is_using_bind_uniform_);
2598  }
2599  return tile_checkerboard_program_.get();
2600}
2601
2602const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() {
2603  if (!debug_border_program_)
2604    debug_border_program_ = make_scoped_ptr(
2605        new DebugBorderProgram(context_, TexCoordPrecisionNA));
2606  if (!debug_border_program_->initialized()) {
2607    TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize");
2608    debug_border_program_->Initialize(context_, is_using_bind_uniform_);
2609  }
2610  return debug_border_program_.get();
2611}
2612
2613const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() {
2614  if (!solid_color_program_)
2615    solid_color_program_ = make_scoped_ptr(
2616        new SolidColorProgram(context_, TexCoordPrecisionNA));
2617  if (!solid_color_program_->initialized()) {
2618    TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
2619    solid_color_program_->Initialize(context_, is_using_bind_uniform_);
2620  }
2621  return solid_color_program_.get();
2622}
2623
2624const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() {
2625  if (!solid_color_program_aa_) {
2626    solid_color_program_aa_ =
2627        make_scoped_ptr(new SolidColorProgramAA(context_, TexCoordPrecisionNA));
2628  }
2629  if (!solid_color_program_aa_->initialized()) {
2630    TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize");
2631    solid_color_program_aa_->Initialize(context_, is_using_bind_uniform_);
2632  }
2633  return solid_color_program_aa_.get();
2634}
2635
2636const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram(
2637      TexCoordPrecision precision) {
2638  scoped_ptr<RenderPassProgram>& program =
2639      (precision == TexCoordPrecisionHigh) ? render_pass_program_highp_
2640                                           : render_pass_program_;
2641  DCHECK(program);
2642  if (!program->initialized()) {
2643    TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
2644    program->Initialize(context_, is_using_bind_uniform_);
2645  }
2646  return program.get();
2647}
2648
2649const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
2650      TexCoordPrecision precision) {
2651  scoped_ptr<RenderPassProgramAA>& program =
2652      (precision == TexCoordPrecisionHigh) ? render_pass_program_aa_highp_
2653                                           : render_pass_program_aa_;
2654  if (!program)
2655    program =
2656        make_scoped_ptr(new RenderPassProgramAA(context_, precision));
2657  if (!program->initialized()) {
2658    TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
2659    program->Initialize(context_, is_using_bind_uniform_);
2660  }
2661  return program.get();
2662}
2663
2664const GLRenderer::RenderPassMaskProgram*
2665GLRenderer::GetRenderPassMaskProgram(TexCoordPrecision precision) {
2666  scoped_ptr<RenderPassMaskProgram>& program =
2667      (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_highp_
2668                                           : render_pass_mask_program_;
2669  if (!program)
2670    program = make_scoped_ptr(new RenderPassMaskProgram(context_, precision));
2671  if (!program->initialized()) {
2672    TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
2673    program->Initialize(context_, is_using_bind_uniform_);
2674  }
2675  return program.get();
2676}
2677
2678const GLRenderer::RenderPassMaskProgramAA*
2679GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision) {
2680  scoped_ptr<RenderPassMaskProgramAA>& program =
2681      (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_aa_highp_
2682                                           : render_pass_mask_program_aa_;
2683  if (!program)
2684    program =
2685        make_scoped_ptr(new RenderPassMaskProgramAA(context_, precision));
2686  if (!program->initialized()) {
2687    TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
2688    program->Initialize(context_, is_using_bind_uniform_);
2689  }
2690  return program.get();
2691}
2692
2693const GLRenderer::RenderPassColorMatrixProgram*
2694GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision) {
2695  scoped_ptr<RenderPassColorMatrixProgram>& program =
2696      (precision == TexCoordPrecisionHigh) ?
2697          render_pass_color_matrix_program_highp_ :
2698          render_pass_color_matrix_program_;
2699  if (!program)
2700    program = make_scoped_ptr(
2701        new RenderPassColorMatrixProgram(context_, precision));
2702  if (!program->initialized()) {
2703    TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize");
2704    program->Initialize(context_, is_using_bind_uniform_);
2705  }
2706  return program.get();
2707}
2708
2709const GLRenderer::RenderPassColorMatrixProgramAA*
2710GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
2711  scoped_ptr<RenderPassColorMatrixProgramAA>& program =
2712      (precision == TexCoordPrecisionHigh) ?
2713          render_pass_color_matrix_program_aa_highp_ :
2714          render_pass_color_matrix_program_aa_;
2715  if (!program)
2716    program = make_scoped_ptr(
2717        new RenderPassColorMatrixProgramAA(context_, precision));
2718  if (!program->initialized()) {
2719    TRACE_EVENT0("cc",
2720                 "GLRenderer::renderPassColorMatrixProgramAA::initialize");
2721    program->Initialize(context_, is_using_bind_uniform_);
2722  }
2723  return program.get();
2724}
2725
2726const GLRenderer::RenderPassMaskColorMatrixProgram*
2727GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
2728  scoped_ptr<RenderPassMaskColorMatrixProgram>& program =
2729      (precision == TexCoordPrecisionHigh) ?
2730          render_pass_mask_color_matrix_program_highp_ :
2731          render_pass_mask_color_matrix_program_;
2732  if (!program)
2733    program = make_scoped_ptr(
2734        new RenderPassMaskColorMatrixProgram(context_, precision));
2735  if (!program->initialized()) {
2736    TRACE_EVENT0("cc",
2737                 "GLRenderer::renderPassMaskColorMatrixProgram::initialize");
2738    program->Initialize(context_, is_using_bind_uniform_);
2739  }
2740  return program.get();
2741}
2742
2743const GLRenderer::RenderPassMaskColorMatrixProgramAA*
2744GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
2745  scoped_ptr<RenderPassMaskColorMatrixProgramAA>& program =
2746      (precision == TexCoordPrecisionHigh) ?
2747          render_pass_mask_color_matrix_program_aa_highp_ :
2748          render_pass_mask_color_matrix_program_aa_;
2749  if (!program)
2750    program = make_scoped_ptr(
2751        new RenderPassMaskColorMatrixProgramAA(context_, precision));
2752  if (!program->initialized()) {
2753    TRACE_EVENT0("cc",
2754                 "GLRenderer::renderPassMaskColorMatrixProgramAA::initialize");
2755    program->Initialize(context_, is_using_bind_uniform_);
2756  }
2757  return program.get();
2758}
2759
2760const GLRenderer::TileProgram* GLRenderer::GetTileProgram(
2761    TexCoordPrecision precision) {
2762  scoped_ptr<TileProgram>& program =
2763      (precision == TexCoordPrecisionHigh) ? tile_program_highp_
2764                                           : tile_program_;
2765  DCHECK(program);
2766  if (!program->initialized()) {
2767    TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
2768    program->Initialize(context_, is_using_bind_uniform_);
2769  }
2770  return program.get();
2771}
2772
2773const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque(
2774    TexCoordPrecision precision) {
2775  scoped_ptr<TileProgramOpaque>& program =
2776      (precision == TexCoordPrecisionHigh) ? tile_program_opaque_highp_
2777                                           : tile_program_opaque_;
2778  DCHECK(program);
2779  if (!program->initialized()) {
2780    TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
2781    program->Initialize(context_, is_using_bind_uniform_);
2782  }
2783  return program.get();
2784}
2785
2786const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA(
2787    TexCoordPrecision precision) {
2788  scoped_ptr<TileProgramAA>& program =
2789      (precision == TexCoordPrecisionHigh) ? tile_program_aa_highp_
2790                                           : tile_program_aa_;
2791  if (!program)
2792    program = make_scoped_ptr(new TileProgramAA(context_, precision));
2793  if (!program->initialized()) {
2794    TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
2795    program->Initialize(context_, is_using_bind_uniform_);
2796  }
2797  return program.get();
2798}
2799
2800const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle(
2801    TexCoordPrecision precision) {
2802  scoped_ptr<TileProgramSwizzle>& program =
2803      (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_highp_
2804                                           : tile_program_swizzle_;
2805  if (!program)
2806    program = make_scoped_ptr(new TileProgramSwizzle(context_, precision));
2807  if (!program->initialized()) {
2808    TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
2809    program->Initialize(context_, is_using_bind_uniform_);
2810  }
2811  return program.get();
2812}
2813
2814const GLRenderer::TileProgramSwizzleOpaque*
2815GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision) {
2816  scoped_ptr<TileProgramSwizzleOpaque>& program =
2817      (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_opaque_highp_
2818                                           : tile_program_swizzle_opaque_;
2819  if (!program)
2820    program = make_scoped_ptr(
2821        new TileProgramSwizzleOpaque(context_, precision));
2822  if (!program->initialized()) {
2823    TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize");
2824    program->Initialize(context_, is_using_bind_uniform_);
2825  }
2826  return program.get();
2827}
2828
2829const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA(
2830    TexCoordPrecision precision) {
2831  scoped_ptr<TileProgramSwizzleAA>& program =
2832      (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_aa_highp_
2833                                           : tile_program_swizzle_aa_;
2834  if (!program)
2835    program = make_scoped_ptr(new TileProgramSwizzleAA(context_, precision));
2836  if (!program->initialized()) {
2837    TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
2838    program->Initialize(context_, is_using_bind_uniform_);
2839  }
2840  return program.get();
2841}
2842
2843const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram(
2844    TexCoordPrecision precision) {
2845  scoped_ptr<TextureProgram>& program =
2846      (precision == TexCoordPrecisionHigh) ? texture_program_highp_
2847                                           : texture_program_;
2848  if (!program)
2849    program = make_scoped_ptr(new TextureProgram(context_, precision));
2850  if (!program->initialized()) {
2851    TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
2852    program->Initialize(context_, is_using_bind_uniform_);
2853  }
2854  return program.get();
2855}
2856
2857const GLRenderer::NonPremultipliedTextureProgram*
2858    GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) {
2859  scoped_ptr<NonPremultipliedTextureProgram>& program =
2860      (precision == TexCoordPrecisionHigh) ?
2861         nonpremultiplied_texture_program_highp_ :
2862         nonpremultiplied_texture_program_;
2863  if (!program) {
2864    program = make_scoped_ptr(
2865        new NonPremultipliedTextureProgram(context_, precision));
2866  }
2867  if (!program->initialized()) {
2868    TRACE_EVENT0("cc",
2869                 "GLRenderer::NonPremultipliedTextureProgram::Initialize");
2870    program->Initialize(context_, is_using_bind_uniform_);
2871  }
2872  return program.get();
2873}
2874
2875const GLRenderer::TextureBackgroundProgram*
2876GLRenderer::GetTextureBackgroundProgram(TexCoordPrecision precision) {
2877  scoped_ptr<TextureBackgroundProgram>& program =
2878      (precision == TexCoordPrecisionHigh) ? texture_background_program_highp_
2879                                           : texture_background_program_;
2880  if (!program) {
2881    program = make_scoped_ptr(
2882        new TextureBackgroundProgram(context_, precision));
2883  }
2884  if (!program->initialized()) {
2885    TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
2886    program->Initialize(context_, is_using_bind_uniform_);
2887  }
2888  return program.get();
2889}
2890
2891const GLRenderer::NonPremultipliedTextureBackgroundProgram*
2892GLRenderer::GetNonPremultipliedTextureBackgroundProgram(
2893    TexCoordPrecision precision) {
2894  scoped_ptr<NonPremultipliedTextureBackgroundProgram>& program =
2895      (precision == TexCoordPrecisionHigh) ?
2896         nonpremultiplied_texture_background_program_highp_ :
2897         nonpremultiplied_texture_background_program_;
2898  if (!program) {
2899    program = make_scoped_ptr(
2900        new NonPremultipliedTextureBackgroundProgram(context_, precision));
2901  }
2902  if (!program->initialized()) {
2903    TRACE_EVENT0("cc",
2904                 "GLRenderer::NonPremultipliedTextureProgram::Initialize");
2905    program->Initialize(context_, is_using_bind_uniform_);
2906  }
2907  return program.get();
2908}
2909
2910const GLRenderer::TextureIOSurfaceProgram*
2911GLRenderer::GetTextureIOSurfaceProgram(TexCoordPrecision precision) {
2912  scoped_ptr<TextureIOSurfaceProgram>& program =
2913      (precision == TexCoordPrecisionHigh) ? texture_io_surface_program_highp_
2914                                           : texture_io_surface_program_;
2915  if (!program)
2916    program =
2917        make_scoped_ptr(new TextureIOSurfaceProgram(context_, precision));
2918  if (!program->initialized()) {
2919    TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
2920    program->Initialize(context_, is_using_bind_uniform_);
2921  }
2922  return program.get();
2923}
2924
2925const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram(
2926    TexCoordPrecision precision) {
2927  scoped_ptr<VideoYUVProgram>& program =
2928      (precision == TexCoordPrecisionHigh) ? video_yuv_program_highp_
2929                                           : video_yuv_program_;
2930  if (!program)
2931    program = make_scoped_ptr(new VideoYUVProgram(context_, precision));
2932  if (!program->initialized()) {
2933    TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
2934    program->Initialize(context_, is_using_bind_uniform_);
2935  }
2936  return program.get();
2937}
2938
2939const GLRenderer::VideoYUVAProgram* GLRenderer::GetVideoYUVAProgram(
2940    TexCoordPrecision precision) {
2941  scoped_ptr<VideoYUVAProgram>& program =
2942      (precision == TexCoordPrecisionHigh) ? video_yuva_program_highp_
2943                                           : video_yuva_program_;
2944  if (!program)
2945    program = make_scoped_ptr(new VideoYUVAProgram(context_, precision));
2946  if (!program->initialized()) {
2947    TRACE_EVENT0("cc", "GLRenderer::videoYUVAProgram::initialize");
2948    program->Initialize(context_, is_using_bind_uniform_);
2949  }
2950  return program.get();
2951}
2952
2953const GLRenderer::VideoStreamTextureProgram*
2954GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) {
2955  if (!Capabilities().using_egl_image)
2956    return NULL;
2957  scoped_ptr<VideoStreamTextureProgram>& program =
2958      (precision == TexCoordPrecisionHigh) ? video_stream_texture_program_highp_
2959                                           : video_stream_texture_program_;
2960  if (!program)
2961    program =
2962        make_scoped_ptr(new VideoStreamTextureProgram(context_, precision));
2963  if (!program->initialized()) {
2964    TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
2965    program->Initialize(context_, is_using_bind_uniform_);
2966  }
2967  return program.get();
2968}
2969
2970void GLRenderer::CleanupSharedObjects() {
2971  MakeContextCurrent();
2972
2973  shared_geometry_.reset();
2974
2975  if (tile_program_)
2976    tile_program_->Cleanup(context_);
2977  if (tile_program_opaque_)
2978    tile_program_opaque_->Cleanup(context_);
2979  if (tile_program_swizzle_)
2980    tile_program_swizzle_->Cleanup(context_);
2981  if (tile_program_swizzle_opaque_)
2982    tile_program_swizzle_opaque_->Cleanup(context_);
2983  if (tile_program_aa_)
2984    tile_program_aa_->Cleanup(context_);
2985  if (tile_program_swizzle_aa_)
2986    tile_program_swizzle_aa_->Cleanup(context_);
2987  if (tile_checkerboard_program_)
2988    tile_checkerboard_program_->Cleanup(context_);
2989
2990  if (tile_program_highp_)
2991    tile_program_highp_->Cleanup(context_);
2992  if (tile_program_opaque_highp_)
2993    tile_program_opaque_highp_->Cleanup(context_);
2994  if (tile_program_swizzle_highp_)
2995    tile_program_swizzle_highp_->Cleanup(context_);
2996  if (tile_program_swizzle_opaque_highp_)
2997    tile_program_swizzle_opaque_highp_->Cleanup(context_);
2998  if (tile_program_aa_highp_)
2999    tile_program_aa_highp_->Cleanup(context_);
3000  if (tile_program_swizzle_aa_highp_)
3001    tile_program_swizzle_aa_highp_->Cleanup(context_);
3002
3003  if (render_pass_mask_program_)
3004    render_pass_mask_program_->Cleanup(context_);
3005  if (render_pass_program_)
3006    render_pass_program_->Cleanup(context_);
3007  if (render_pass_mask_program_aa_)
3008    render_pass_mask_program_aa_->Cleanup(context_);
3009  if (render_pass_program_aa_)
3010    render_pass_program_aa_->Cleanup(context_);
3011  if (render_pass_color_matrix_program_)
3012    render_pass_color_matrix_program_->Cleanup(context_);
3013  if (render_pass_mask_color_matrix_program_aa_)
3014    render_pass_mask_color_matrix_program_aa_->Cleanup(context_);
3015  if (render_pass_color_matrix_program_aa_)
3016    render_pass_color_matrix_program_aa_->Cleanup(context_);
3017  if (render_pass_mask_color_matrix_program_)
3018    render_pass_mask_color_matrix_program_->Cleanup(context_);
3019
3020  if (render_pass_mask_program_highp_)
3021    render_pass_mask_program_highp_->Cleanup(context_);
3022  if (render_pass_program_highp_)
3023    render_pass_program_highp_->Cleanup(context_);
3024  if (render_pass_mask_program_aa_highp_)
3025    render_pass_mask_program_aa_highp_->Cleanup(context_);
3026  if (render_pass_program_aa_highp_)
3027    render_pass_program_aa_highp_->Cleanup(context_);
3028  if (render_pass_color_matrix_program_highp_)
3029    render_pass_color_matrix_program_highp_->Cleanup(context_);
3030  if (render_pass_mask_color_matrix_program_aa_highp_)
3031    render_pass_mask_color_matrix_program_aa_highp_->Cleanup(context_);
3032  if (render_pass_color_matrix_program_aa_highp_)
3033    render_pass_color_matrix_program_aa_highp_->Cleanup(context_);
3034  if (render_pass_mask_color_matrix_program_highp_)
3035    render_pass_mask_color_matrix_program_highp_->Cleanup(context_);
3036
3037  if (texture_program_)
3038    texture_program_->Cleanup(context_);
3039  if (nonpremultiplied_texture_program_)
3040    nonpremultiplied_texture_program_->Cleanup(context_);
3041  if (texture_background_program_)
3042    texture_background_program_->Cleanup(context_);
3043  if (nonpremultiplied_texture_background_program_)
3044    nonpremultiplied_texture_background_program_->Cleanup(context_);
3045  if (texture_io_surface_program_)
3046    texture_io_surface_program_->Cleanup(context_);
3047
3048  if (texture_program_highp_)
3049    texture_program_highp_->Cleanup(context_);
3050  if (nonpremultiplied_texture_program_highp_)
3051    nonpremultiplied_texture_program_highp_->Cleanup(context_);
3052  if (texture_background_program_highp_)
3053    texture_background_program_highp_->Cleanup(context_);
3054  if (nonpremultiplied_texture_background_program_highp_)
3055    nonpremultiplied_texture_background_program_highp_->Cleanup(context_);
3056  if (texture_io_surface_program_highp_)
3057    texture_io_surface_program_highp_->Cleanup(context_);
3058
3059  if (video_yuv_program_)
3060    video_yuv_program_->Cleanup(context_);
3061  if (video_yuva_program_)
3062    video_yuva_program_->Cleanup(context_);
3063  if (video_stream_texture_program_)
3064    video_stream_texture_program_->Cleanup(context_);
3065
3066  if (video_yuv_program_highp_)
3067    video_yuv_program_highp_->Cleanup(context_);
3068  if (video_yuva_program_highp_)
3069    video_yuva_program_highp_->Cleanup(context_);
3070  if (video_stream_texture_program_highp_)
3071    video_stream_texture_program_highp_->Cleanup(context_);
3072
3073  if (debug_border_program_)
3074    debug_border_program_->Cleanup(context_);
3075  if (solid_color_program_)
3076    solid_color_program_->Cleanup(context_);
3077  if (solid_color_program_aa_)
3078    solid_color_program_aa_->Cleanup(context_);
3079
3080  if (offscreen_framebuffer_id_)
3081    GLC(context_, context_->deleteFramebuffer(offscreen_framebuffer_id_));
3082
3083  if (on_demand_tile_raster_resource_id_)
3084    resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
3085
3086  ReleaseRenderPassTextures();
3087}
3088
3089void GLRenderer::ReinitializeGrCanvas() {
3090  if (!CanUseSkiaGPUBackend())
3091    return;
3092
3093  GrBackendRenderTargetDesc desc;
3094  desc.fWidth = client_->DeviceViewport().width();
3095  desc.fHeight = client_->DeviceViewport().height();
3096  desc.fConfig = kRGBA_8888_GrPixelConfig;
3097  desc.fOrigin = kTopLeft_GrSurfaceOrigin;
3098  desc.fSampleCnt = 1;
3099  desc.fStencilBits = 8;
3100  desc.fRenderTargetHandle = 0;
3101
3102  skia::RefPtr<GrSurface> surface(
3103      skia::AdoptRef(gr_context_->wrapBackendRenderTarget(desc)));
3104  skia::RefPtr<SkBaseDevice> device(
3105      skia::AdoptRef(SkGpuDevice::Create(surface.get())));
3106  sk_canvas_ = skia::AdoptRef(new SkCanvas(device.get()));
3107}
3108
3109void GLRenderer::ReinitializeGLState() {
3110  // Bind the common vertex attributes used for drawing all the layers.
3111  shared_geometry_->PrepareForDraw();
3112
3113  GLC(context_, context_->disable(GL_DEPTH_TEST));
3114  GLC(context_, context_->disable(GL_CULL_FACE));
3115  GLC(context_, context_->colorMask(true, true, true, true));
3116  GLC(context_, context_->disable(GL_STENCIL_TEST));
3117  stencil_shadow_ = false;
3118  GLC(context_, context_->enable(GL_BLEND));
3119  blend_shadow_ = true;
3120  GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
3121  GLC(context_, context_->activeTexture(GL_TEXTURE0));
3122  program_shadow_ = 0;
3123
3124  // Make sure scissoring starts as disabled.
3125  is_scissor_enabled_ = false;
3126  GLC(context_, context_->disable(GL_SCISSOR_TEST));
3127}
3128
3129bool GLRenderer::CanUseSkiaGPUBackend() const {
3130  // The Skia GPU backend requires a stencil buffer.  See ReinitializeGrCanvas
3131  // implementation.
3132  return gr_context_ && context_->getContextAttributes().stencil;
3133}
3134
3135bool GLRenderer::IsContextLost() {
3136  return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR);
3137}
3138
3139void GLRenderer::LazyLabelOffscreenContext(
3140    ContextProvider* offscreen_context_provider) {
3141  if (offscreen_context_labelled_)
3142    return;
3143  offscreen_context_labelled_ = true;
3144  std::string unique_context_name = base::StringPrintf(
3145      "%s-Offscreen-%p", settings_->compositor_name.c_str(), context_);
3146  offscreen_context_provider->Context3d()
3147      ->pushGroupMarkerEXT(unique_context_name.c_str());
3148}
3149
3150
3151}  // namespace cc
3152