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