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