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