Remove bool return for Renderer SwapBuffers
[chromium-blink-merge.git] / cc / output / gl_renderer.cc
blobc767bd16abccb35a26cff42555c4a39d577db8fe
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.
5 #include "cc/output/gl_renderer.h"
7 #include <algorithm>
8 #include <set>
9 #include <string>
10 #include <vector>
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "base/string_util.h"
15 #include "base/strings/string_split.h"
16 #include "build/build_config.h"
17 #include "cc/base/math_util.h"
18 #include "cc/layers/video_layer_impl.h"
19 #include "cc/output/compositor_frame.h"
20 #include "cc/output/compositor_frame_metadata.h"
21 #include "cc/output/context_provider.h"
22 #include "cc/output/geometry_binding.h"
23 #include "cc/output/gl_frame_data.h"
24 #include "cc/output/output_surface.h"
25 #include "cc/output/render_surface_filters.h"
26 #include "cc/quads/picture_draw_quad.h"
27 #include "cc/quads/render_pass.h"
28 #include "cc/quads/stream_video_draw_quad.h"
29 #include "cc/quads/texture_draw_quad.h"
30 #include "cc/resources/layer_quad.h"
31 #include "cc/resources/priority_calculator.h"
32 #include "cc/resources/scoped_resource.h"
33 #include "cc/trees/damage_tracker.h"
34 #include "cc/trees/proxy.h"
35 #include "cc/trees/single_thread_proxy.h"
36 #include "gpu/GLES2/gl2extchromium.h"
37 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
38 #include "third_party/khronos/GLES2/gl2.h"
39 #include "third_party/khronos/GLES2/gl2ext.h"
40 #include "third_party/skia/include/core/SkBitmap.h"
41 #include "third_party/skia/include/core/SkColor.h"
42 #include "third_party/skia/include/core/SkColorFilter.h"
43 #include "third_party/skia/include/gpu/GrContext.h"
44 #include "third_party/skia/include/gpu/GrTexture.h"
45 #include "third_party/skia/include/gpu/SkGpuDevice.h"
46 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h"
47 #include "ui/gfx/quad_f.h"
48 #include "ui/gfx/rect_conversions.h"
50 using WebKit::WebGraphicsContext3D;
51 using WebKit::WebGraphicsMemoryAllocation;
53 namespace cc {
55 namespace {
57 // TODO(epenner): This should probably be moved to output surface.
59 // This implements a simple fence based on client side swaps.
60 // This is to isolate the ResourceProvider from 'frames' which
61 // it shouldn't need to care about, while still allowing us to
62 // enforce good texture recycling behavior strictly throughout
63 // the compositor (don't recycle a texture while it's in use).
64 class SimpleSwapFence : public ResourceProvider::Fence {
65 public:
66 SimpleSwapFence() : has_passed_(false) {}
67 virtual bool HasPassed() OVERRIDE { return has_passed_; }
68 void SetHasPassed() { has_passed_ = true; }
69 private:
70 virtual ~SimpleSwapFence() {}
71 bool has_passed_;
74 bool NeedsIOSurfaceReadbackWorkaround() {
75 #if defined(OS_MACOSX)
76 // This isn't strictly required in DumpRenderTree-mode when Mesa is used,
77 // but it doesn't seem to hurt.
78 return true;
79 #else
80 return false;
81 #endif
84 // Smallest unit that impact anti-aliasing output. We use this to
85 // determine when anti-aliasing is unnecessary.
86 const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
88 } // anonymous namespace
90 scoped_ptr<GLRenderer> GLRenderer::Create(RendererClient* client,
91 OutputSurface* output_surface,
92 ResourceProvider* resource_provider,
93 int highp_threshold_min) {
94 scoped_ptr<GLRenderer> renderer(new GLRenderer(
95 client, output_surface, resource_provider, highp_threshold_min));
96 if (!renderer->Initialize())
97 return scoped_ptr<GLRenderer>();
99 return renderer.Pass();
102 GLRenderer::GLRenderer(RendererClient* client,
103 OutputSurface* output_surface,
104 ResourceProvider* resource_provider,
105 int highp_threshold_min)
106 : DirectRenderer(client, resource_provider),
107 offscreen_framebuffer_id_(0),
108 shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)),
109 output_surface_(output_surface),
110 context_(output_surface->context3d()),
111 is_viewport_changed_(false),
112 is_backbuffer_discarded_(false),
113 discard_backbuffer_when_not_visible_(false),
114 is_using_bind_uniform_(false),
115 visible_(true),
116 is_scissor_enabled_(false),
117 highp_threshold_min_(highp_threshold_min),
118 on_demand_tile_raster_resource_id_(0) {
119 DCHECK(context_);
122 bool GLRenderer::Initialize() {
123 if (!context_->makeContextCurrent())
124 return false;
126 context_->pushGroupMarkerEXT("CompositorContext");
128 std::string extensions_string =
129 UTF16ToASCII(context_->getString(GL_EXTENSIONS));
130 std::vector<std::string> extensions_list;
131 base::SplitString(extensions_string, ' ', &extensions_list);
132 std::set<std::string> extensions(extensions_list.begin(),
133 extensions_list.end());
135 if (Settings().accelerate_painting &&
136 extensions.count("GL_EXT_texture_format_BGRA8888") &&
137 extensions.count("GL_EXT_read_format_bgra"))
138 capabilities_.using_accelerated_painting = true;
139 else
140 capabilities_.using_accelerated_painting = false;
142 capabilities_.using_partial_swap =
143 Settings().partial_swap_enabled &&
144 extensions.count("GL_CHROMIUM_post_sub_buffer");
146 // Use the SwapBuffers callback only with the threaded proxy.
147 if (client_->HasImplThread())
148 capabilities_.using_swap_complete_callback =
149 extensions.count("GL_CHROMIUM_swapbuffers_complete_callback") > 0;
151 capabilities_.using_set_visibility =
152 extensions.count("GL_CHROMIUM_set_visibility") > 0;
154 if (extensions.count("GL_CHROMIUM_iosurface") > 0)
155 DCHECK_GT(extensions.count("GL_ARB_texture_rectangle"), 0u);
157 capabilities_.using_gpu_memory_manager =
158 extensions.count("GL_CHROMIUM_gpu_memory_manager") > 0 &&
159 Settings().use_memory_management;
160 if (capabilities_.using_gpu_memory_manager)
161 context_->setMemoryAllocationChangedCallbackCHROMIUM(this);
163 capabilities_.using_egl_image =
164 extensions.count("GL_OES_EGL_image_external") > 0;
166 capabilities_.max_texture_size = resource_provider_->max_texture_size();
167 capabilities_.best_texture_format = resource_provider_->best_texture_format();
169 // The updater can access textures while the GLRenderer is using them.
170 capabilities_.allow_partial_texture_updates = true;
172 // Check for texture fast paths. Currently we always use MO8 textures,
173 // so we only need to avoid POT textures if we have an NPOT fast-path.
174 capabilities_.avoid_pow2_textures =
175 extensions.count("GL_CHROMIUM_fast_NPOT_MO8_textures") > 0;
177 capabilities_.using_offscreen_context3d = true;
179 is_using_bind_uniform_ =
180 extensions.count("GL_CHROMIUM_bind_uniform_location") > 0;
182 // Make sure scissoring starts as disabled.
183 GLC(context_, context_->disable(GL_SCISSOR_TEST));
184 DCHECK(!is_scissor_enabled_);
186 if (!InitializeSharedObjects())
187 return false;
189 // Make sure the viewport and context gets initialized, even if it is to zero.
190 ViewportChanged();
191 return true;
194 GLRenderer::~GLRenderer() {
195 context_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
196 CleanupSharedObjects();
199 const RendererCapabilities& GLRenderer::Capabilities() const {
200 return capabilities_;
203 WebGraphicsContext3D* GLRenderer::Context() { return context_; }
205 void GLRenderer::DebugGLCall(WebGraphicsContext3D* context,
206 const char* command,
207 const char* file,
208 int line) {
209 unsigned error = context->getError();
210 if (error != GL_NO_ERROR)
211 LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line
212 << "\n\tcommand: " << command << ", error "
213 << static_cast<int>(error) << "\n";
216 void GLRenderer::SetVisible(bool visible) {
217 if (visible_ == visible)
218 return;
219 visible_ = visible;
221 EnforceMemoryPolicy();
223 // TODO(jamesr): Replace setVisibilityCHROMIUM() with an extension to
224 // explicitly manage front/backbuffers
225 // crbug.com/116049
226 if (capabilities_.using_set_visibility)
227 context_->setVisibilityCHROMIUM(visible);
230 void GLRenderer::SendManagedMemoryStats(size_t bytes_visible,
231 size_t bytes_visible_and_nearby,
232 size_t bytes_allocated) {
233 WebKit::WebGraphicsManagedMemoryStats stats;
234 stats.bytesVisible = bytes_visible;
235 stats.bytesVisibleAndNearby = bytes_visible_and_nearby;
236 stats.bytesAllocated = bytes_allocated;
237 stats.backbufferRequested = !is_backbuffer_discarded_;
238 context_->sendManagedMemoryStatsCHROMIUM(&stats);
241 void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
243 void GLRenderer::ViewportChanged() { is_viewport_changed_ = true; }
245 void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
246 // On DEBUG builds, opaque render passes are cleared to blue to easily see
247 // regions that were not drawn on the screen.
248 if (frame->current_render_pass->has_transparent_background)
249 GLC(context_, context_->clearColor(0, 0, 0, 0));
250 else
251 GLC(context_, context_->clearColor(0, 0, 1, 1));
253 #ifdef NDEBUG
254 if (frame->current_render_pass->has_transparent_background)
255 #endif
256 context_->clear(GL_COLOR_BUFFER_BIT);
259 void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) {
260 // FIXME: Remove this once backbuffer is automatically recreated on first use
261 EnsureBackbuffer();
263 if (ViewportSize().IsEmpty())
264 return;
266 TRACE_EVENT0("cc", "GLRenderer::DrawLayers");
267 if (is_viewport_changed_) {
268 // Only reshape when we know we are going to draw. Otherwise, the reshape
269 // can leave the window at the wrong size if we never draw and the proper
270 // viewport size is never set.
271 is_viewport_changed_ = false;
272 output_surface_->Reshape(gfx::Size(ViewportWidth(), ViewportHeight()));
275 MakeContextCurrent();
276 // Bind the common vertex attributes used for drawing all the layers.
277 shared_geometry_->PrepareForDraw();
279 GLC(context_, context_->disable(GL_DEPTH_TEST));
280 GLC(context_, context_->disable(GL_CULL_FACE));
281 GLC(context_, context_->colorMask(true, true, true, true));
282 GLC(context_, context_->enable(GL_BLEND));
283 blend_shadow_ = true;
284 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
285 GLC(Context(), Context()->activeTexture(GL_TEXTURE0));
286 program_shadow_ = 0;
289 void GLRenderer::DoNoOp() {
290 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0));
291 GLC(context_, context_->flush());
294 void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
295 DCHECK(quad->rect.Contains(quad->visible_rect));
296 if (quad->material != DrawQuad::TEXTURE_CONTENT) {
297 FlushTextureQuadCache();
300 switch (quad->material) {
301 case DrawQuad::INVALID:
302 NOTREACHED();
303 break;
304 case DrawQuad::CHECKERBOARD:
305 DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
306 break;
307 case DrawQuad::DEBUG_BORDER:
308 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
309 break;
310 case DrawQuad::IO_SURFACE_CONTENT:
311 DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad));
312 break;
313 case DrawQuad::PICTURE_CONTENT:
314 DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad));
315 break;
316 case DrawQuad::RENDER_PASS:
317 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
318 break;
319 case DrawQuad::SOLID_COLOR:
320 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
321 break;
322 case DrawQuad::STREAM_VIDEO_CONTENT:
323 DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad));
324 break;
325 case DrawQuad::TEXTURE_CONTENT:
326 EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
327 break;
328 case DrawQuad::TILED_CONTENT:
329 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
330 break;
331 case DrawQuad::YUV_VIDEO_CONTENT:
332 DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad));
333 break;
337 void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
338 const CheckerboardDrawQuad* quad) {
339 SetBlendEnabled(quad->ShouldDrawWithBlending());
341 const TileCheckerboardProgram* program = GetTileCheckerboardProgram();
342 DCHECK(program && (program->initialized() || IsContextLost()));
343 SetUseProgram(program->program());
345 SkColor color = quad->color;
346 GLC(Context(),
347 Context()->uniform4f(program->fragment_shader().color_location(),
348 SkColorGetR(color) * (1.0f / 255.0f),
349 SkColorGetG(color) * (1.0f / 255.0f),
350 SkColorGetB(color) * (1.0f / 255.0f),
351 1));
353 const int checkerboard_width = 16;
354 float frequency = 1.0f / checkerboard_width;
356 gfx::Rect tile_rect = quad->rect;
357 float tex_offset_x = tile_rect.x() % checkerboard_width;
358 float tex_offset_y = tile_rect.y() % checkerboard_width;
359 float tex_scale_x = tile_rect.width();
360 float tex_scale_y = tile_rect.height();
361 GLC(Context(),
362 Context()->uniform4f(program->fragment_shader().tex_transform_location(),
363 tex_offset_x,
364 tex_offset_y,
365 tex_scale_x,
366 tex_scale_y));
368 GLC(Context(),
369 Context()->uniform1f(program->fragment_shader().frequency_location(),
370 frequency));
372 SetShaderOpacity(quad->opacity(),
373 program->fragment_shader().alpha_location());
374 DrawQuadGeometry(frame,
375 quad->quadTransform(),
376 quad->rect,
377 program->vertex_shader().matrix_location());
380 void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
381 const DebugBorderDrawQuad* quad) {
382 SetBlendEnabled(quad->ShouldDrawWithBlending());
384 static float gl_matrix[16];
385 const DebugBorderProgram* program = GetDebugBorderProgram();
386 DCHECK(program && (program->initialized() || IsContextLost()));
387 SetUseProgram(program->program());
389 // Use the full quad_rect for debug quads to not move the edges based on
390 // partial swaps.
391 gfx::Rect layer_rect = quad->rect;
392 gfx::Transform render_matrix = quad->quadTransform();
393 render_matrix.Translate(0.5f * layer_rect.width() + layer_rect.x(),
394 0.5f * layer_rect.height() + layer_rect.y());
395 render_matrix.Scale(layer_rect.width(), layer_rect.height());
396 GLRenderer::ToGLMatrix(&gl_matrix[0],
397 frame->projection_matrix * render_matrix);
398 GLC(Context(),
399 Context()->uniformMatrix4fv(
400 program->vertex_shader().matrix_location(), 1, false, &gl_matrix[0]));
402 SkColor color = quad->color;
403 float alpha = SkColorGetA(color) * (1.0f / 255.0f);
405 GLC(Context(),
406 Context()->uniform4f(program->fragment_shader().color_location(),
407 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
408 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
409 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
410 alpha));
412 GLC(Context(), Context()->lineWidth(quad->width));
414 // The indices for the line are stored in the same array as the triangle
415 // indices.
416 GLC(Context(),
417 Context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0));
420 static inline SkBitmap ApplyFilters(GLRenderer* renderer,
421 const WebKit::WebFilterOperations& filters,
422 ScopedResource* source_texture_resource) {
423 if (filters.isEmpty())
424 return SkBitmap();
426 ContextProvider* offscreen_contexts =
427 renderer->resource_provider()->offscreen_context_provider();
428 if (!offscreen_contexts || !offscreen_contexts->GrContext())
429 return SkBitmap();
431 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
432 source_texture_resource->id());
434 // Flush the compositor context to ensure that textures there are available
435 // in the shared context. Do this after locking/creating the compositor
436 // texture.
437 renderer->resource_provider()->Flush();
439 // Make sure skia uses the correct GL context.
440 offscreen_contexts->Context3d()->makeContextCurrent();
442 SkBitmap source =
443 RenderSurfaceFilters::Apply(filters,
444 lock.texture_id(),
445 source_texture_resource->size(),
446 offscreen_contexts->GrContext());
448 // Flush skia context so that all the rendered stuff appears on the
449 // texture.
450 offscreen_contexts->GrContext()->flush();
452 // Flush the GL context so rendering results from this context are
453 // visible in the compositor's context.
454 offscreen_contexts->Context3d()->flush();
456 // Use the compositor's GL context again.
457 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent();
458 return source;
461 static SkBitmap ApplyImageFilter(GLRenderer* renderer,
462 SkImageFilter* filter,
463 ScopedResource* source_texture_resource) {
464 if (!filter)
465 return SkBitmap();
467 ContextProvider* offscreen_contexts =
468 renderer->resource_provider()->offscreen_context_provider();
469 if (!offscreen_contexts || !offscreen_contexts->GrContext())
470 return SkBitmap();
472 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
473 source_texture_resource->id());
475 // Flush the compositor context to ensure that textures there are available
476 // in the shared context. Do this after locking/creating the compositor
477 // texture.
478 renderer->resource_provider()->Flush();
480 // Make sure skia uses the correct GL context.
481 offscreen_contexts->Context3d()->makeContextCurrent();
483 // Wrap the source texture in a Ganesh platform texture.
484 GrBackendTextureDesc backend_texture_description;
485 backend_texture_description.fWidth = source_texture_resource->size().width();
486 backend_texture_description.fHeight =
487 source_texture_resource->size().height();
488 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
489 backend_texture_description.fTextureHandle = lock.texture_id();
490 backend_texture_description.fOrigin = kTopLeft_GrSurfaceOrigin;
491 skia::RefPtr<GrTexture> texture =
492 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
493 backend_texture_description));
495 // Place the platform texture inside an SkBitmap.
496 SkBitmap source;
497 source.setConfig(SkBitmap::kARGB_8888_Config,
498 source_texture_resource->size().width(),
499 source_texture_resource->size().height());
500 skia::RefPtr<SkGrPixelRef> pixel_ref =
501 skia::AdoptRef(new SkGrPixelRef(texture.get()));
502 source.setPixelRef(pixel_ref.get());
504 // Create a scratch texture for backing store.
505 GrTextureDesc desc;
506 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
507 desc.fSampleCnt = 0;
508 desc.fWidth = source.width();
509 desc.fHeight = source.height();
510 desc.fConfig = kSkia8888_GrPixelConfig;
511 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
512 GrAutoScratchTexture scratch_texture(
513 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
514 skia::RefPtr<GrTexture> backing_store =
515 skia::AdoptRef(scratch_texture.detach());
517 // Create a device and canvas using that backing store.
518 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
519 SkCanvas canvas(&device);
521 // Draw the source bitmap through the filter to the canvas.
522 SkPaint paint;
523 paint.setImageFilter(filter);
524 canvas.clear(SK_ColorTRANSPARENT);
525 canvas.drawSprite(source, 0, 0, &paint);
527 // Flush skia context so that all the rendered stuff appears on the
528 // texture.
529 offscreen_contexts->GrContext()->flush();
531 // Flush the GL context so rendering results from this context are
532 // visible in the compositor's context.
533 offscreen_contexts->Context3d()->flush();
535 // Use the compositor's GL context again.
536 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent();
538 return device.accessBitmap(false);
541 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
542 DrawingFrame* frame,
543 const RenderPassDrawQuad* quad,
544 const gfx::Transform& contents_device_transform,
545 const gfx::Transform& contents_device_transform_inverse) {
546 // This method draws a background filter, which applies a filter to any pixels
547 // behind the quad and seen through its background. The algorithm works as
548 // follows:
549 // 1. Compute a bounding box around the pixels that will be visible through
550 // the quad.
551 // 2. Read the pixels in the bounding box into a buffer R.
552 // 3. Apply the background filter to R, so that it is applied in the pixels'
553 // coordinate space.
554 // 4. Apply the quad's inverse transform to map the pixels in R into the
555 // quad's content space. This implicitly clips R by the content bounds of the
556 // quad since the destination texture has bounds matching the quad's content.
557 // 5. Draw the background texture for the contents using the same transform as
558 // used to draw the contents itself. This is done without blending to replace
559 // the current background pixels with the new filtered background.
560 // 6. Draw the contents of the quad over drop of the new background with
561 // blending, as per usual. The filtered background pixels will show through
562 // any non-opaque pixels in this draws.
564 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
566 // FIXME: When this algorithm changes, update
567 // LayerTreeHost::PrioritizeTextures() accordingly.
569 const WebKit::WebFilterOperations& filters = quad->background_filters;
570 DCHECK(!filters.isEmpty());
572 // FIXME: We only allow background filters on an opaque render surface because
573 // other surfaces may contain translucent pixels, and the contents behind
574 // those translucent pixels wouldn't have the filter applied.
575 if (frame->current_render_pass->has_transparent_background)
576 return scoped_ptr<ScopedResource>();
577 DCHECK(!frame->current_texture);
579 // FIXME: Do a single readback for both the surface and replica and cache the
580 // filtered results (once filter textures are not reused).
581 gfx::Rect device_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
582 contents_device_transform, SharedGeometryQuad().BoundingBox()));
584 int top, right, bottom, left;
585 filters.getOutsets(top, right, bottom, left);
586 device_rect.Inset(-left, -top, -right, -bottom);
588 device_rect.Intersect(frame->current_render_pass->output_rect);
590 scoped_ptr<ScopedResource> device_background_texture =
591 ScopedResource::create(resource_provider_);
592 if (!GetFramebufferTexture(device_background_texture.get(), device_rect))
593 return scoped_ptr<ScopedResource>();
595 SkBitmap filtered_device_background =
596 ApplyFilters(this, filters, device_background_texture.get());
597 if (!filtered_device_background.getTexture())
598 return scoped_ptr<ScopedResource>();
600 GrTexture* texture =
601 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
602 int filtered_device_background_texture_id = texture->getTextureHandle();
604 scoped_ptr<ScopedResource> background_texture =
605 ScopedResource::create(resource_provider_);
606 if (!background_texture->Allocate(quad->rect.size(),
607 GL_RGBA,
608 ResourceProvider::TextureUsageFramebuffer))
609 return scoped_ptr<ScopedResource>();
611 const RenderPass* target_render_pass = frame->current_render_pass;
612 bool using_background_texture =
613 UseScopedTexture(frame, background_texture.get(), quad->rect);
615 if (using_background_texture) {
616 // Copy the readback pixels from device to the background texture for the
617 // surface.
618 gfx::Transform device_to_framebuffer_transform;
619 device_to_framebuffer_transform.Translate(
620 quad->rect.width() * 0.5f + quad->rect.x(),
621 quad->rect.height() * 0.5f + quad->rect.y());
622 device_to_framebuffer_transform.Scale(quad->rect.width(),
623 quad->rect.height());
624 device_to_framebuffer_transform.PreconcatTransform(
625 contents_device_transform_inverse);
627 #ifndef NDEBUG
628 GLC(Context(), Context()->clearColor(0, 0, 1, 1));
629 Context()->clear(GL_COLOR_BUFFER_BIT);
630 #endif
632 CopyTextureToFramebuffer(frame,
633 filtered_device_background_texture_id,
634 device_rect,
635 device_to_framebuffer_transform);
638 UseRenderPass(frame, target_render_pass);
640 if (!using_background_texture)
641 return scoped_ptr<ScopedResource>();
642 return background_texture.Pass();
645 void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
646 const RenderPassDrawQuad* quad) {
647 SetBlendEnabled(quad->ShouldDrawWithBlending());
649 CachedResource* contents_texture =
650 render_pass_textures_.get(quad->render_pass_id);
651 if (!contents_texture || !contents_texture->id())
652 return;
654 gfx::Transform quad_rect_matrix;
655 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
656 gfx::Transform contents_device_transform =
657 frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
658 contents_device_transform.FlattenTo2d();
660 // Can only draw surface if device matrix is invertible.
661 gfx::Transform contents_device_transform_inverse(
662 gfx::Transform::kSkipInitialization);
663 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
664 return;
666 scoped_ptr<ScopedResource> background_texture;
667 if (!quad->background_filters.isEmpty()) {
668 // The pixels from the filtered background should completely replace the
669 // current pixel values.
670 bool disable_blending = blend_enabled();
671 if (disable_blending)
672 SetBlendEnabled(false);
674 background_texture = DrawBackgroundFilters(
675 frame,
676 quad,
677 contents_device_transform,
678 contents_device_transform_inverse);
680 if (disable_blending)
681 SetBlendEnabled(true);
684 // FIXME: Cache this value so that we don't have to do it for both the surface
685 // and its replica. Apply filters to the contents texture.
686 SkBitmap filter_bitmap;
687 SkScalar color_matrix[20];
688 bool use_color_matrix = false;
689 if (quad->filter) {
690 SkColorFilter* cf;
691 if ((quad->filter->asColorFilter(&cf)) && cf->asColorMatrix(color_matrix) &&
692 !quad->filter->getInput(0)) {
693 // We have a single color matrix as a filter; apply it locally
694 // in the compositor.
695 use_color_matrix = true;
696 } else {
697 filter_bitmap =
698 ApplyImageFilter(this, quad->filter.get(), contents_texture);
700 } else {
701 filter_bitmap = ApplyFilters(this, quad->filters, contents_texture);
704 // Draw the background texture if there is one.
705 if (background_texture) {
706 DCHECK(background_texture->size() == quad->rect.size());
707 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
708 background_texture->id());
709 CopyTextureToFramebuffer(
710 frame, lock.texture_id(), quad->rect, quad->quadTransform());
713 bool clipped = false;
714 gfx::QuadF device_quad = MathUtil::MapQuad(
715 contents_device_transform, SharedGeometryQuad(), &clipped);
716 DCHECK(!clipped);
717 LayerQuad device_layer_bounds(gfx::QuadF(device_quad.BoundingBox()));
718 LayerQuad device_layer_edges(device_quad);
720 // Use anti-aliasing programs only when necessary.
721 bool use_aa = (!device_quad.IsRectilinear() ||
722 !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(),
723 kAntiAliasingEpsilon));
724 if (use_aa) {
725 device_layer_bounds.InflateAntiAliasingDistance();
726 device_layer_edges.InflateAntiAliasingDistance();
729 scoped_ptr<ResourceProvider::ScopedReadLockGL> mask_resource_lock;
730 unsigned mask_texture_id = 0;
731 if (quad->mask_resource_id) {
732 mask_resource_lock.reset(new ResourceProvider::ScopedReadLockGL(
733 resource_provider_, quad->mask_resource_id));
734 mask_texture_id = mask_resource_lock->texture_id();
737 // FIXME: use the background_texture and blend the background in with this
738 // draw instead of having a separate copy of the background texture.
740 scoped_ptr<ResourceProvider::ScopedReadLockGL> contents_resource_lock;
741 if (filter_bitmap.getTexture()) {
742 GrTexture* texture =
743 reinterpret_cast<GrTexture*>(filter_bitmap.getTexture());
744 Context()->bindTexture(GL_TEXTURE_2D, texture->getTextureHandle());
745 } else {
746 contents_resource_lock = make_scoped_ptr(
747 new ResourceProvider::ScopedSamplerGL(resource_provider_,
748 contents_texture->id(),
749 GL_TEXTURE_2D,
750 GL_LINEAR));
753 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
754 context_, highp_threshold_min_,
755 quad->shared_quad_state->visible_content_rect.bottom_right());
757 int shader_quad_location = -1;
758 int shader_edge_location = -1;
759 int shader_mask_sampler_location = -1;
760 int shader_mask_tex_coord_scale_location = -1;
761 int shader_mask_tex_coord_offset_location = -1;
762 int shader_matrix_location = -1;
763 int shader_alpha_location = -1;
764 int shader_color_matrix_location = -1;
765 int shader_color_offset_location = -1;
766 int shader_tex_transform_location = -1;
767 int shader_tex_scale_location = -1;
769 if (use_aa && mask_texture_id && !use_color_matrix) {
770 const RenderPassMaskProgramAA* program =
771 GetRenderPassMaskProgramAA(tex_coord_precision);
772 SetUseProgram(program->program());
773 GLC(Context(),
774 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
776 shader_quad_location = program->vertex_shader().point_location();
777 shader_edge_location = program->fragment_shader().edge_location();
778 shader_mask_sampler_location =
779 program->fragment_shader().mask_sampler_location();
780 shader_mask_tex_coord_scale_location =
781 program->fragment_shader().mask_tex_coord_scale_location();
782 shader_mask_tex_coord_offset_location =
783 program->fragment_shader().mask_tex_coord_offset_location();
784 shader_matrix_location = program->vertex_shader().matrix_location();
785 shader_alpha_location = program->fragment_shader().alpha_location();
786 shader_tex_scale_location = program->vertex_shader().tex_scale_location();
787 } else if (!use_aa && mask_texture_id && !use_color_matrix) {
788 const RenderPassMaskProgram* program =
789 GetRenderPassMaskProgram(tex_coord_precision);
790 SetUseProgram(program->program());
791 GLC(Context(),
792 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
794 shader_mask_sampler_location =
795 program->fragment_shader().mask_sampler_location();
796 shader_mask_tex_coord_scale_location =
797 program->fragment_shader().mask_tex_coord_scale_location();
798 shader_mask_tex_coord_offset_location =
799 program->fragment_shader().mask_tex_coord_offset_location();
800 shader_matrix_location = program->vertex_shader().matrix_location();
801 shader_alpha_location = program->fragment_shader().alpha_location();
802 shader_tex_transform_location =
803 program->vertex_shader().tex_transform_location();
804 } else if (use_aa && !mask_texture_id && !use_color_matrix) {
805 const RenderPassProgramAA* program =
806 GetRenderPassProgramAA(tex_coord_precision);
807 SetUseProgram(program->program());
808 GLC(Context(),
809 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
811 shader_quad_location = program->vertex_shader().point_location();
812 shader_edge_location = program->fragment_shader().edge_location();
813 shader_matrix_location = program->vertex_shader().matrix_location();
814 shader_alpha_location = program->fragment_shader().alpha_location();
815 shader_tex_scale_location = program->vertex_shader().tex_scale_location();
816 } else if (use_aa && mask_texture_id && use_color_matrix) {
817 const RenderPassMaskColorMatrixProgramAA* program =
818 GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision);
819 SetUseProgram(program->program());
820 GLC(Context(),
821 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
823 shader_matrix_location = program->vertex_shader().matrix_location();
824 shader_quad_location = program->vertex_shader().point_location();
825 shader_tex_scale_location = program->vertex_shader().tex_scale_location();
826 shader_edge_location = program->fragment_shader().edge_location();
827 shader_alpha_location = program->fragment_shader().alpha_location();
828 shader_mask_sampler_location =
829 program->fragment_shader().mask_sampler_location();
830 shader_mask_tex_coord_scale_location =
831 program->fragment_shader().mask_tex_coord_scale_location();
832 shader_mask_tex_coord_offset_location =
833 program->fragment_shader().mask_tex_coord_offset_location();
834 shader_color_matrix_location =
835 program->fragment_shader().color_matrix_location();
836 shader_color_offset_location =
837 program->fragment_shader().color_offset_location();
838 } else if (use_aa && !mask_texture_id && use_color_matrix) {
839 const RenderPassColorMatrixProgramAA* program =
840 GetRenderPassColorMatrixProgramAA(tex_coord_precision);
841 SetUseProgram(program->program());
842 GLC(Context(),
843 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
845 shader_matrix_location = program->vertex_shader().matrix_location();
846 shader_quad_location = program->vertex_shader().point_location();
847 shader_tex_scale_location = program->vertex_shader().tex_scale_location();
848 shader_edge_location = program->fragment_shader().edge_location();
849 shader_alpha_location = program->fragment_shader().alpha_location();
850 shader_color_matrix_location =
851 program->fragment_shader().color_matrix_location();
852 shader_color_offset_location =
853 program->fragment_shader().color_offset_location();
854 } else if (!use_aa && mask_texture_id && use_color_matrix) {
855 const RenderPassMaskColorMatrixProgram* program =
856 GetRenderPassMaskColorMatrixProgram(tex_coord_precision);
857 SetUseProgram(program->program());
858 GLC(Context(),
859 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
861 shader_matrix_location = program->vertex_shader().matrix_location();
862 shader_tex_transform_location =
863 program->vertex_shader().tex_transform_location();
864 shader_mask_sampler_location =
865 program->fragment_shader().mask_sampler_location();
866 shader_mask_tex_coord_scale_location =
867 program->fragment_shader().mask_tex_coord_scale_location();
868 shader_mask_tex_coord_offset_location =
869 program->fragment_shader().mask_tex_coord_offset_location();
870 shader_alpha_location = program->fragment_shader().alpha_location();
871 shader_color_matrix_location =
872 program->fragment_shader().color_matrix_location();
873 shader_color_offset_location =
874 program->fragment_shader().color_offset_location();
875 } else if (!use_aa && !mask_texture_id && use_color_matrix) {
876 const RenderPassColorMatrixProgram* program =
877 GetRenderPassColorMatrixProgram(tex_coord_precision);
878 SetUseProgram(program->program());
879 GLC(Context(),
880 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
882 shader_matrix_location = program->vertex_shader().matrix_location();
883 shader_tex_transform_location =
884 program->vertex_shader().tex_transform_location();
885 shader_alpha_location = program->fragment_shader().alpha_location();
886 shader_color_matrix_location =
887 program->fragment_shader().color_matrix_location();
888 shader_color_offset_location =
889 program->fragment_shader().color_offset_location();
890 } else {
891 const RenderPassProgram* program =
892 GetRenderPassProgram(tex_coord_precision);
893 SetUseProgram(program->program());
894 GLC(Context(),
895 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
897 shader_matrix_location = program->vertex_shader().matrix_location();
898 shader_alpha_location = program->fragment_shader().alpha_location();
899 shader_tex_transform_location =
900 program->vertex_shader().tex_transform_location();
902 float tex_scale_x =
903 quad->rect.width() / static_cast<float>(contents_texture->size().width());
904 float tex_scale_y = quad->rect.height() /
905 static_cast<float>(contents_texture->size().height());
906 DCHECK_LE(tex_scale_x, 1.0f);
907 DCHECK_LE(tex_scale_y, 1.0f);
909 if (shader_tex_transform_location != -1) {
910 GLC(Context(),
911 Context()->uniform4f(shader_tex_transform_location,
912 0.0f,
913 0.0f,
914 tex_scale_x,
915 tex_scale_y));
916 } else if (shader_tex_scale_location != -1) {
917 GLC(Context(),
918 Context()->uniform2f(
919 shader_tex_scale_location, tex_scale_x, tex_scale_y));
920 } else {
921 DCHECK(IsContextLost());
924 if (shader_mask_sampler_location != -1) {
925 DCHECK_NE(shader_mask_tex_coord_scale_location, 1);
926 DCHECK_NE(shader_mask_tex_coord_offset_location, 1);
927 GLC(Context(), Context()->activeTexture(GL_TEXTURE1));
928 GLC(Context(), Context()->uniform1i(shader_mask_sampler_location, 1));
929 GLC(Context(),
930 Context()->uniform2f(shader_mask_tex_coord_offset_location,
931 quad->mask_uv_rect.x(),
932 quad->mask_uv_rect.y()));
933 GLC(Context(),
934 Context()->uniform2f(shader_mask_tex_coord_scale_location,
935 quad->mask_uv_rect.width() / tex_scale_x,
936 quad->mask_uv_rect.height() / tex_scale_y));
937 resource_provider_->BindForSampling(
938 quad->mask_resource_id, GL_TEXTURE_2D, GL_LINEAR);
939 GLC(Context(), Context()->activeTexture(GL_TEXTURE0));
942 if (shader_edge_location != -1) {
943 float edge[24];
944 device_layer_edges.ToFloatArray(edge);
945 device_layer_bounds.ToFloatArray(&edge[12]);
946 GLC(Context(), Context()->uniform3fv(shader_edge_location, 8, edge));
949 if (shader_color_matrix_location != -1) {
950 float matrix[16];
951 for (int i = 0; i < 4; ++i) {
952 for (int j = 0; j < 4; ++j)
953 matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]);
955 GLC(Context(),
956 Context()->uniformMatrix4fv(
957 shader_color_matrix_location, 1, false, matrix));
959 static const float kScale = 1.0f / 255.0f;
960 if (shader_color_offset_location != -1) {
961 float offset[4];
962 for (int i = 0; i < 4; ++i)
963 offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale;
965 GLC(Context(),
966 Context()->uniform4fv(shader_color_offset_location, 1, offset));
969 // Map device space quad to surface space. contents_device_transform has no 3d
970 // component since it was flattened, so we don't need to project.
971 gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse,
972 device_layer_edges.ToQuadF(),
973 &clipped);
974 DCHECK(!clipped);
976 SetShaderOpacity(quad->opacity(), shader_alpha_location);
977 SetShaderQuadF(surface_quad, shader_quad_location);
978 DrawQuadGeometry(
979 frame, quad->quadTransform(), quad->rect, shader_matrix_location);
981 // Flush the compositor context before the filter bitmap goes out of
982 // scope, so the draw gets processed before the filter texture gets deleted.
983 if (filter_bitmap.getTexture())
984 context_->flush();
987 struct SolidColorProgramUniforms {
988 unsigned program;
989 unsigned matrix_location;
990 unsigned color_location;
991 unsigned point_location;
992 unsigned tex_scale_location;
993 unsigned edge_location;
996 template<class T>
997 static void SolidColorUniformLocation(T program,
998 SolidColorProgramUniforms* uniforms) {
999 uniforms->program = program->program();
1000 uniforms->matrix_location = program->vertex_shader().matrix_location();
1001 uniforms->color_location = program->fragment_shader().color_location();
1002 uniforms->point_location = program->vertex_shader().point_location();
1003 uniforms->tex_scale_location = program->vertex_shader().tex_scale_location();
1004 uniforms->edge_location = program->fragment_shader().edge_location();
1007 bool GLRenderer::SetupQuadForAntialiasing(
1008 const gfx::Transform& device_transform,
1009 const DrawQuad* quad,
1010 gfx::QuadF* local_quad,
1011 float edge[24]) const {
1012 gfx::Rect tile_rect = quad->visible_rect;
1014 bool clipped = false;
1015 gfx::QuadF device_layer_quad = MathUtil::MapQuad(
1016 device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped);
1017 DCHECK(!clipped);
1019 bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear();
1020 bool is_nearest_rect_within_epsilon = is_axis_aligned_in_target &&
1021 gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(),
1022 kAntiAliasingEpsilon);
1023 bool use_aa = !clipped && !is_nearest_rect_within_epsilon && quad->IsEdge();
1025 if (!use_aa)
1026 return false;
1028 LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox()));
1029 device_layer_bounds.InflateAntiAliasingDistance();
1031 LayerQuad device_layer_edges(device_layer_quad);
1032 device_layer_edges.InflateAntiAliasingDistance();
1034 device_layer_edges.ToFloatArray(edge);
1035 device_layer_bounds.ToFloatArray(&edge[12]);
1037 gfx::PointF bottom_right = tile_rect.bottom_right();
1038 gfx::PointF bottom_left = tile_rect.bottom_left();
1039 gfx::PointF top_left = tile_rect.origin();
1040 gfx::PointF top_right = tile_rect.top_right();
1042 // Map points to device space.
1043 bottom_right = MathUtil::MapPoint(device_transform, bottom_right, &clipped);
1044 DCHECK(!clipped);
1045 bottom_left = MathUtil::MapPoint(device_transform, bottom_left, &clipped);
1046 DCHECK(!clipped);
1047 top_left = MathUtil::MapPoint(device_transform, top_left, &clipped);
1048 DCHECK(!clipped);
1049 top_right = MathUtil::MapPoint(device_transform, top_right, &clipped);
1050 DCHECK(!clipped);
1052 LayerQuad::Edge bottom_edge(bottom_right, bottom_left);
1053 LayerQuad::Edge left_edge(bottom_left, top_left);
1054 LayerQuad::Edge top_edge(top_left, top_right);
1055 LayerQuad::Edge right_edge(top_right, bottom_right);
1057 // Only apply anti-aliasing to edges not clipped by culling or scissoring.
1058 if (quad->IsTopEdge() && tile_rect.y() == quad->rect.y())
1059 top_edge = device_layer_edges.top();
1060 if (quad->IsLeftEdge() && tile_rect.x() == quad->rect.x())
1061 left_edge = device_layer_edges.left();
1062 if (quad->IsRightEdge() && tile_rect.right() == quad->rect.right())
1063 right_edge = device_layer_edges.right();
1064 if (quad->IsBottomEdge() && tile_rect.bottom() == quad->rect.bottom())
1065 bottom_edge = device_layer_edges.bottom();
1067 float sign = gfx::QuadF(tile_rect).IsCounterClockwise() ? -1 : 1;
1068 bottom_edge.scale(sign);
1069 left_edge.scale(sign);
1070 top_edge.scale(sign);
1071 right_edge.scale(sign);
1073 // Create device space quad.
1074 LayerQuad device_quad(left_edge, top_edge, right_edge, bottom_edge);
1076 // Map device space quad to local space. device_transform has no 3d
1077 // component since it was flattened, so we don't need to project. We should
1078 // have already checked that the transform was uninvertible above.
1079 gfx::Transform inverse_device_transform(
1080 gfx::Transform::kSkipInitialization);
1081 bool did_invert = device_transform.GetInverse(&inverse_device_transform);
1082 DCHECK(did_invert);
1083 *local_quad = MathUtil::MapQuad(
1084 inverse_device_transform, device_quad.ToQuadF(), &clipped);
1085 // We should not DCHECK(!clipped) here, because anti-aliasing inflation may
1086 // cause device_quad to become clipped. To our knowledge this scenario does
1087 // not need to be handled differently than the unclipped case.
1089 return true;
1092 void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame,
1093 const SolidColorDrawQuad* quad) {
1094 SetBlendEnabled(quad->ShouldDrawWithBlending());
1095 gfx::Rect tile_rect = quad->visible_rect;
1097 gfx::Transform device_transform =
1098 frame->window_matrix * frame->projection_matrix * quad->quadTransform();
1099 device_transform.FlattenTo2d();
1100 if (!device_transform.IsInvertible())
1101 return;
1103 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect));
1104 float edge[24];
1105 bool use_aa = SetupQuadForAntialiasing(
1106 device_transform, quad, &local_quad, edge);
1108 SolidColorProgramUniforms uniforms;
1109 if (use_aa)
1110 SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms);
1111 else
1112 SolidColorUniformLocation(GetSolidColorProgram(), &uniforms);
1113 SetUseProgram(uniforms.program);
1115 SkColor color = quad->color;
1116 float opacity = quad->opacity();
1117 float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
1119 GLC(Context(),
1120 Context()->uniform4f(uniforms.color_location,
1121 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
1122 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
1123 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
1124 alpha));
1126 if (use_aa)
1127 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge));
1129 // Enable blending when the quad properties require it or if we decided
1130 // to use antialiasing.
1131 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
1133 // Normalize to tile_rect.
1134 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
1136 SetShaderQuadF(local_quad, uniforms.point_location);
1138 // The transform and vertex data are used to figure out the extents that the
1139 // un-antialiased quad should have and which vertex this is and the float
1140 // quad passed in via uniform is the actual geometry that gets used to draw
1141 // it. This is why this centered rect is used and not the original quad_rect.
1142 gfx::RectF centered_rect(gfx::PointF(-0.5f * tile_rect.width(),
1143 -0.5f * tile_rect.height()),
1144 tile_rect.size());
1145 DrawQuadGeometry(frame, quad->quadTransform(),
1146 centered_rect, uniforms.matrix_location);
1149 struct TileProgramUniforms {
1150 unsigned program;
1151 unsigned sampler_location;
1152 unsigned vertex_tex_transform_location;
1153 unsigned fragment_tex_transform_location;
1154 unsigned edge_location;
1155 unsigned matrix_location;
1156 unsigned alpha_location;
1157 unsigned point_location;
1160 template <class T>
1161 static void TileUniformLocation(T program, TileProgramUniforms* uniforms) {
1162 uniforms->program = program->program();
1163 uniforms->vertex_tex_transform_location =
1164 program->vertex_shader().vertex_tex_transform_location();
1165 uniforms->matrix_location = program->vertex_shader().matrix_location();
1166 uniforms->point_location = program->vertex_shader().point_location();
1168 uniforms->sampler_location = program->fragment_shader().sampler_location();
1169 uniforms->alpha_location = program->fragment_shader().alpha_location();
1170 uniforms->fragment_tex_transform_location =
1171 program->fragment_shader().fragment_tex_transform_location();
1172 uniforms->edge_location = program->fragment_shader().edge_location();
1175 void GLRenderer::DrawTileQuad(const DrawingFrame* frame,
1176 const TileDrawQuad* quad) {
1177 DrawContentQuad(frame, quad, quad->resource_id);
1180 void GLRenderer::DrawContentQuad(const DrawingFrame* frame,
1181 const ContentDrawQuadBase* quad,
1182 ResourceProvider::ResourceId resource_id) {
1183 gfx::Rect tile_rect = quad->visible_rect;
1185 gfx::RectF tex_coord_rect = quad->tex_coord_rect;
1186 float tex_to_geom_scale_x = quad->rect.width() / tex_coord_rect.width();
1187 float tex_to_geom_scale_y = quad->rect.height() / tex_coord_rect.height();
1189 // tex_coord_rect corresponds to quad_rect, but quad_visible_rect may be
1190 // smaller than quad_rect due to occlusion or clipping. Adjust
1191 // tex_coord_rect to match.
1192 gfx::Vector2d top_left_diff = tile_rect.origin() - quad->rect.origin();
1193 gfx::Vector2d bottom_right_diff =
1194 tile_rect.bottom_right() - quad->rect.bottom_right();
1195 tex_coord_rect.Inset(top_left_diff.x() / tex_to_geom_scale_x,
1196 top_left_diff.y() / tex_to_geom_scale_y,
1197 -bottom_right_diff.x() / tex_to_geom_scale_x,
1198 -bottom_right_diff.y() / tex_to_geom_scale_y);
1200 gfx::RectF clamp_geom_rect(tile_rect);
1201 gfx::RectF clamp_tex_rect(tex_coord_rect);
1202 // Clamp texture coordinates to avoid sampling outside the layer
1203 // by deflating the tile region half a texel or half a texel
1204 // minus epsilon for one pixel layers. The resulting clamp region
1205 // is mapped to the unit square by the vertex shader and mapped
1206 // back to normalized texture coordinates by the fragment shader
1207 // after being clamped to 0-1 range.
1208 float tex_clamp_x = std::min(
1209 0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon);
1210 float tex_clamp_y = std::min(
1211 0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon);
1212 float geom_clamp_x = std::min(
1213 tex_clamp_x * tex_to_geom_scale_x,
1214 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon);
1215 float geom_clamp_y = std::min(
1216 tex_clamp_y * tex_to_geom_scale_y,
1217 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon);
1218 clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y);
1219 clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y);
1221 // Map clamping rectangle to unit square.
1222 float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width();
1223 float vertex_tex_translate_y =
1224 -clamp_geom_rect.y() / clamp_geom_rect.height();
1225 float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width();
1226 float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height();
1228 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1229 context_, highp_threshold_min_, quad->texture_size);
1231 // Map to normalized texture coordinates.
1232 gfx::Size texture_size = quad->texture_size;
1233 float fragment_tex_translate_x = clamp_tex_rect.x() / texture_size.width();
1234 float fragment_tex_translate_y = clamp_tex_rect.y() / texture_size.height();
1235 float fragment_tex_scale_x = clamp_tex_rect.width() / texture_size.width();
1236 float fragment_tex_scale_y = clamp_tex_rect.height() / texture_size.height();
1238 gfx::Transform device_transform =
1239 frame->window_matrix * frame->projection_matrix * quad->quadTransform();
1240 device_transform.FlattenTo2d();
1241 if (!device_transform.IsInvertible())
1242 return;
1244 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect));
1245 float edge[24];
1246 bool use_aa = SetupQuadForAntialiasing(
1247 device_transform, quad, &local_quad, edge);
1249 TileProgramUniforms uniforms;
1250 if (use_aa) {
1251 if (quad->swizzle_contents) {
1252 TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision),
1253 &uniforms);
1254 } else {
1255 TileUniformLocation(GetTileProgramAA(tex_coord_precision), &uniforms);
1257 } else {
1258 if (quad->ShouldDrawWithBlending()) {
1259 if (quad->swizzle_contents) {
1260 TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision),
1261 &uniforms);
1262 } else {
1263 TileUniformLocation(GetTileProgram(tex_coord_precision), &uniforms);
1265 } else {
1266 if (quad->swizzle_contents) {
1267 TileUniformLocation(GetTileProgramSwizzleOpaque(tex_coord_precision),
1268 &uniforms);
1269 } else {
1270 TileUniformLocation(GetTileProgramOpaque(tex_coord_precision),
1271 &uniforms);
1276 SetUseProgram(uniforms.program);
1277 GLC(Context(), Context()->uniform1i(uniforms.sampler_location, 0));
1278 bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
1279 GLenum filter = (use_aa || scaled ||
1280 !quad->quadTransform().IsIdentityOrIntegerTranslation())
1281 ? GL_LINEAR
1282 : GL_NEAREST;
1283 ResourceProvider::ScopedSamplerGL quad_resource_lock(
1284 resource_provider_, resource_id, GL_TEXTURE_2D, filter);
1286 if (use_aa) {
1287 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge));
1289 GLC(Context(),
1290 Context()->uniform4f(uniforms.vertex_tex_transform_location,
1291 vertex_tex_translate_x,
1292 vertex_tex_translate_y,
1293 vertex_tex_scale_x,
1294 vertex_tex_scale_y));
1295 GLC(Context(),
1296 Context()->uniform4f(uniforms.fragment_tex_transform_location,
1297 fragment_tex_translate_x,
1298 fragment_tex_translate_y,
1299 fragment_tex_scale_x,
1300 fragment_tex_scale_y));
1301 } else {
1302 // Move fragment shader transform to vertex shader. We can do this while
1303 // still producing correct results as fragment_tex_transform_location
1304 // should always be non-negative when tiles are transformed in a way
1305 // that could result in sampling outside the layer.
1306 vertex_tex_scale_x *= fragment_tex_scale_x;
1307 vertex_tex_scale_y *= fragment_tex_scale_y;
1308 vertex_tex_translate_x *= fragment_tex_scale_x;
1309 vertex_tex_translate_y *= fragment_tex_scale_y;
1310 vertex_tex_translate_x += fragment_tex_translate_x;
1311 vertex_tex_translate_y += fragment_tex_translate_y;
1313 GLC(Context(),
1314 Context()->uniform4f(uniforms.vertex_tex_transform_location,
1315 vertex_tex_translate_x,
1316 vertex_tex_translate_y,
1317 vertex_tex_scale_x,
1318 vertex_tex_scale_y));
1321 // Enable blending when the quad properties require it or if we decided
1322 // to use antialiasing.
1323 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
1325 // Normalize to tile_rect.
1326 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
1328 SetShaderOpacity(quad->opacity(), uniforms.alpha_location);
1329 SetShaderQuadF(local_quad, uniforms.point_location);
1331 // The transform and vertex data are used to figure out the extents that the
1332 // un-antialiased quad should have and which vertex this is and the float
1333 // quad passed in via uniform is the actual geometry that gets used to draw
1334 // it. This is why this centered rect is used and not the original quad_rect.
1335 gfx::RectF centered_rect(
1336 gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
1337 tile_rect.size());
1338 DrawQuadGeometry(
1339 frame, quad->quadTransform(), centered_rect, uniforms.matrix_location);
1342 void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
1343 const YUVVideoDrawQuad* quad) {
1344 SetBlendEnabled(quad->ShouldDrawWithBlending());
1346 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1347 context_, highp_threshold_min_,
1348 quad->shared_quad_state->visible_content_rect.bottom_right());
1350 const VideoYUVProgram* program = GetVideoYUVProgram(tex_coord_precision);
1351 DCHECK(program && (program->initialized() || IsContextLost()));
1353 GLC(Context(), Context()->activeTexture(GL_TEXTURE1));
1354 ResourceProvider::ScopedSamplerGL y_plane_lock(
1355 resource_provider_, quad->y_plane_resource_id, GL_TEXTURE_2D, GL_LINEAR);
1356 GLC(Context(), Context()->activeTexture(GL_TEXTURE2));
1357 ResourceProvider::ScopedSamplerGL u_plane_lock(
1358 resource_provider_, quad->u_plane_resource_id, GL_TEXTURE_2D, GL_LINEAR);
1359 GLC(Context(), Context()->activeTexture(GL_TEXTURE3));
1360 ResourceProvider::ScopedSamplerGL v_plane_lock(
1361 resource_provider_, quad->v_plane_resource_id, GL_TEXTURE_2D, GL_LINEAR);
1363 SetUseProgram(program->program());
1365 GLC(Context(),
1366 Context()->uniform2f(program->vertex_shader().tex_scale_location(),
1367 quad->tex_scale.width(),
1368 quad->tex_scale.height()));
1369 GLC(Context(),
1370 Context()->uniform1i(program->fragment_shader().y_texture_location(), 1));
1371 GLC(Context(),
1372 Context()->uniform1i(program->fragment_shader().u_texture_location(), 2));
1373 GLC(Context(),
1374 Context()->uniform1i(program->fragment_shader().v_texture_location(), 3));
1376 // These values are magic numbers that are used in the transformation from YUV
1377 // to RGB color values. They are taken from the following webpage:
1378 // http://www.fourcc.org/fccyvrgb.php
1379 float yuv_to_rgb[9] = {
1380 1.164f, 1.164f, 1.164f,
1381 0.0f, -.391f, 2.018f,
1382 1.596f, -.813f, 0.0f,
1384 GLC(Context(),
1385 Context()->uniformMatrix3fv(
1386 program->fragment_shader().yuv_matrix_location(), 1, 0, yuv_to_rgb));
1388 // These values map to 16, 128, and 128 respectively, and are computed
1389 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
1390 // They are used in the YUV to RGBA conversion formula:
1391 // Y - 16 : Gives 16 values of head and footroom for overshooting
1392 // U - 128 : Turns unsigned U into signed U [-128,127]
1393 // V - 128 : Turns unsigned V into signed V [-128,127]
1394 float yuv_adjust[3] = { -0.0625f, -0.5f, -0.5f, };
1395 GLC(Context(),
1396 Context()->uniform3fv(
1397 program->fragment_shader().yuv_adj_location(), 1, yuv_adjust));
1399 SetShaderOpacity(quad->opacity(),
1400 program->fragment_shader().alpha_location());
1401 DrawQuadGeometry(frame,
1402 quad->quadTransform(),
1403 quad->rect,
1404 program->vertex_shader().matrix_location());
1406 // Reset active texture back to texture 0.
1407 GLC(Context(), Context()->activeTexture(GL_TEXTURE0));
1410 void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame,
1411 const StreamVideoDrawQuad* quad) {
1412 SetBlendEnabled(quad->ShouldDrawWithBlending());
1414 static float gl_matrix[16];
1416 DCHECK(capabilities_.using_egl_image);
1418 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1419 context_, highp_threshold_min_,
1420 quad->shared_quad_state->visible_content_rect.bottom_right());
1422 const VideoStreamTextureProgram* program =
1423 GetVideoStreamTextureProgram(tex_coord_precision);
1424 SetUseProgram(program->program());
1426 ToGLMatrix(&gl_matrix[0], quad->matrix);
1427 GLC(Context(),
1428 Context()->uniformMatrix4fv(
1429 program->vertex_shader().tex_matrix_location(), 1, false, gl_matrix));
1431 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
1432 quad->resource_id);
1433 GLC(Context(),
1434 Context()->bindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id()));
1436 GLC(Context(),
1437 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1439 SetShaderOpacity(quad->opacity(),
1440 program->fragment_shader().alpha_location());
1441 DrawQuadGeometry(frame,
1442 quad->quadTransform(),
1443 quad->rect,
1444 program->vertex_shader().matrix_location());
1447 void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
1448 const PictureDrawQuad* quad) {
1449 if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() ||
1450 on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) {
1451 on_demand_tile_raster_bitmap_.setConfig(
1452 SkBitmap::kARGB_8888_Config,
1453 quad->texture_size.width(),
1454 quad->texture_size.height());
1455 on_demand_tile_raster_bitmap_.allocPixels();
1457 if (on_demand_tile_raster_resource_id_)
1458 resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
1460 on_demand_tile_raster_resource_id_ = resource_provider_->CreateGLTexture(
1461 quad->texture_size,
1462 GL_RGBA,
1463 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
1464 ResourceProvider::TextureUsageAny);
1467 SkDevice device(on_demand_tile_raster_bitmap_);
1468 SkCanvas canvas(&device);
1470 quad->picture_pile->Raster(&canvas, quad->content_rect, quad->contents_scale,
1471 NULL);
1473 resource_provider_->SetPixels(
1474 on_demand_tile_raster_resource_id_,
1475 reinterpret_cast<uint8_t*>(on_demand_tile_raster_bitmap_.getPixels()),
1476 gfx::Rect(quad->texture_size),
1477 gfx::Rect(quad->texture_size),
1478 gfx::Vector2d());
1480 DrawContentQuad(frame, quad, on_demand_tile_raster_resource_id_);
1483 struct TextureProgramBinding {
1484 template <class Program>
1485 void Set(Program* program, WebKit::WebGraphicsContext3D* context) {
1486 DCHECK(program && (program->initialized() || context->isContextLost()));
1487 program_id = program->program();
1488 sampler_location = program->fragment_shader().sampler_location();
1489 matrix_location = program->vertex_shader().matrix_location();
1490 alpha_location = program->fragment_shader().alpha_location();
1492 int program_id;
1493 int sampler_location;
1494 int matrix_location;
1495 int alpha_location;
1498 struct TexTransformTextureProgramBinding : TextureProgramBinding {
1499 template <class Program>
1500 void Set(Program* program, WebKit::WebGraphicsContext3D* context) {
1501 TextureProgramBinding::Set(program, context);
1502 tex_transform_location = program->vertex_shader().tex_transform_location();
1503 vertex_opacity_location =
1504 program->vertex_shader().vertex_opacity_location();
1506 int tex_transform_location;
1507 int vertex_opacity_location;
1510 void GLRenderer::FlushTextureQuadCache() {
1511 // Check to see if we have anything to draw.
1512 if (draw_cache_.program_id == 0)
1513 return;
1515 // Set the correct blending mode.
1516 SetBlendEnabled(draw_cache_.needs_blending);
1518 // Bind the program to the GL state.
1519 SetUseProgram(draw_cache_.program_id);
1521 // Bind the correct texture sampler location.
1522 GLC(Context(), Context()->uniform1i(draw_cache_.sampler_location, 0));
1524 // Assume the current active textures is 0.
1525 ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_,
1526 draw_cache_.resource_id);
1527 GLC(Context(),
1528 Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id()));
1530 // set up premultiplied alpha.
1531 if (!draw_cache_.use_premultiplied_alpha) {
1532 // As it turns out, the premultiplied alpha blending function (ONE,
1533 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to
1534 // anything less than 1.0f if it is initialized to that value! Therefore,
1535 // premultiplied_alpha being false is the first situation we can generally
1536 // see an alpha channel less than 1.0f coming out of the compositor. This is
1537 // causing platform differences in some layout tests (see
1538 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use
1539 // a separate blend function for the alpha channel to avoid modifying it.
1540 // Don't use colorMask() for this as it has performance implications on some
1541 // platforms.
1542 GLC(Context(),
1543 Context()->blendFuncSeparate(
1544 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE));
1547 COMPILE_ASSERT(
1548 sizeof(Float4) == 4 * sizeof(float), // NOLINT(runtime/sizeof)
1549 struct_is_densely_packed);
1550 COMPILE_ASSERT(
1551 sizeof(Float16) == 16 * sizeof(float), // NOLINT(runtime/sizeof)
1552 struct_is_densely_packed);
1554 // Upload the tranforms for both points and uvs.
1555 GLC(context_,
1556 context_->uniformMatrix4fv(
1557 static_cast<int>(draw_cache_.matrix_location),
1558 static_cast<int>(draw_cache_.matrix_data.size()),
1559 false,
1560 reinterpret_cast<float*>(&draw_cache_.matrix_data.front())));
1561 GLC(context_,
1562 context_->uniform4fv(
1563 static_cast<int>(draw_cache_.uv_xform_location),
1564 static_cast<int>(draw_cache_.uv_xform_data.size()),
1565 reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front())));
1566 GLC(context_,
1567 context_->uniform1fv(
1568 static_cast<int>(draw_cache_.vertex_opacity_location),
1569 static_cast<int>(draw_cache_.vertex_opacity_data.size()),
1570 static_cast<float*>(&draw_cache_.vertex_opacity_data.front())));
1572 // Draw the quads!
1573 GLC(context_,
1574 context_->drawElements(GL_TRIANGLES,
1575 6 * draw_cache_.matrix_data.size(),
1576 GL_UNSIGNED_SHORT,
1577 0));
1579 // Clean up after ourselves (reset state set above).
1580 if (!draw_cache_.use_premultiplied_alpha)
1581 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
1583 // Clear the cache.
1584 draw_cache_.program_id = 0;
1585 draw_cache_.uv_xform_data.resize(0);
1586 draw_cache_.vertex_opacity_data.resize(0);
1587 draw_cache_.matrix_data.resize(0);
1590 void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
1591 const TextureDrawQuad* quad) {
1592 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1593 context_, highp_threshold_min_,
1594 quad->shared_quad_state->visible_content_rect.bottom_right());
1596 // Choose the correct texture program binding
1597 TexTransformTextureProgramBinding binding;
1598 if (quad->flipped)
1599 binding.Set(GetTextureProgramFlip(tex_coord_precision), Context());
1600 else
1601 binding.Set(GetTextureProgram(tex_coord_precision), Context());
1603 int resource_id = quad->resource_id;
1605 if (draw_cache_.program_id != binding.program_id ||
1606 draw_cache_.resource_id != resource_id ||
1607 draw_cache_.use_premultiplied_alpha != quad->premultiplied_alpha ||
1608 draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
1609 draw_cache_.matrix_data.size() >= 8) {
1610 FlushTextureQuadCache();
1611 draw_cache_.program_id = binding.program_id;
1612 draw_cache_.resource_id = resource_id;
1613 draw_cache_.use_premultiplied_alpha = quad->premultiplied_alpha;
1614 draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
1616 draw_cache_.uv_xform_location = binding.tex_transform_location;
1617 draw_cache_.vertex_opacity_location = binding.vertex_opacity_location;
1618 draw_cache_.matrix_location = binding.matrix_location;
1619 draw_cache_.sampler_location = binding.sampler_location;
1622 // Generate the uv-transform
1623 gfx::PointF uv0 = quad->uv_top_left;
1624 gfx::PointF uv1 = quad->uv_bottom_right;
1625 Float4 uv = { { uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y() } };
1626 draw_cache_.uv_xform_data.push_back(uv);
1628 // Generate the vertex opacity
1629 const float opacity = quad->opacity();
1630 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
1631 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity);
1632 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity);
1633 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity);
1635 // Generate the transform matrix
1636 gfx::Transform quad_rect_matrix;
1637 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
1638 quad_rect_matrix = frame->projection_matrix * quad_rect_matrix;
1640 Float16 m;
1641 quad_rect_matrix.matrix().asColMajorf(m.data);
1642 draw_cache_.matrix_data.push_back(m);
1645 void GLRenderer::DrawTextureQuad(const DrawingFrame* frame,
1646 const TextureDrawQuad* quad) {
1647 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1648 context_, highp_threshold_min_,
1649 quad->shared_quad_state->visible_content_rect.bottom_right());
1651 TexTransformTextureProgramBinding binding;
1652 if (quad->flipped)
1653 binding.Set(GetTextureProgramFlip(tex_coord_precision), Context());
1654 else
1655 binding.Set(GetTextureProgram(tex_coord_precision), Context());
1656 SetUseProgram(binding.program_id);
1657 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0));
1658 gfx::PointF uv0 = quad->uv_top_left;
1659 gfx::PointF uv1 = quad->uv_bottom_right;
1660 GLC(Context(),
1661 Context()->uniform4f(binding.tex_transform_location,
1662 uv0.x(),
1663 uv0.y(),
1664 uv1.x() - uv0.x(),
1665 uv1.y() - uv0.y()));
1667 GLC(Context(),
1668 Context()->uniform1fv(
1669 binding.vertex_opacity_location, 4, quad->vertex_opacity));
1671 ResourceProvider::ScopedSamplerGL quad_resource_lock(
1672 resource_provider_, quad->resource_id, GL_TEXTURE_2D, GL_LINEAR);
1674 if (!quad->premultiplied_alpha) {
1675 // As it turns out, the premultiplied alpha blending function (ONE,
1676 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to
1677 // anything less than 1.0f if it is initialized to that value! Therefore,
1678 // premultiplied_alpha being false is the first situation we can generally
1679 // see an alpha channel less than 1.0f coming out of the compositor. This is
1680 // causing platform differences in some layout tests (see
1681 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use
1682 // a separate blend function for the alpha channel to avoid modifying it.
1683 // Don't use colorMask() for this as it has performance implications on some
1684 // platforms.
1685 GLC(Context(),
1686 Context()->blendFuncSeparate(
1687 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE));
1690 DrawQuadGeometry(
1691 frame, quad->quadTransform(), quad->rect, binding.matrix_location);
1693 if (!quad->premultiplied_alpha)
1694 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
1697 void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame,
1698 const IOSurfaceDrawQuad* quad) {
1699 SetBlendEnabled(quad->ShouldDrawWithBlending());
1701 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1702 context_, highp_threshold_min_,
1703 quad->shared_quad_state->visible_content_rect.bottom_right());
1705 TexTransformTextureProgramBinding binding;
1706 binding.Set(GetTextureIOSurfaceProgram(tex_coord_precision), Context());
1708 SetUseProgram(binding.program_id);
1709 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0));
1710 if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) {
1711 GLC(Context(),
1712 Context()->uniform4f(binding.tex_transform_location,
1714 quad->io_surface_size.height(),
1715 quad->io_surface_size.width(),
1716 quad->io_surface_size.height() * -1.0f));
1717 } else {
1718 GLC(Context(),
1719 Context()->uniform4f(binding.tex_transform_location,
1722 quad->io_surface_size.width(),
1723 quad->io_surface_size.height()));
1726 const float vertex_opacity[] = { quad->opacity(), quad->opacity(),
1727 quad->opacity(), quad->opacity() };
1728 GLC(Context(),
1729 Context()->uniform1fv(
1730 binding.vertex_opacity_location, 4, vertex_opacity));
1732 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
1733 quad->io_surface_resource_id);
1734 GLC(Context(),
1735 Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB,
1736 lock.texture_id()));
1738 DrawQuadGeometry(
1739 frame, quad->quadTransform(), quad->rect, binding.matrix_location);
1741 GLC(Context(), Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, 0));
1744 void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
1745 current_framebuffer_lock_.reset();
1746 swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect));
1748 GLC(context_, context_->disable(GL_BLEND));
1749 blend_shadow_ = false;
1751 if (Settings().compositor_frame_message) {
1752 CompositorFrame compositor_frame;
1753 compositor_frame.metadata = client_->MakeCompositorFrameMetadata();
1754 output_surface_->SendFrameToParentCompositor(&compositor_frame);
1758 void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); }
1760 bool GLRenderer::FlippedFramebuffer() const { return true; }
1762 void GLRenderer::EnsureScissorTestEnabled() {
1763 if (is_scissor_enabled_)
1764 return;
1766 FlushTextureQuadCache();
1767 GLC(context_, context_->enable(GL_SCISSOR_TEST));
1768 is_scissor_enabled_ = true;
1771 void GLRenderer::EnsureScissorTestDisabled() {
1772 if (!is_scissor_enabled_)
1773 return;
1775 FlushTextureQuadCache();
1776 GLC(context_, context_->disable(GL_SCISSOR_TEST));
1777 is_scissor_enabled_ = false;
1780 void GLRenderer::CopyCurrentRenderPassToBitmap(DrawingFrame* frame,
1781 SkBitmap* bitmap) {
1782 gfx::Size render_pass_size = frame->current_render_pass->output_rect.size();
1783 bitmap->setConfig(SkBitmap::kARGB_8888_Config,
1784 render_pass_size.width(),
1785 render_pass_size.height());
1786 if (bitmap->allocPixels()) {
1787 bitmap->lockPixels();
1788 GetFramebufferPixels(bitmap->getPixels(), gfx::Rect(render_pass_size));
1789 bitmap->unlockPixels();
1793 void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) {
1794 transform.matrix().asColMajorf(gl_matrix);
1797 void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) {
1798 if (quad_location == -1)
1799 return;
1801 float point[8];
1802 point[0] = quad.p1().x();
1803 point[1] = quad.p1().y();
1804 point[2] = quad.p2().x();
1805 point[3] = quad.p2().y();
1806 point[4] = quad.p3().x();
1807 point[5] = quad.p3().y();
1808 point[6] = quad.p4().x();
1809 point[7] = quad.p4().y();
1810 GLC(context_, context_->uniform2fv(quad_location, 4, point));
1813 void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) {
1814 if (alpha_location != -1)
1815 GLC(context_, context_->uniform1f(alpha_location, opacity));
1818 void GLRenderer::SetBlendEnabled(bool enabled) {
1819 if (enabled == blend_shadow_)
1820 return;
1822 if (enabled)
1823 GLC(context_, context_->enable(GL_BLEND));
1824 else
1825 GLC(context_, context_->disable(GL_BLEND));
1826 blend_shadow_ = enabled;
1829 void GLRenderer::SetUseProgram(unsigned program) {
1830 if (program == program_shadow_)
1831 return;
1832 GLC(context_, context_->useProgram(program));
1833 program_shadow_ = program;
1836 void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame,
1837 const gfx::Transform& draw_transform,
1838 const gfx::RectF& quad_rect,
1839 int matrix_location) {
1840 gfx::Transform quad_rect_matrix;
1841 QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
1842 static float gl_matrix[16];
1843 ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix);
1844 GLC(context_,
1845 context_->uniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0]));
1847 GLC(context_, context_->drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
1850 void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
1851 int texture_id,
1852 gfx::Rect rect,
1853 const gfx::Transform& draw_matrix) {
1854 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
1855 context_, highp_threshold_min_, rect.bottom_right());
1856 const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision);
1858 GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, texture_id));
1860 SetUseProgram(program->program());
1861 GLC(Context(),
1862 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1863 GLC(Context(),
1864 Context()->uniform4f(program->vertex_shader().tex_transform_location(),
1865 0.0f,
1866 0.0f,
1867 1.0f,
1868 1.0f));
1869 SetShaderOpacity(1, program->fragment_shader().alpha_location());
1870 DrawQuadGeometry(
1871 frame, draw_matrix, rect, program->vertex_shader().matrix_location());
1874 void GLRenderer::Finish() {
1875 TRACE_EVENT0("cc", "GLRenderer::finish");
1876 context_->finish();
1879 void GLRenderer::SwapBuffers(const LatencyInfo& latency_info) {
1880 DCHECK(visible_);
1881 DCHECK(!is_backbuffer_discarded_);
1883 TRACE_EVENT0("cc", "GLRenderer::SwapBuffers");
1884 // We're done! Time to swapbuffers!
1886 if (capabilities_.using_partial_swap && client_->AllowPartialSwap()) {
1887 // If supported, we can save significant bandwidth by only swapping the
1888 // damaged/scissored region (clamped to the viewport)
1889 swap_buffer_rect_.Intersect(gfx::Rect(ViewportSize()));
1890 int flipped_y_pos_of_rect_bottom =
1891 ViewportHeight() - swap_buffer_rect_.y() - swap_buffer_rect_.height();
1892 output_surface_->PostSubBuffer(gfx::Rect(swap_buffer_rect_.x(),
1893 flipped_y_pos_of_rect_bottom,
1894 swap_buffer_rect_.width(),
1895 swap_buffer_rect_.height()),
1896 latency_info);
1897 } else {
1898 output_surface_->SwapBuffers(latency_info);
1901 swap_buffer_rect_ = gfx::Rect();
1903 // We don't have real fences, so we mark read fences as passed
1904 // assuming a double-buffered GPU pipeline. A texture can be
1905 // written to after one full frame has past since it was last read.
1906 if (last_swap_fence_)
1907 static_cast<SimpleSwapFence*>(last_swap_fence_.get())->SetHasPassed();
1908 last_swap_fence_ = resource_provider_->GetReadLockFence();
1909 resource_provider_->SetReadLockFence(new SimpleSwapFence());
1912 void GLRenderer::onMemoryAllocationChanged(
1913 WebGraphicsMemoryAllocation allocation) {
1914 // Just ignore the memory manager when it says to set the limit to zero
1915 // bytes. This will happen when the memory manager thinks that the renderer
1916 // is not visible (which the renderer knows better).
1917 if (allocation.bytesLimitWhenVisible) {
1918 ManagedMemoryPolicy policy(
1919 allocation.bytesLimitWhenVisible,
1920 PriorityCutoff(allocation.priorityCutoffWhenVisible),
1921 allocation.bytesLimitWhenNotVisible,
1922 PriorityCutoff(allocation.priorityCutoffWhenNotVisible));
1924 if (allocation.enforceButDoNotKeepAsPolicy)
1925 client_->EnforceManagedMemoryPolicy(policy);
1926 else
1927 client_->SetManagedMemoryPolicy(policy);
1930 bool old_discard_backbuffer_when_not_visible =
1931 discard_backbuffer_when_not_visible_;
1932 discard_backbuffer_when_not_visible_ = !allocation.suggestHaveBackbuffer;
1933 EnforceMemoryPolicy();
1934 if (allocation.enforceButDoNotKeepAsPolicy)
1935 discard_backbuffer_when_not_visible_ =
1936 old_discard_backbuffer_when_not_visible;
1939 ManagedMemoryPolicy::PriorityCutoff GLRenderer::PriorityCutoff(
1940 WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priority_cutoff) {
1941 // This is simple a 1:1 map, the names differ only because the WebKit names
1942 // should be to match the cc names.
1943 switch (priority_cutoff) {
1944 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing:
1945 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
1946 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly:
1947 return ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
1948 case WebKit::WebGraphicsMemoryAllocation::
1949 PriorityCutoffAllowVisibleAndNearby:
1950 return ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
1951 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything:
1952 return ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING;
1954 NOTREACHED();
1955 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
1958 void GLRenderer::EnforceMemoryPolicy() {
1959 if (!visible_) {
1960 TRACE_EVENT0("cc", "GLRenderer::EnforceMemoryPolicy dropping resources");
1961 ReleaseRenderPassTextures();
1962 if (discard_backbuffer_when_not_visible_)
1963 DiscardBackbuffer();
1964 resource_provider_->ReleaseCachedData();
1965 GLC(context_, context_->flush());
1969 void GLRenderer::DiscardBackbuffer() {
1970 if (is_backbuffer_discarded_)
1971 return;
1973 output_surface_->DiscardBackbuffer();
1975 is_backbuffer_discarded_ = true;
1977 // Damage tracker needs a full reset every time framebuffer is discarded.
1978 client_->SetFullRootLayerDamage();
1981 void GLRenderer::EnsureBackbuffer() {
1982 if (!is_backbuffer_discarded_)
1983 return;
1985 output_surface_->EnsureBackbuffer();
1986 is_backbuffer_discarded_ = false;
1989 void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
1990 DCHECK(rect.right() <= ViewportWidth());
1991 DCHECK(rect.bottom() <= ViewportHeight());
1993 if (!pixels)
1994 return;
1996 MakeContextCurrent();
1998 bool do_workaround = NeedsIOSurfaceReadbackWorkaround();
2000 GLuint temporary_texture = 0;
2001 GLuint temporary_fbo = 0;
2003 if (do_workaround) {
2004 // On Mac OS X, calling glReadPixels() against an FBO whose color attachment
2005 // is an IOSurface-backed texture causes corruption of future glReadPixels()
2006 // calls, even those on different OpenGL contexts. It is believed that this
2007 // is the root cause of top crasher
2008 // http://crbug.com/99393. <rdar://problem/10949687>
2010 temporary_texture = context_->createTexture();
2011 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture));
2012 GLC(context_,
2013 context_->texParameteri(
2014 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2015 GLC(context_,
2016 context_->texParameteri(
2017 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2018 GLC(context_,
2019 context_->texParameteri(
2020 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2021 GLC(context_,
2022 context_->texParameteri(
2023 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2024 // Copy the contents of the current (IOSurface-backed) framebuffer into a
2025 // temporary texture.
2026 GLC(context_,
2027 context_->copyTexImage2D(GL_TEXTURE_2D,
2029 GL_RGBA,
2032 ViewportSize().width(),
2033 ViewportSize().height(),
2034 0));
2035 temporary_fbo = context_->createFramebuffer();
2036 // Attach this texture to an FBO, and perform the readback from that FBO.
2037 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
2038 GLC(context_,
2039 context_->framebufferTexture2D(GL_FRAMEBUFFER,
2040 GL_COLOR_ATTACHMENT0,
2041 GL_TEXTURE_2D,
2042 temporary_texture,
2043 0));
2045 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
2046 GL_FRAMEBUFFER_COMPLETE);
2049 scoped_ptr<uint8_t[]> src_pixels(
2050 new uint8_t[rect.width() * rect.height() * 4]);
2051 GLC(context_,
2052 context_->readPixels(rect.x(),
2053 ViewportSize().height() - rect.bottom(),
2054 rect.width(),
2055 rect.height(),
2056 GL_RGBA,
2057 GL_UNSIGNED_BYTE,
2058 src_pixels.get()));
2060 uint8_t* dest_pixels = static_cast<uint8_t*>(pixels);
2061 size_t row_bytes = rect.width() * 4;
2062 int num_rows = rect.height();
2063 size_t total_bytes = num_rows * row_bytes;
2064 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
2065 // Flip Y axis.
2066 size_t src_y = total_bytes - dest_y - row_bytes;
2067 // Swizzle BGRA -> RGBA.
2068 for (size_t x = 0; x < row_bytes; x += 4) {
2069 dest_pixels[dest_y + (x + 0)] = src_pixels.get()[src_y + (x + 2)];
2070 dest_pixels[dest_y + (x + 1)] = src_pixels.get()[src_y + (x + 1)];
2071 dest_pixels[dest_y + (x + 2)] = src_pixels.get()[src_y + (x + 0)];
2072 dest_pixels[dest_y + (x + 3)] = src_pixels.get()[src_y + (x + 3)];
2076 if (do_workaround) {
2077 // Clean up.
2078 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0));
2079 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2080 GLC(context_, context_->deleteFramebuffer(temporary_fbo));
2081 GLC(context_, context_->deleteTexture(temporary_texture));
2084 EnforceMemoryPolicy();
2087 bool GLRenderer::GetFramebufferTexture(ScopedResource* texture,
2088 gfx::Rect device_rect) {
2089 DCHECK(!texture->id() || (texture->size() == device_rect.size() &&
2090 texture->format() == GL_RGB));
2092 if (!texture->id() && !texture->Allocate(device_rect.size(),
2093 GL_RGB,
2094 ResourceProvider::TextureUsageAny))
2095 return false;
2097 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, texture->id());
2098 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, lock.texture_id()));
2099 GLC(context_,
2100 context_->copyTexImage2D(GL_TEXTURE_2D,
2102 texture->format(),
2103 device_rect.x(),
2104 device_rect.y(),
2105 device_rect.width(),
2106 device_rect.height(),
2107 0));
2108 return true;
2111 bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
2112 const ScopedResource* texture,
2113 gfx::Rect viewport_rect) {
2114 DCHECK(texture->id());
2115 frame->current_render_pass = NULL;
2116 frame->current_texture = texture;
2118 return BindFramebufferToTexture(frame, texture, viewport_rect);
2121 void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
2122 current_framebuffer_lock_.reset();
2123 output_surface_->BindFramebuffer();
2126 bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
2127 const ScopedResource* texture,
2128 gfx::Rect framebuffer_rect) {
2129 DCHECK(texture->id());
2131 GLC(context_,
2132 context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_));
2133 current_framebuffer_lock_ =
2134 make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL(
2135 resource_provider_, texture->id()));
2136 unsigned texture_id = current_framebuffer_lock_->texture_id();
2137 GLC(context_,
2138 context_->framebufferTexture2D(
2139 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0));
2141 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
2142 GL_FRAMEBUFFER_COMPLETE || IsContextLost());
2144 InitializeMatrices(frame, framebuffer_rect, false);
2145 SetDrawViewportSize(framebuffer_rect.size());
2147 return true;
2150 void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
2151 EnsureScissorTestEnabled();
2153 // Don't unnecessarily ask the context to change the scissor, because it
2154 // may cause undesired GPU pipeline flushes.
2155 if (scissor_rect == scissor_rect_)
2156 return;
2158 scissor_rect_ = scissor_rect;
2159 FlushTextureQuadCache();
2160 GLC(context_,
2161 context_->scissor(scissor_rect.x(),
2162 scissor_rect.y(),
2163 scissor_rect.width(),
2164 scissor_rect.height()));
2167 void GLRenderer::SetDrawViewportSize(gfx::Size viewport_size) {
2168 GLC(context_,
2169 context_->viewport(0, 0, viewport_size.width(), viewport_size.height()));
2172 bool GLRenderer::MakeContextCurrent() { return context_->makeContextCurrent(); }
2174 bool GLRenderer::InitializeSharedObjects() {
2175 TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects");
2176 MakeContextCurrent();
2178 // Create an FBO for doing offscreen rendering.
2179 GLC(context_, offscreen_framebuffer_id_ = context_->createFramebuffer());
2181 // We will always need these programs to render, so create the programs
2182 // eagerly so that the shader compilation can start while we do other work.
2183 // Other programs are created lazily on first access.
2184 shared_geometry_ = make_scoped_ptr(
2185 new GeometryBinding(context_, QuadVertexRect()));
2186 render_pass_program_ = make_scoped_ptr(
2187 new RenderPassProgram(context_, TexCoordPrecisionMedium));
2188 render_pass_program_highp_ = make_scoped_ptr(
2189 new RenderPassProgram(context_, TexCoordPrecisionHigh));
2190 tile_program_ = make_scoped_ptr(
2191 new TileProgram(context_, TexCoordPrecisionMedium));
2192 tile_program_opaque_ = make_scoped_ptr(
2193 new TileProgramOpaque(context_, TexCoordPrecisionMedium));
2194 tile_program_highp_ = make_scoped_ptr(
2195 new TileProgram(context_, TexCoordPrecisionHigh));
2196 tile_program_opaque_highp_ = make_scoped_ptr(
2197 new TileProgramOpaque(context_, TexCoordPrecisionHigh));
2199 GLC(context_, context_->flush());
2201 return true;
2204 const GLRenderer::TileCheckerboardProgram*
2205 GLRenderer::GetTileCheckerboardProgram() {
2206 if (!tile_checkerboard_program_)
2207 tile_checkerboard_program_ = make_scoped_ptr(
2208 new TileCheckerboardProgram(context_, TexCoordPrecisionNA));
2209 if (!tile_checkerboard_program_->initialized()) {
2210 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
2211 tile_checkerboard_program_->Initialize(context_, is_using_bind_uniform_);
2213 return tile_checkerboard_program_.get();
2216 const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() {
2217 if (!debug_border_program_)
2218 debug_border_program_ = make_scoped_ptr(
2219 new DebugBorderProgram(context_, TexCoordPrecisionNA));
2220 if (!debug_border_program_->initialized()) {
2221 TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize");
2222 debug_border_program_->Initialize(context_, is_using_bind_uniform_);
2224 return debug_border_program_.get();
2227 const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() {
2228 if (!solid_color_program_)
2229 solid_color_program_ = make_scoped_ptr(
2230 new SolidColorProgram(context_, TexCoordPrecisionNA));
2231 if (!solid_color_program_->initialized()) {
2232 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
2233 solid_color_program_->Initialize(context_, is_using_bind_uniform_);
2235 return solid_color_program_.get();
2238 const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() {
2239 if (!solid_color_program_aa_) {
2240 solid_color_program_aa_ =
2241 make_scoped_ptr(new SolidColorProgramAA(context_, TexCoordPrecisionNA));
2243 if (!solid_color_program_aa_->initialized()) {
2244 TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize");
2245 solid_color_program_aa_->Initialize(context_, is_using_bind_uniform_);
2247 return solid_color_program_aa_.get();
2250 const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram(
2251 TexCoordPrecision precision) {
2252 scoped_ptr<RenderPassProgram>& program =
2253 (precision == TexCoordPrecisionHigh) ? render_pass_program_highp_
2254 : render_pass_program_;
2255 DCHECK(program);
2256 if (!program->initialized()) {
2257 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
2258 program->Initialize(context_, is_using_bind_uniform_);
2260 return program.get();
2263 const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
2264 TexCoordPrecision precision) {
2265 scoped_ptr<RenderPassProgramAA>& program =
2266 (precision == TexCoordPrecisionHigh) ? render_pass_program_aa_highp_
2267 : render_pass_program_aa_;
2268 if (!program)
2269 program =
2270 make_scoped_ptr(new RenderPassProgramAA(context_, precision));
2271 if (!program->initialized()) {
2272 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
2273 program->Initialize(context_, is_using_bind_uniform_);
2275 return program.get();
2278 const GLRenderer::RenderPassMaskProgram*
2279 GLRenderer::GetRenderPassMaskProgram(TexCoordPrecision precision) {
2280 scoped_ptr<RenderPassMaskProgram>& program =
2281 (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_highp_
2282 : render_pass_mask_program_;
2283 if (!program)
2284 program = make_scoped_ptr(new RenderPassMaskProgram(context_, precision));
2285 if (!program->initialized()) {
2286 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
2287 program->Initialize(context_, is_using_bind_uniform_);
2289 return program.get();
2292 const GLRenderer::RenderPassMaskProgramAA*
2293 GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision) {
2294 scoped_ptr<RenderPassMaskProgramAA>& program =
2295 (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_aa_highp_
2296 : render_pass_mask_program_aa_;
2297 if (!program)
2298 program =
2299 make_scoped_ptr(new RenderPassMaskProgramAA(context_, precision));
2300 if (!program->initialized()) {
2301 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
2302 program->Initialize(context_, is_using_bind_uniform_);
2304 return program.get();
2307 const GLRenderer::RenderPassColorMatrixProgram*
2308 GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision) {
2309 scoped_ptr<RenderPassColorMatrixProgram>& program =
2310 (precision == TexCoordPrecisionHigh) ?
2311 render_pass_color_matrix_program_highp_ :
2312 render_pass_color_matrix_program_;
2313 if (!program)
2314 program = make_scoped_ptr(
2315 new RenderPassColorMatrixProgram(context_, precision));
2316 if (!program->initialized()) {
2317 TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize");
2318 program->Initialize(context_, is_using_bind_uniform_);
2320 return program.get();
2323 const GLRenderer::RenderPassColorMatrixProgramAA*
2324 GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
2325 scoped_ptr<RenderPassColorMatrixProgramAA>& program =
2326 (precision == TexCoordPrecisionHigh) ?
2327 render_pass_color_matrix_program_aa_highp_ :
2328 render_pass_color_matrix_program_aa_;
2329 if (!program)
2330 program = make_scoped_ptr(
2331 new RenderPassColorMatrixProgramAA(context_, precision));
2332 if (!program->initialized()) {
2333 TRACE_EVENT0("cc",
2334 "GLRenderer::renderPassColorMatrixProgramAA::initialize");
2335 program->Initialize(context_, is_using_bind_uniform_);
2337 return program.get();
2340 const GLRenderer::RenderPassMaskColorMatrixProgram*
2341 GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
2342 scoped_ptr<RenderPassMaskColorMatrixProgram>& program =
2343 (precision == TexCoordPrecisionHigh) ?
2344 render_pass_mask_color_matrix_program_highp_ :
2345 render_pass_mask_color_matrix_program_;
2346 if (!program)
2347 program = make_scoped_ptr(
2348 new RenderPassMaskColorMatrixProgram(context_, precision));
2349 if (!program->initialized()) {
2350 TRACE_EVENT0("cc",
2351 "GLRenderer::renderPassMaskColorMatrixProgram::initialize");
2352 program->Initialize(context_, is_using_bind_uniform_);
2354 return program.get();
2357 const GLRenderer::RenderPassMaskColorMatrixProgramAA*
2358 GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
2359 scoped_ptr<RenderPassMaskColorMatrixProgramAA>& program =
2360 (precision == TexCoordPrecisionHigh) ?
2361 render_pass_mask_color_matrix_program_aa_highp_ :
2362 render_pass_mask_color_matrix_program_aa_;
2363 if (!program)
2364 program = make_scoped_ptr(
2365 new RenderPassMaskColorMatrixProgramAA(context_, precision));
2366 if (!program->initialized()) {
2367 TRACE_EVENT0("cc",
2368 "GLRenderer::renderPassMaskColorMatrixProgramAA::initialize");
2369 program->Initialize(context_, is_using_bind_uniform_);
2371 return program.get();
2374 const GLRenderer::TileProgram* GLRenderer::GetTileProgram(
2375 TexCoordPrecision precision) {
2376 scoped_ptr<TileProgram>& program =
2377 (precision == TexCoordPrecisionHigh) ? tile_program_highp_
2378 : tile_program_;
2379 DCHECK(program);
2380 if (!program->initialized()) {
2381 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
2382 program->Initialize(context_, is_using_bind_uniform_);
2384 return program.get();
2387 const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque(
2388 TexCoordPrecision precision) {
2389 scoped_ptr<TileProgramOpaque>& program =
2390 (precision == TexCoordPrecisionHigh) ? tile_program_opaque_highp_
2391 : tile_program_opaque_;
2392 DCHECK(program);
2393 if (!program->initialized()) {
2394 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
2395 program->Initialize(context_, is_using_bind_uniform_);
2397 return program.get();
2400 const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA(
2401 TexCoordPrecision precision) {
2402 scoped_ptr<TileProgramAA>& program =
2403 (precision == TexCoordPrecisionHigh) ? tile_program_aa_highp_
2404 : tile_program_aa_;
2405 if (!program)
2406 program = make_scoped_ptr(new TileProgramAA(context_, precision));
2407 if (!program->initialized()) {
2408 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
2409 program->Initialize(context_, is_using_bind_uniform_);
2411 return program.get();
2414 const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle(
2415 TexCoordPrecision precision) {
2416 scoped_ptr<TileProgramSwizzle>& program =
2417 (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_highp_
2418 : tile_program_swizzle_;
2419 if (!program)
2420 program = make_scoped_ptr(new TileProgramSwizzle(context_, precision));
2421 if (!program->initialized()) {
2422 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
2423 program->Initialize(context_, is_using_bind_uniform_);
2425 return program.get();
2428 const GLRenderer::TileProgramSwizzleOpaque*
2429 GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision) {
2430 scoped_ptr<TileProgramSwizzleOpaque>& program =
2431 (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_opaque_highp_
2432 : tile_program_swizzle_opaque_;
2433 if (!program)
2434 program = make_scoped_ptr(
2435 new TileProgramSwizzleOpaque(context_, precision));
2436 if (!program->initialized()) {
2437 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize");
2438 program->Initialize(context_, is_using_bind_uniform_);
2440 return program.get();
2443 const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA(
2444 TexCoordPrecision precision) {
2445 scoped_ptr<TileProgramSwizzleAA>& program =
2446 (precision == TexCoordPrecisionHigh) ? tile_program_swizzle_aa_highp_
2447 : tile_program_swizzle_aa_;
2448 if (!program)
2449 program = make_scoped_ptr(new TileProgramSwizzleAA(context_, precision));
2450 if (!program->initialized()) {
2451 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
2452 program->Initialize(context_, is_using_bind_uniform_);
2454 return program.get();
2457 const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram(
2458 TexCoordPrecision precision) {
2459 scoped_ptr<TextureProgram>& program =
2460 (precision == TexCoordPrecisionHigh) ? texture_program_highp_
2461 : texture_program_;
2462 if (!program)
2463 program = make_scoped_ptr(new TextureProgram(context_, precision));
2464 if (!program->initialized()) {
2465 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
2466 program->Initialize(context_, is_using_bind_uniform_);
2468 return program.get();
2471 const GLRenderer::TextureProgramFlip* GLRenderer::GetTextureProgramFlip(
2472 TexCoordPrecision precision) {
2473 scoped_ptr<TextureProgramFlip>& program =
2474 (precision == TexCoordPrecisionHigh) ? texture_program_flip_highp_
2475 : texture_program_flip_;
2476 if (!program)
2477 program = make_scoped_ptr(new TextureProgramFlip(context_, precision));
2478 if (!program->initialized()) {
2479 TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize");
2480 program->Initialize(context_, is_using_bind_uniform_);
2482 return program.get();
2485 const GLRenderer::TextureIOSurfaceProgram*
2486 GLRenderer::GetTextureIOSurfaceProgram(TexCoordPrecision precision) {
2487 scoped_ptr<TextureIOSurfaceProgram>& program =
2488 (precision == TexCoordPrecisionHigh) ? texture_io_surface_program_highp_
2489 : texture_io_surface_program_;
2490 if (!program)
2491 program =
2492 make_scoped_ptr(new TextureIOSurfaceProgram(context_, precision));
2493 if (!program->initialized()) {
2494 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
2495 program->Initialize(context_, is_using_bind_uniform_);
2497 return program.get();
2500 const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram(
2501 TexCoordPrecision precision) {
2502 scoped_ptr<VideoYUVProgram>& program =
2503 (precision == TexCoordPrecisionHigh) ? video_yuv_program_highp_
2504 : video_yuv_program_;
2505 if (!program)
2506 program = make_scoped_ptr(new VideoYUVProgram(context_, precision));
2507 if (!program->initialized()) {
2508 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
2509 program->Initialize(context_, is_using_bind_uniform_);
2511 return program.get();
2514 const GLRenderer::VideoStreamTextureProgram*
2515 GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) {
2516 if (!Capabilities().using_egl_image)
2517 return NULL;
2518 scoped_ptr<VideoStreamTextureProgram>& program =
2519 (precision == TexCoordPrecisionHigh) ? video_stream_texture_program_highp_
2520 : video_stream_texture_program_;
2521 if (!program)
2522 program =
2523 make_scoped_ptr(new VideoStreamTextureProgram(context_, precision));
2524 if (!program->initialized()) {
2525 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
2526 program->Initialize(context_, is_using_bind_uniform_);
2528 return program.get();
2531 void GLRenderer::CleanupSharedObjects() {
2532 MakeContextCurrent();
2534 shared_geometry_.reset();
2536 if (tile_program_)
2537 tile_program_->Cleanup(context_);
2538 if (tile_program_opaque_)
2539 tile_program_opaque_->Cleanup(context_);
2540 if (tile_program_swizzle_)
2541 tile_program_swizzle_->Cleanup(context_);
2542 if (tile_program_swizzle_opaque_)
2543 tile_program_swizzle_opaque_->Cleanup(context_);
2544 if (tile_program_aa_)
2545 tile_program_aa_->Cleanup(context_);
2546 if (tile_program_swizzle_aa_)
2547 tile_program_swizzle_aa_->Cleanup(context_);
2548 if (tile_checkerboard_program_)
2549 tile_checkerboard_program_->Cleanup(context_);
2551 if (tile_program_highp_)
2552 tile_program_highp_->Cleanup(context_);
2553 if (tile_program_opaque_highp_)
2554 tile_program_opaque_highp_->Cleanup(context_);
2555 if (tile_program_swizzle_highp_)
2556 tile_program_swizzle_highp_->Cleanup(context_);
2557 if (tile_program_swizzle_opaque_highp_)
2558 tile_program_swizzle_opaque_highp_->Cleanup(context_);
2559 if (tile_program_aa_highp_)
2560 tile_program_aa_highp_->Cleanup(context_);
2561 if (tile_program_swizzle_aa_highp_)
2562 tile_program_swizzle_aa_highp_->Cleanup(context_);
2564 if (render_pass_mask_program_)
2565 render_pass_mask_program_->Cleanup(context_);
2566 if (render_pass_program_)
2567 render_pass_program_->Cleanup(context_);
2568 if (render_pass_mask_program_aa_)
2569 render_pass_mask_program_aa_->Cleanup(context_);
2570 if (render_pass_program_aa_)
2571 render_pass_program_aa_->Cleanup(context_);
2572 if (render_pass_color_matrix_program_)
2573 render_pass_color_matrix_program_->Cleanup(context_);
2574 if (render_pass_mask_color_matrix_program_aa_)
2575 render_pass_mask_color_matrix_program_aa_->Cleanup(context_);
2576 if (render_pass_color_matrix_program_aa_)
2577 render_pass_color_matrix_program_aa_->Cleanup(context_);
2578 if (render_pass_mask_color_matrix_program_)
2579 render_pass_mask_color_matrix_program_->Cleanup(context_);
2581 if (render_pass_mask_program_highp_)
2582 render_pass_mask_program_highp_->Cleanup(context_);
2583 if (render_pass_program_highp_)
2584 render_pass_program_highp_->Cleanup(context_);
2585 if (render_pass_mask_program_aa_highp_)
2586 render_pass_mask_program_aa_highp_->Cleanup(context_);
2587 if (render_pass_program_aa_highp_)
2588 render_pass_program_aa_highp_->Cleanup(context_);
2589 if (render_pass_color_matrix_program_highp_)
2590 render_pass_color_matrix_program_highp_->Cleanup(context_);
2591 if (render_pass_mask_color_matrix_program_aa_highp_)
2592 render_pass_mask_color_matrix_program_aa_highp_->Cleanup(context_);
2593 if (render_pass_color_matrix_program_aa_highp_)
2594 render_pass_color_matrix_program_aa_highp_->Cleanup(context_);
2595 if (render_pass_mask_color_matrix_program_highp_)
2596 render_pass_mask_color_matrix_program_highp_->Cleanup(context_);
2598 if (texture_program_)
2599 texture_program_->Cleanup(context_);
2600 if (texture_program_flip_)
2601 texture_program_flip_->Cleanup(context_);
2602 if (texture_io_surface_program_)
2603 texture_io_surface_program_->Cleanup(context_);
2605 if (texture_program_highp_)
2606 texture_program_highp_->Cleanup(context_);
2607 if (texture_program_flip_highp_)
2608 texture_program_flip_highp_->Cleanup(context_);
2609 if (texture_io_surface_program_highp_)
2610 texture_io_surface_program_highp_->Cleanup(context_);
2612 if (video_yuv_program_)
2613 video_yuv_program_->Cleanup(context_);
2614 if (video_stream_texture_program_)
2615 video_stream_texture_program_->Cleanup(context_);
2617 if (video_yuv_program_highp_)
2618 video_yuv_program_highp_->Cleanup(context_);
2619 if (video_stream_texture_program_highp_)
2620 video_stream_texture_program_highp_->Cleanup(context_);
2622 if (debug_border_program_)
2623 debug_border_program_->Cleanup(context_);
2624 if (solid_color_program_)
2625 solid_color_program_->Cleanup(context_);
2626 if (solid_color_program_aa_)
2627 solid_color_program_aa_->Cleanup(context_);
2629 if (offscreen_framebuffer_id_)
2630 GLC(context_, context_->deleteFramebuffer(offscreen_framebuffer_id_));
2632 if (on_demand_tile_raster_resource_id_)
2633 resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
2635 ReleaseRenderPassTextures();
2638 bool GLRenderer::IsContextLost() {
2639 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR);
2642 } // namespace cc