Fix build break
[chromium-blink-merge.git] / cc / output / gl_renderer.cc
blob5a70f384d3f2031013416db44c8bb6a3c838c94d
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 } // anonymous namespace
86 scoped_ptr<GLRenderer> GLRenderer::Create(RendererClient* client,
87 OutputSurface* output_surface,
88 ResourceProvider* resource_provider,
89 int highp_threshold_min) {
90 scoped_ptr<GLRenderer> renderer(new GLRenderer(
91 client, output_surface, resource_provider, highp_threshold_min));
92 if (!renderer->Initialize())
93 return scoped_ptr<GLRenderer>();
95 return renderer.Pass();
98 GLRenderer::GLRenderer(RendererClient* client,
99 OutputSurface* output_surface,
100 ResourceProvider* resource_provider,
101 int highp_threshold_min)
102 : DirectRenderer(client, resource_provider),
103 offscreen_framebuffer_id_(0),
104 shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)),
105 output_surface_(output_surface),
106 context_(output_surface->context3d()),
107 is_viewport_changed_(false),
108 is_backbuffer_discarded_(false),
109 discard_backbuffer_when_not_visible_(false),
110 is_using_bind_uniform_(false),
111 visible_(true),
112 is_scissor_enabled_(false),
113 highp_threshold_min_(highp_threshold_min),
114 on_demand_tile_raster_resource_id_(0) {
115 DCHECK(context_);
118 bool GLRenderer::Initialize() {
119 if (!context_->makeContextCurrent())
120 return false;
122 context_->setContextLostCallback(this);
123 context_->pushGroupMarkerEXT("CompositorContext");
125 std::string extensions_string =
126 UTF16ToASCII(context_->getString(GL_EXTENSIONS));
127 std::vector<std::string> extensions_list;
128 base::SplitString(extensions_string, ' ', &extensions_list);
129 std::set<std::string> extensions(extensions_list.begin(),
130 extensions_list.end());
132 if (Settings().accelerate_painting &&
133 extensions.count("GL_EXT_texture_format_BGRA8888") &&
134 extensions.count("GL_EXT_read_format_bgra"))
135 capabilities_.using_accelerated_painting = true;
136 else
137 capabilities_.using_accelerated_painting = false;
139 capabilities_.using_partial_swap =
140 Settings().partial_swap_enabled &&
141 extensions.count("GL_CHROMIUM_post_sub_buffer");
143 // Use the SwapBuffers callback only with the threaded proxy.
144 if (client_->HasImplThread())
145 capabilities_.using_swap_complete_callback =
146 extensions.count("GL_CHROMIUM_swapbuffers_complete_callback") > 0;
147 if (capabilities_.using_swap_complete_callback)
148 context_->setSwapBuffersCompleteCallbackCHROMIUM(this);
150 capabilities_.using_set_visibility =
151 extensions.count("GL_CHROMIUM_set_visibility") > 0;
153 if (extensions.count("GL_CHROMIUM_iosurface") > 0)
154 DCHECK(extensions.count("GL_ARB_texture_rectangle") > 0);
156 capabilities_.using_gpu_memory_manager =
157 extensions.count("GL_CHROMIUM_gpu_memory_manager") > 0 &&
158 Settings().use_memory_management;
159 if (capabilities_.using_gpu_memory_manager)
160 context_->setMemoryAllocationChangedCallbackCHROMIUM(this);
162 capabilities_.using_egl_image =
163 extensions.count("GL_OES_EGL_image_external") > 0;
165 capabilities_.max_texture_size = resource_provider_->max_texture_size();
166 capabilities_.best_texture_format = resource_provider_->best_texture_format();
168 // The updater can access textures while the GLRenderer is using them.
169 capabilities_.allow_partial_texture_updates = true;
171 // Check for texture fast paths. Currently we always use MO8 textures,
172 // so we only need to avoid POT textures if we have an NPOT fast-path.
173 capabilities_.avoid_pow2_textures =
174 extensions.count("GL_CHROMIUM_fast_NPOT_MO8_textures") > 0;
176 capabilities_.using_offscreen_context3d = true;
178 is_using_bind_uniform_ =
179 extensions.count("GL_CHROMIUM_bind_uniform_location") > 0;
181 // Make sure scissoring starts as disabled.
182 GLC(context_, context_->disable(GL_SCISSOR_TEST));
183 DCHECK(!is_scissor_enabled_);
185 if (!InitializeSharedObjects())
186 return false;
188 // Make sure the viewport and context gets initialized, even if it is to zero.
189 ViewportChanged();
190 return true;
193 GLRenderer::~GLRenderer() {
194 context_->setSwapBuffersCompleteCallbackCHROMIUM(NULL);
195 context_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
196 context_->setContextLostCallback(NULL);
197 CleanupSharedObjects();
200 const RendererCapabilities& GLRenderer::Capabilities() const {
201 return capabilities_;
204 WebGraphicsContext3D* GLRenderer::Context() { return context_; }
206 void GLRenderer::DebugGLCall(WebGraphicsContext3D* context,
207 const char* command,
208 const char* file,
209 int line) {
210 unsigned error = context->getError();
211 if (error != GL_NO_ERROR)
212 LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line
213 << "\n\tcommand: " << command << ", error "
214 << static_cast<int>(error) << "\n";
217 void GLRenderer::SetVisible(bool visible) {
218 if (visible_ == visible)
219 return;
220 visible_ = visible;
222 EnforceMemoryPolicy();
224 // TODO(jamesr): Replace setVisibilityCHROMIUM() with an extension to
225 // explicitly manage front/backbuffers
226 // crbug.com/116049
227 if (capabilities_.using_set_visibility)
228 context_->setVisibilityCHROMIUM(visible);
231 void GLRenderer::SendManagedMemoryStats(size_t bytes_visible,
232 size_t bytes_visible_and_nearby,
233 size_t bytes_allocated) {
234 WebKit::WebGraphicsManagedMemoryStats stats;
235 stats.bytesVisible = bytes_visible;
236 stats.bytesVisibleAndNearby = bytes_visible_and_nearby;
237 stats.bytesAllocated = bytes_allocated;
238 stats.backbufferRequested = !is_backbuffer_discarded_;
239 context_->sendManagedMemoryStatsCHROMIUM(&stats);
242 void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
244 void GLRenderer::ViewportChanged() { is_viewport_changed_ = true; }
246 void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
247 // On DEBUG builds, opaque render passes are cleared to blue to easily see
248 // regions that were not drawn on the screen.
249 if (frame->current_render_pass->has_transparent_background)
250 GLC(context_, context_->clearColor(0, 0, 0, 0));
251 else
252 GLC(context_, context_->clearColor(0, 0, 1, 1));
254 #ifdef NDEBUG
255 if (frame->current_render_pass->has_transparent_background)
256 #endif
257 context_->clear(GL_COLOR_BUFFER_BIT);
260 void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) {
261 // FIXME: Remove this once backbuffer is automatically recreated on first use
262 EnsureBackbuffer();
264 if (ViewportSize().IsEmpty())
265 return;
267 TRACE_EVENT0("cc", "GLRenderer::DrawLayers");
268 if (is_viewport_changed_) {
269 // Only reshape when we know we are going to draw. Otherwise, the reshape
270 // can leave the window at the wrong size if we never draw and the proper
271 // viewport size is never set.
272 is_viewport_changed_ = false;
273 output_surface_->Reshape(gfx::Size(ViewportWidth(), ViewportHeight()));
276 MakeContextCurrent();
277 // Bind the common vertex attributes used for drawing all the layers.
278 shared_geometry_->PrepareForDraw();
280 GLC(context_, context_->disable(GL_DEPTH_TEST));
281 GLC(context_, context_->disable(GL_CULL_FACE));
282 GLC(context_, context_->colorMask(true, true, true, true));
283 GLC(context_, context_->enable(GL_BLEND));
284 blend_shadow_ = true;
285 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
286 GLC(Context(), Context()->activeTexture(GL_TEXTURE0));
287 program_shadow_ = 0;
290 void GLRenderer::DoNoOp() {
291 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0));
292 GLC(context_, context_->flush());
295 void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
296 DCHECK(quad->rect.Contains(quad->visible_rect));
297 if (quad->material != DrawQuad::TEXTURE_CONTENT) {
298 FlushTextureQuadCache();
301 switch (quad->material) {
302 case DrawQuad::INVALID:
303 NOTREACHED();
304 break;
305 case DrawQuad::CHECKERBOARD:
306 DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
307 break;
308 case DrawQuad::DEBUG_BORDER:
309 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
310 break;
311 case DrawQuad::IO_SURFACE_CONTENT:
312 DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad));
313 break;
314 case DrawQuad::PICTURE_CONTENT:
315 DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad));
316 break;
317 case DrawQuad::RENDER_PASS:
318 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
319 break;
320 case DrawQuad::SOLID_COLOR:
321 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
322 break;
323 case DrawQuad::STREAM_VIDEO_CONTENT:
324 DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad));
325 break;
326 case DrawQuad::TEXTURE_CONTENT:
327 EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
328 break;
329 case DrawQuad::TILED_CONTENT:
330 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
331 break;
332 case DrawQuad::YUV_VIDEO_CONTENT:
333 DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad));
334 break;
338 void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
339 const CheckerboardDrawQuad* quad) {
340 SetBlendEnabled(quad->ShouldDrawWithBlending());
342 const TileCheckerboardProgram* program = GetTileCheckerboardProgram();
343 DCHECK(program && (program->initialized() || IsContextLost()));
344 SetUseProgram(program->program());
346 SkColor color = quad->color;
347 GLC(Context(),
348 Context()->uniform4f(program->fragment_shader().color_location(),
349 SkColorGetR(color) * (1.0f / 255.0f),
350 SkColorGetG(color) * (1.0f / 255.0f),
351 SkColorGetB(color) * (1.0f / 255.0f),
352 1));
354 const int checkerboard_width = 16;
355 float frequency = 1.0f / checkerboard_width;
357 gfx::Rect tile_rect = quad->rect;
358 float tex_offset_x = tile_rect.x() % checkerboard_width;
359 float tex_offset_y = tile_rect.y() % checkerboard_width;
360 float tex_scale_x = tile_rect.width();
361 float tex_scale_y = tile_rect.height();
362 GLC(Context(),
363 Context()->uniform4f(program->fragment_shader().tex_transform_location(),
364 tex_offset_x,
365 tex_offset_y,
366 tex_scale_x,
367 tex_scale_y));
369 GLC(Context(),
370 Context()->uniform1f(program->fragment_shader().frequency_location(),
371 frequency));
373 SetShaderOpacity(quad->opacity(),
374 program->fragment_shader().alpha_location());
375 DrawQuadGeometry(frame,
376 quad->quadTransform(),
377 quad->rect,
378 program->vertex_shader().matrix_location());
381 void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
382 const DebugBorderDrawQuad* quad) {
383 SetBlendEnabled(quad->ShouldDrawWithBlending());
385 static float gl_matrix[16];
386 const DebugBorderProgram* program = GetDebugBorderProgram();
387 DCHECK(program && (program->initialized() || IsContextLost()));
388 SetUseProgram(program->program());
390 // Use the full quad_rect for debug quads to not move the edges based on
391 // partial swaps.
392 gfx::Rect layer_rect = quad->rect;
393 gfx::Transform render_matrix = quad->quadTransform();
394 render_matrix.Translate(0.5f * layer_rect.width() + layer_rect.x(),
395 0.5f * layer_rect.height() + layer_rect.y());
396 render_matrix.Scale(layer_rect.width(), layer_rect.height());
397 GLRenderer::ToGLMatrix(&gl_matrix[0],
398 frame->projection_matrix * render_matrix);
399 GLC(Context(),
400 Context()->uniformMatrix4fv(
401 program->vertex_shader().matrix_location(), 1, false, &gl_matrix[0]));
403 SkColor color = quad->color;
404 float alpha = SkColorGetA(color) * (1.0f / 255.0f);
406 GLC(Context(),
407 Context()->uniform4f(program->fragment_shader().color_location(),
408 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
409 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
410 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
411 alpha));
413 GLC(Context(), Context()->lineWidth(quad->width));
415 // The indices for the line are stored in the same array as the triangle
416 // indices.
417 GLC(Context(),
418 Context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0));
421 static inline SkBitmap ApplyFilters(GLRenderer* renderer,
422 const WebKit::WebFilterOperations& filters,
423 ScopedResource* source_texture_resource) {
424 if (filters.isEmpty())
425 return SkBitmap();
427 ContextProvider* offscreen_contexts =
428 renderer->resource_provider()->offscreen_context_provider();
429 if (!offscreen_contexts || !offscreen_contexts->GrContext())
430 return SkBitmap();
432 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
433 source_texture_resource->id());
435 // Flush the compositor context to ensure that textures there are available
436 // in the shared context. Do this after locking/creating the compositor
437 // texture.
438 renderer->resource_provider()->Flush();
440 // Make sure skia uses the correct GL context.
441 offscreen_contexts->Context3d()->makeContextCurrent();
443 SkBitmap source =
444 RenderSurfaceFilters::Apply(filters,
445 lock.texture_id(),
446 source_texture_resource->size(),
447 offscreen_contexts->GrContext());
449 // Flush skia context so that all the rendered stuff appears on the
450 // texture.
451 offscreen_contexts->GrContext()->flush();
453 // Flush the GL context so rendering results from this context are
454 // visible in the compositor's context.
455 offscreen_contexts->Context3d()->flush();
457 // Use the compositor's GL context again.
458 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent();
459 return source;
462 static SkBitmap ApplyImageFilter(GLRenderer* renderer,
463 SkImageFilter* filter,
464 ScopedResource* source_texture_resource) {
465 if (!filter)
466 return SkBitmap();
468 ContextProvider* offscreen_contexts =
469 renderer->resource_provider()->offscreen_context_provider();
470 if (!offscreen_contexts || !offscreen_contexts->GrContext())
471 return SkBitmap();
473 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
474 source_texture_resource->id());
476 // Flush the compositor context to ensure that textures there are available
477 // in the shared context. Do this after locking/creating the compositor
478 // texture.
479 renderer->resource_provider()->Flush();
481 // Make sure skia uses the correct GL context.
482 offscreen_contexts->Context3d()->makeContextCurrent();
484 // Wrap the source texture in a Ganesh platform texture.
485 GrBackendTextureDesc backend_texture_description;
486 backend_texture_description.fWidth = source_texture_resource->size().width();
487 backend_texture_description.fHeight =
488 source_texture_resource->size().height();
489 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
490 backend_texture_description.fTextureHandle = lock.texture_id();
491 backend_texture_description.fOrigin = kTopLeft_GrSurfaceOrigin;
492 skia::RefPtr<GrTexture> texture =
493 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
494 backend_texture_description));
496 // Place the platform texture inside an SkBitmap.
497 SkBitmap source;
498 source.setConfig(SkBitmap::kARGB_8888_Config,
499 source_texture_resource->size().width(),
500 source_texture_resource->size().height());
501 skia::RefPtr<SkGrPixelRef> pixel_ref =
502 skia::AdoptRef(new SkGrPixelRef(texture.get()));
503 source.setPixelRef(pixel_ref.get());
505 // Create a scratch texture for backing store.
506 GrTextureDesc desc;
507 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
508 desc.fSampleCnt = 0;
509 desc.fWidth = source.width();
510 desc.fHeight = source.height();
511 desc.fConfig = kSkia8888_GrPixelConfig;
512 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
513 GrAutoScratchTexture scratch_texture(
514 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
515 skia::RefPtr<GrTexture> backing_store =
516 skia::AdoptRef(scratch_texture.detach());
518 // Create a device and canvas using that backing store.
519 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
520 SkCanvas canvas(&device);
522 // Draw the source bitmap through the filter to the canvas.
523 SkPaint paint;
524 paint.setImageFilter(filter);
525 canvas.clear(SK_ColorTRANSPARENT);
526 canvas.drawSprite(source, 0, 0, &paint);
528 // Flush skia context so that all the rendered stuff appears on the
529 // texture.
530 offscreen_contexts->GrContext()->flush();
532 // Flush the GL context so rendering results from this context are
533 // visible in the compositor's context.
534 offscreen_contexts->Context3d()->flush();
536 // Use the compositor's GL context again.
537 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent();
539 return device.accessBitmap(false);
542 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters(
543 DrawingFrame* frame,
544 const RenderPassDrawQuad* quad,
545 const gfx::Transform& contents_device_transform,
546 const gfx::Transform& contents_device_transform_inverse) {
547 // This method draws a background filter, which applies a filter to any pixels
548 // behind the quad and seen through its background. The algorithm works as
549 // follows:
550 // 1. Compute a bounding box around the pixels that will be visible through
551 // the quad.
552 // 2. Read the pixels in the bounding box into a buffer R.
553 // 3. Apply the background filter to R, so that it is applied in the pixels'
554 // coordinate space.
555 // 4. Apply the quad's inverse transform to map the pixels in R into the
556 // quad's content space. This implicitly clips R by the content bounds of the
557 // quad since the destination texture has bounds matching the quad's content.
558 // 5. Draw the background texture for the contents using the same transform as
559 // used to draw the contents itself. This is done without blending to replace
560 // the current background pixels with the new filtered background.
561 // 6. Draw the contents of the quad over drop of the new background with
562 // blending, as per usual. The filtered background pixels will show through
563 // any non-opaque pixels in this draws.
565 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
567 // FIXME: When this algorithm changes, update
568 // LayerTreeHost::PrioritizeTextures() accordingly.
570 const WebKit::WebFilterOperations& filters = quad->background_filters;
571 DCHECK(!filters.isEmpty());
573 // FIXME: We only allow background filters on an opaque render surface because
574 // other surfaces may contain translucent pixels, and the contents behind
575 // those translucent pixels wouldn't have the filter applied.
576 if (frame->current_render_pass->has_transparent_background)
577 return scoped_ptr<ScopedResource>();
578 DCHECK(!frame->current_texture);
580 // FIXME: Do a single readback for both the surface and replica and cache the
581 // filtered results (once filter textures are not reused).
582 gfx::Rect device_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
583 contents_device_transform, SharedGeometryQuad().BoundingBox()));
585 int top, right, bottom, left;
586 filters.getOutsets(top, right, bottom, left);
587 device_rect.Inset(-left, -top, -right, -bottom);
589 device_rect.Intersect(frame->current_render_pass->output_rect);
591 scoped_ptr<ScopedResource> device_background_texture =
592 ScopedResource::create(resource_provider_);
593 if (!GetFramebufferTexture(device_background_texture.get(), device_rect))
594 return scoped_ptr<ScopedResource>();
596 SkBitmap filtered_device_background =
597 ApplyFilters(this, filters, device_background_texture.get());
598 if (!filtered_device_background.getTexture())
599 return scoped_ptr<ScopedResource>();
601 GrTexture* texture =
602 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
603 int filtered_device_background_texture_id = texture->getTextureHandle();
605 scoped_ptr<ScopedResource> background_texture =
606 ScopedResource::create(resource_provider_);
607 if (!background_texture->Allocate(quad->rect.size(),
608 GL_RGBA,
609 ResourceProvider::TextureUsageFramebuffer))
610 return scoped_ptr<ScopedResource>();
612 const RenderPass* target_render_pass = frame->current_render_pass;
613 bool using_background_texture =
614 UseScopedTexture(frame, background_texture.get(), quad->rect);
616 if (using_background_texture) {
617 // Copy the readback pixels from device to the background texture for the
618 // surface.
619 gfx::Transform device_to_framebuffer_transform;
620 device_to_framebuffer_transform.Translate(
621 quad->rect.width() * 0.5f + quad->rect.x(),
622 quad->rect.height() * 0.5f + quad->rect.y());
623 device_to_framebuffer_transform.Scale(quad->rect.width(),
624 quad->rect.height());
625 device_to_framebuffer_transform.PreconcatTransform(
626 contents_device_transform_inverse);
628 #ifndef NDEBUG
629 GLC(Context(), Context()->clearColor(0, 0, 1, 1));
630 Context()->clear(GL_COLOR_BUFFER_BIT);
631 #endif
633 CopyTextureToFramebuffer(frame,
634 filtered_device_background_texture_id,
635 device_rect,
636 device_to_framebuffer_transform);
639 UseRenderPass(frame, target_render_pass);
641 if (!using_background_texture)
642 return scoped_ptr<ScopedResource>();
643 return background_texture.Pass();
646 void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
647 const RenderPassDrawQuad* quad) {
648 SetBlendEnabled(quad->ShouldDrawWithBlending());
650 CachedResource* contents_texture =
651 render_pass_textures_.get(quad->render_pass_id);
652 if (!contents_texture || !contents_texture->id())
653 return;
655 gfx::Transform quad_rect_matrix;
656 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
657 gfx::Transform contents_device_transform =
658 frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
659 contents_device_transform.FlattenTo2d();
661 // Can only draw surface if device matrix is invertible.
662 gfx::Transform contents_device_transform_inverse(
663 gfx::Transform::kSkipInitialization);
664 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
665 return;
667 scoped_ptr<ScopedResource> background_texture;
668 if (!quad->background_filters.isEmpty()) {
669 // The pixels from the filtered background should completely replace the
670 // current pixel values.
671 bool disable_blending = blend_enabled();
672 if (disable_blending)
673 SetBlendEnabled(false);
675 background_texture = DrawBackgroundFilters(
676 frame,
677 quad,
678 contents_device_transform,
679 contents_device_transform_inverse);
681 if (disable_blending)
682 SetBlendEnabled(true);
685 // FIXME: Cache this value so that we don't have to do it for both the surface
686 // and its replica. Apply filters to the contents texture.
687 SkBitmap filter_bitmap;
688 SkScalar color_matrix[20];
689 bool use_color_matrix = false;
690 if (quad->filter) {
691 SkColorFilter* cf;
692 if ((quad->filter->asColorFilter(&cf)) && cf->asColorMatrix(color_matrix) &&
693 !quad->filter->getInput(0)) {
694 // We have a single color matrix as a filter; apply it locally
695 // in the compositor.
696 use_color_matrix = true;
697 } else {
698 filter_bitmap =
699 ApplyImageFilter(this, quad->filter.get(), contents_texture);
701 } else {
702 filter_bitmap = ApplyFilters(this, quad->filters, contents_texture);
705 // Draw the background texture if there is one.
706 if (background_texture) {
707 DCHECK(background_texture->size() == quad->rect.size());
708 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
709 background_texture->id());
710 CopyTextureToFramebuffer(
711 frame, lock.texture_id(), quad->rect, quad->quadTransform());
714 bool clipped = false;
715 gfx::QuadF device_quad = MathUtil::MapQuad(
716 contents_device_transform, SharedGeometryQuad(), &clipped);
717 DCHECK(!clipped);
718 LayerQuad device_layer_bounds(gfx::QuadF(device_quad.BoundingBox()));
719 LayerQuad device_layer_edges(device_quad);
721 // Use anti-aliasing programs only when necessary.
722 bool use_aa = (!device_quad.IsRectilinear() ||
723 !device_quad.BoundingBox().IsExpressibleAsRect());
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 texCoordPrecision = 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(texCoordPrecision);
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(texCoordPrecision);
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(texCoordPrecision);
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(texCoordPrecision);
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(texCoordPrecision);
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(texCoordPrecision);
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(texCoordPrecision);
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(texCoordPrecision);
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 // TODO(reveman): Axis-aligned is not enough to avoid anti-aliasing.
1020 // Bounding rectangle for quad also needs to be expressible as an integer
1021 // rectangle. crbug.com/169374
1022 bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear();
1023 bool use_aa = !clipped && !is_axis_aligned_in_target && 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 const float epsilon = 1.0f / 1024.0f;
1209 float tex_clamp_x = std::min(0.5f, 0.5f * clamp_tex_rect.width() - epsilon);
1210 float tex_clamp_y = std::min(0.5f, 0.5f * clamp_tex_rect.height() - epsilon);
1211 float geom_clamp_x = std::min(tex_clamp_x * tex_to_geom_scale_x,
1212 0.5f * clamp_geom_rect.width() - epsilon);
1213 float geom_clamp_y = std::min(tex_clamp_y * tex_to_geom_scale_y,
1214 0.5f * clamp_geom_rect.height() - epsilon);
1215 clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y);
1216 clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y);
1218 // Map clamping rectangle to unit square.
1219 float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width();
1220 float vertex_tex_translate_y =
1221 -clamp_geom_rect.y() / clamp_geom_rect.height();
1222 float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width();
1223 float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height();
1225 // We assume we do not need highp texture coordinates for tiles.
1226 // Make sure that assumption is correct here.
1227 DCHECK_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
1228 context_, highp_threshold_min_, quad->texture_size));
1230 // Map to normalized texture coordinates.
1231 gfx::Size texture_size = quad->texture_size;
1232 float fragment_tex_translate_x = clamp_tex_rect.x() / texture_size.width();
1233 float fragment_tex_translate_y = clamp_tex_rect.y() / texture_size.height();
1234 float fragment_tex_scale_x = clamp_tex_rect.width() / texture_size.width();
1235 float fragment_tex_scale_y = clamp_tex_rect.height() / texture_size.height();
1237 gfx::Transform device_transform =
1238 frame->window_matrix * frame->projection_matrix * quad->quadTransform();
1239 device_transform.FlattenTo2d();
1240 if (!device_transform.IsInvertible())
1241 return;
1243 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect));
1244 float edge[24];
1245 bool use_aa = SetupQuadForAntialiasing(
1246 device_transform, quad, &local_quad, edge);
1248 TileProgramUniforms uniforms;
1249 if (use_aa) {
1250 if (quad->swizzle_contents)
1251 TileUniformLocation(GetTileProgramSwizzleAA(), &uniforms);
1252 else
1253 TileUniformLocation(GetTileProgramAA(), &uniforms);
1254 } else {
1255 if (quad->ShouldDrawWithBlending()) {
1256 if (quad->swizzle_contents)
1257 TileUniformLocation(GetTileProgramSwizzle(), &uniforms);
1258 else
1259 TileUniformLocation(GetTileProgram(), &uniforms);
1260 } else {
1261 if (quad->swizzle_contents)
1262 TileUniformLocation(GetTileProgramSwizzleOpaque(), &uniforms);
1263 else
1264 TileUniformLocation(GetTileProgramOpaque(), &uniforms);
1268 SetUseProgram(uniforms.program);
1269 GLC(Context(), Context()->uniform1i(uniforms.sampler_location, 0));
1270 bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
1271 GLenum filter = (use_aa || scaled ||
1272 !quad->quadTransform().IsIdentityOrIntegerTranslation())
1273 ? GL_LINEAR
1274 : GL_NEAREST;
1275 ResourceProvider::ScopedSamplerGL quad_resource_lock(
1276 resource_provider_, resource_id, GL_TEXTURE_2D, filter);
1278 if (use_aa) {
1279 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge));
1281 GLC(Context(),
1282 Context()->uniform4f(uniforms.vertex_tex_transform_location,
1283 vertex_tex_translate_x,
1284 vertex_tex_translate_y,
1285 vertex_tex_scale_x,
1286 vertex_tex_scale_y));
1287 GLC(Context(),
1288 Context()->uniform4f(uniforms.fragment_tex_transform_location,
1289 fragment_tex_translate_x,
1290 fragment_tex_translate_y,
1291 fragment_tex_scale_x,
1292 fragment_tex_scale_y));
1293 } else {
1294 // Move fragment shader transform to vertex shader. We can do this while
1295 // still producing correct results as fragment_tex_transform_location
1296 // should always be non-negative when tiles are transformed in a way
1297 // that could result in sampling outside the layer.
1298 vertex_tex_scale_x *= fragment_tex_scale_x;
1299 vertex_tex_scale_y *= fragment_tex_scale_y;
1300 vertex_tex_translate_x *= fragment_tex_scale_x;
1301 vertex_tex_translate_y *= fragment_tex_scale_y;
1302 vertex_tex_translate_x += fragment_tex_translate_x;
1303 vertex_tex_translate_y += fragment_tex_translate_y;
1305 GLC(Context(),
1306 Context()->uniform4f(uniforms.vertex_tex_transform_location,
1307 vertex_tex_translate_x,
1308 vertex_tex_translate_y,
1309 vertex_tex_scale_x,
1310 vertex_tex_scale_y));
1313 // Enable blending when the quad properties require it or if we decided
1314 // to use antialiasing.
1315 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
1317 // Normalize to tile_rect.
1318 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
1320 SetShaderOpacity(quad->opacity(), uniforms.alpha_location);
1321 SetShaderQuadF(local_quad, uniforms.point_location);
1323 // The transform and vertex data are used to figure out the extents that the
1324 // un-antialiased quad should have and which vertex this is and the float
1325 // quad passed in via uniform is the actual geometry that gets used to draw
1326 // it. This is why this centered rect is used and not the original quad_rect.
1327 gfx::RectF centered_rect(
1328 gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
1329 tile_rect.size());
1330 DrawQuadGeometry(
1331 frame, quad->quadTransform(), centered_rect, uniforms.matrix_location);
1334 void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
1335 const YUVVideoDrawQuad* quad) {
1336 SetBlendEnabled(quad->ShouldDrawWithBlending());
1338 TexCoordPrecision texCoordPrecision = TexCoordPrecisionRequired(
1339 context_, highp_threshold_min_,
1340 quad->shared_quad_state->visible_content_rect.bottom_right());
1342 const VideoYUVProgram* program = GetVideoYUVProgram(texCoordPrecision);
1343 DCHECK(program && (program->initialized() || IsContextLost()));
1345 GLC(Context(), Context()->activeTexture(GL_TEXTURE1));
1346 ResourceProvider::ScopedSamplerGL y_plane_lock(
1347 resource_provider_, quad->y_plane_resource_id, GL_TEXTURE_2D, GL_LINEAR);
1348 GLC(Context(), Context()->activeTexture(GL_TEXTURE2));
1349 ResourceProvider::ScopedSamplerGL u_plane_lock(
1350 resource_provider_, quad->u_plane_resource_id, GL_TEXTURE_2D, GL_LINEAR);
1351 GLC(Context(), Context()->activeTexture(GL_TEXTURE3));
1352 ResourceProvider::ScopedSamplerGL v_plane_lock(
1353 resource_provider_, quad->v_plane_resource_id, GL_TEXTURE_2D, GL_LINEAR);
1355 SetUseProgram(program->program());
1357 GLC(Context(),
1358 Context()->uniform2f(program->vertex_shader().tex_scale_location(),
1359 quad->tex_scale.width(),
1360 quad->tex_scale.height()));
1361 GLC(Context(),
1362 Context()->uniform1i(program->fragment_shader().y_texture_location(), 1));
1363 GLC(Context(),
1364 Context()->uniform1i(program->fragment_shader().u_texture_location(), 2));
1365 GLC(Context(),
1366 Context()->uniform1i(program->fragment_shader().v_texture_location(), 3));
1368 // These values are magic numbers that are used in the transformation from YUV
1369 // to RGB color values. They are taken from the following webpage:
1370 // http://www.fourcc.org/fccyvrgb.php
1371 float yuv_to_rgb[9] = {
1372 1.164f, 1.164f, 1.164f,
1373 0.0f, -.391f, 2.018f,
1374 1.596f, -.813f, 0.0f,
1376 GLC(Context(),
1377 Context()->uniformMatrix3fv(
1378 program->fragment_shader().yuv_matrix_location(), 1, 0, yuv_to_rgb));
1380 // These values map to 16, 128, and 128 respectively, and are computed
1381 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
1382 // They are used in the YUV to RGBA conversion formula:
1383 // Y - 16 : Gives 16 values of head and footroom for overshooting
1384 // U - 128 : Turns unsigned U into signed U [-128,127]
1385 // V - 128 : Turns unsigned V into signed V [-128,127]
1386 float yuv_adjust[3] = { -0.0625f, -0.5f, -0.5f, };
1387 GLC(Context(),
1388 Context()->uniform3fv(
1389 program->fragment_shader().yuv_adj_location(), 1, yuv_adjust));
1391 SetShaderOpacity(quad->opacity(),
1392 program->fragment_shader().alpha_location());
1393 DrawQuadGeometry(frame,
1394 quad->quadTransform(),
1395 quad->rect,
1396 program->vertex_shader().matrix_location());
1398 // Reset active texture back to texture 0.
1399 GLC(Context(), Context()->activeTexture(GL_TEXTURE0));
1402 void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame,
1403 const StreamVideoDrawQuad* quad) {
1404 SetBlendEnabled(quad->ShouldDrawWithBlending());
1406 static float gl_matrix[16];
1408 DCHECK(capabilities_.using_egl_image);
1410 TexCoordPrecision texCoordPrecision = TexCoordPrecisionRequired(
1411 context_, highp_threshold_min_,
1412 quad->shared_quad_state->visible_content_rect.bottom_right());
1414 const VideoStreamTextureProgram* program =
1415 GetVideoStreamTextureProgram(texCoordPrecision);
1416 SetUseProgram(program->program());
1418 ToGLMatrix(&gl_matrix[0], quad->matrix);
1419 GLC(Context(),
1420 Context()->uniformMatrix4fv(
1421 program->vertex_shader().tex_matrix_location(), 1, false, gl_matrix));
1423 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
1424 quad->resource_id);
1425 GLC(Context(),
1426 Context()->bindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id()));
1428 GLC(Context(),
1429 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1431 SetShaderOpacity(quad->opacity(),
1432 program->fragment_shader().alpha_location());
1433 DrawQuadGeometry(frame,
1434 quad->quadTransform(),
1435 quad->rect,
1436 program->vertex_shader().matrix_location());
1439 void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
1440 const PictureDrawQuad* quad) {
1441 if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() ||
1442 on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) {
1443 on_demand_tile_raster_bitmap_.setConfig(
1444 SkBitmap::kARGB_8888_Config,
1445 quad->texture_size.width(),
1446 quad->texture_size.height());
1447 on_demand_tile_raster_bitmap_.allocPixels();
1449 if (on_demand_tile_raster_resource_id_)
1450 resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
1452 on_demand_tile_raster_resource_id_ = resource_provider_->CreateGLTexture(
1453 quad->texture_size,
1454 GL_RGBA,
1455 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
1456 ResourceProvider::TextureUsageAny);
1459 SkDevice device(on_demand_tile_raster_bitmap_);
1460 SkCanvas canvas(&device);
1462 quad->picture_pile->Raster(&canvas, quad->content_rect, quad->contents_scale);
1464 resource_provider_->SetPixels(
1465 on_demand_tile_raster_resource_id_,
1466 reinterpret_cast<uint8_t*>(on_demand_tile_raster_bitmap_.getPixels()),
1467 gfx::Rect(quad->texture_size),
1468 gfx::Rect(quad->texture_size),
1469 gfx::Vector2d());
1471 DrawContentQuad(frame, quad, on_demand_tile_raster_resource_id_);
1474 struct TextureProgramBinding {
1475 template <class Program>
1476 void Set(Program* program, WebKit::WebGraphicsContext3D* context) {
1477 DCHECK(program && (program->initialized() || context->isContextLost()));
1478 program_id = program->program();
1479 sampler_location = program->fragment_shader().sampler_location();
1480 matrix_location = program->vertex_shader().matrix_location();
1481 alpha_location = program->fragment_shader().alpha_location();
1483 int program_id;
1484 int sampler_location;
1485 int matrix_location;
1486 int alpha_location;
1489 struct TexTransformTextureProgramBinding : TextureProgramBinding {
1490 template <class Program>
1491 void Set(Program* program, WebKit::WebGraphicsContext3D* context) {
1492 TextureProgramBinding::Set(program, context);
1493 tex_transform_location = program->vertex_shader().tex_transform_location();
1494 vertex_opacity_location =
1495 program->vertex_shader().vertex_opacity_location();
1497 int tex_transform_location;
1498 int vertex_opacity_location;
1501 void GLRenderer::FlushTextureQuadCache() {
1502 // Check to see if we have anything to draw.
1503 if (draw_cache_.program_id == 0)
1504 return;
1506 // Set the correct blending mode.
1507 SetBlendEnabled(draw_cache_.needs_blending);
1509 // Bind the program to the GL state.
1510 SetUseProgram(draw_cache_.program_id);
1512 // Bind the correct texture sampler location.
1513 GLC(Context(), Context()->uniform1i(draw_cache_.sampler_location, 0));
1515 // Assume the current active textures is 0.
1516 ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_,
1517 draw_cache_.resource_id);
1518 GLC(Context(),
1519 Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id()));
1521 // set up premultiplied alpha.
1522 if (!draw_cache_.use_premultiplied_alpha) {
1523 // As it turns out, the premultiplied alpha blending function (ONE,
1524 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to
1525 // anything less than 1.0f if it is initialized to that value! Therefore,
1526 // premultiplied_alpha being false is the first situation we can generally
1527 // see an alpha channel less than 1.0f coming out of the compositor. This is
1528 // causing platform differences in some layout tests (see
1529 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use
1530 // a separate blend function for the alpha channel to avoid modifying it.
1531 // Don't use colorMask() for this as it has performance implications on some
1532 // platforms.
1533 GLC(Context(),
1534 Context()->blendFuncSeparate(
1535 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE));
1538 COMPILE_ASSERT(
1539 sizeof(Float4) == 4 * sizeof(float), // NOLINT(runtime/sizeof)
1540 struct_is_densely_packed);
1541 COMPILE_ASSERT(
1542 sizeof(Float16) == 16 * sizeof(float), // NOLINT(runtime/sizeof)
1543 struct_is_densely_packed);
1545 // Upload the tranforms for both points and uvs.
1546 GLC(context_,
1547 context_->uniformMatrix4fv(
1548 static_cast<int>(draw_cache_.matrix_location),
1549 static_cast<int>(draw_cache_.matrix_data.size()),
1550 false,
1551 reinterpret_cast<float*>(&draw_cache_.matrix_data.front())));
1552 GLC(context_,
1553 context_->uniform4fv(
1554 static_cast<int>(draw_cache_.uv_xform_location),
1555 static_cast<int>(draw_cache_.uv_xform_data.size()),
1556 reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front())));
1557 GLC(context_,
1558 context_->uniform1fv(
1559 static_cast<int>(draw_cache_.vertex_opacity_location),
1560 static_cast<int>(draw_cache_.vertex_opacity_data.size()),
1561 static_cast<float*>(&draw_cache_.vertex_opacity_data.front())));
1563 // Draw the quads!
1564 GLC(context_,
1565 context_->drawElements(GL_TRIANGLES,
1566 6 * draw_cache_.matrix_data.size(),
1567 GL_UNSIGNED_SHORT,
1568 0));
1570 // Clean up after ourselves (reset state set above).
1571 if (!draw_cache_.use_premultiplied_alpha)
1572 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
1574 // Clear the cache.
1575 draw_cache_.program_id = 0;
1576 draw_cache_.uv_xform_data.resize(0);
1577 draw_cache_.vertex_opacity_data.resize(0);
1578 draw_cache_.matrix_data.resize(0);
1581 void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
1582 const TextureDrawQuad* quad) {
1583 TexCoordPrecision texCoordPrecision = TexCoordPrecisionRequired(
1584 context_, highp_threshold_min_,
1585 quad->shared_quad_state->visible_content_rect.bottom_right());
1587 // Choose the correct texture program binding
1588 TexTransformTextureProgramBinding binding;
1589 if (quad->flipped)
1590 binding.Set(GetTextureProgramFlip(texCoordPrecision), Context());
1591 else
1592 binding.Set(GetTextureProgram(texCoordPrecision), Context());
1594 int resource_id = quad->resource_id;
1596 if (draw_cache_.program_id != binding.program_id ||
1597 draw_cache_.resource_id != resource_id ||
1598 draw_cache_.use_premultiplied_alpha != quad->premultiplied_alpha ||
1599 draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
1600 draw_cache_.matrix_data.size() >= 8) {
1601 FlushTextureQuadCache();
1602 draw_cache_.program_id = binding.program_id;
1603 draw_cache_.resource_id = resource_id;
1604 draw_cache_.use_premultiplied_alpha = quad->premultiplied_alpha;
1605 draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
1607 draw_cache_.uv_xform_location = binding.tex_transform_location;
1608 draw_cache_.vertex_opacity_location = binding.vertex_opacity_location;
1609 draw_cache_.matrix_location = binding.matrix_location;
1610 draw_cache_.sampler_location = binding.sampler_location;
1613 // Generate the uv-transform
1614 gfx::PointF uv0 = quad->uv_top_left;
1615 gfx::PointF uv1 = quad->uv_bottom_right;
1616 Float4 uv = { { uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y() } };
1617 draw_cache_.uv_xform_data.push_back(uv);
1619 // Generate the vertex opacity
1620 const float opacity = quad->opacity();
1621 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
1622 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity);
1623 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity);
1624 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity);
1626 // Generate the transform matrix
1627 gfx::Transform quad_rect_matrix;
1628 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
1629 quad_rect_matrix = frame->projection_matrix * quad_rect_matrix;
1631 Float16 m;
1632 quad_rect_matrix.matrix().asColMajorf(m.data);
1633 draw_cache_.matrix_data.push_back(m);
1636 void GLRenderer::DrawTextureQuad(const DrawingFrame* frame,
1637 const TextureDrawQuad* quad) {
1638 TexCoordPrecision texCoordPrecision = TexCoordPrecisionRequired(
1639 context_, highp_threshold_min_,
1640 quad->shared_quad_state->visible_content_rect.bottom_right());
1642 TexTransformTextureProgramBinding binding;
1643 if (quad->flipped)
1644 binding.Set(GetTextureProgramFlip(texCoordPrecision), Context());
1645 else
1646 binding.Set(GetTextureProgram(texCoordPrecision), Context());
1647 SetUseProgram(binding.program_id);
1648 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0));
1649 gfx::PointF uv0 = quad->uv_top_left;
1650 gfx::PointF uv1 = quad->uv_bottom_right;
1651 GLC(Context(),
1652 Context()->uniform4f(binding.tex_transform_location,
1653 uv0.x(),
1654 uv0.y(),
1655 uv1.x() - uv0.x(),
1656 uv1.y() - uv0.y()));
1658 GLC(Context(),
1659 Context()->uniform1fv(
1660 binding.vertex_opacity_location, 4, quad->vertex_opacity));
1662 ResourceProvider::ScopedSamplerGL quad_resource_lock(
1663 resource_provider_, quad->resource_id, GL_TEXTURE_2D, GL_LINEAR);
1665 if (!quad->premultiplied_alpha) {
1666 // As it turns out, the premultiplied alpha blending function (ONE,
1667 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to
1668 // anything less than 1.0f if it is initialized to that value! Therefore,
1669 // premultiplied_alpha being false is the first situation we can generally
1670 // see an alpha channel less than 1.0f coming out of the compositor. This is
1671 // causing platform differences in some layout tests (see
1672 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use
1673 // a separate blend function for the alpha channel to avoid modifying it.
1674 // Don't use colorMask() for this as it has performance implications on some
1675 // platforms.
1676 GLC(Context(),
1677 Context()->blendFuncSeparate(
1678 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE));
1681 DrawQuadGeometry(
1682 frame, quad->quadTransform(), quad->rect, binding.matrix_location);
1684 if (!quad->premultiplied_alpha)
1685 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
1688 void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame,
1689 const IOSurfaceDrawQuad* quad) {
1690 SetBlendEnabled(quad->ShouldDrawWithBlending());
1692 TexCoordPrecision texCoordPrecision = TexCoordPrecisionRequired(
1693 context_, highp_threshold_min_,
1694 quad->shared_quad_state->visible_content_rect.bottom_right());
1696 TexTransformTextureProgramBinding binding;
1697 binding.Set(GetTextureIOSurfaceProgram(texCoordPrecision), Context());
1699 SetUseProgram(binding.program_id);
1700 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0));
1701 if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) {
1702 GLC(Context(),
1703 Context()->uniform4f(binding.tex_transform_location,
1705 quad->io_surface_size.height(),
1706 quad->io_surface_size.width(),
1707 quad->io_surface_size.height() * -1.0f));
1708 } else {
1709 GLC(Context(),
1710 Context()->uniform4f(binding.tex_transform_location,
1713 quad->io_surface_size.width(),
1714 quad->io_surface_size.height()));
1717 const float vertex_opacity[] = { quad->opacity(), quad->opacity(),
1718 quad->opacity(), quad->opacity() };
1719 GLC(Context(),
1720 Context()->uniform1fv(
1721 binding.vertex_opacity_location, 4, vertex_opacity));
1723 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
1724 quad->io_surface_resource_id);
1725 GLC(Context(),
1726 Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB,
1727 lock.texture_id()));
1729 DrawQuadGeometry(
1730 frame, quad->quadTransform(), quad->rect, binding.matrix_location);
1732 GLC(Context(), Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, 0));
1735 void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
1736 current_framebuffer_lock_.reset();
1737 swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect));
1739 GLC(context_, context_->disable(GL_BLEND));
1740 blend_shadow_ = false;
1742 if (Settings().compositor_frame_message) {
1743 CompositorFrame compositor_frame;
1744 compositor_frame.metadata = client_->MakeCompositorFrameMetadata();
1745 output_surface_->SendFrameToParentCompositor(&compositor_frame);
1749 void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); }
1751 bool GLRenderer::FlippedFramebuffer() const { return true; }
1753 void GLRenderer::EnsureScissorTestEnabled() {
1754 if (is_scissor_enabled_)
1755 return;
1757 FlushTextureQuadCache();
1758 GLC(context_, context_->enable(GL_SCISSOR_TEST));
1759 is_scissor_enabled_ = true;
1762 void GLRenderer::EnsureScissorTestDisabled() {
1763 if (!is_scissor_enabled_)
1764 return;
1766 FlushTextureQuadCache();
1767 GLC(context_, context_->disable(GL_SCISSOR_TEST));
1768 is_scissor_enabled_ = false;
1771 void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) {
1772 transform.matrix().asColMajorf(gl_matrix);
1775 void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) {
1776 if (quad_location == -1)
1777 return;
1779 float point[8];
1780 point[0] = quad.p1().x();
1781 point[1] = quad.p1().y();
1782 point[2] = quad.p2().x();
1783 point[3] = quad.p2().y();
1784 point[4] = quad.p3().x();
1785 point[5] = quad.p3().y();
1786 point[6] = quad.p4().x();
1787 point[7] = quad.p4().y();
1788 GLC(context_, context_->uniform2fv(quad_location, 4, point));
1791 void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) {
1792 if (alpha_location != -1)
1793 GLC(context_, context_->uniform1f(alpha_location, opacity));
1796 void GLRenderer::SetBlendEnabled(bool enabled) {
1797 if (enabled == blend_shadow_)
1798 return;
1800 if (enabled)
1801 GLC(context_, context_->enable(GL_BLEND));
1802 else
1803 GLC(context_, context_->disable(GL_BLEND));
1804 blend_shadow_ = enabled;
1807 void GLRenderer::SetUseProgram(unsigned program) {
1808 if (program == program_shadow_)
1809 return;
1810 GLC(context_, context_->useProgram(program));
1811 program_shadow_ = program;
1814 void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame,
1815 const gfx::Transform& draw_transform,
1816 const gfx::RectF& quad_rect,
1817 int matrix_location) {
1818 gfx::Transform quad_rect_matrix;
1819 QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
1820 static float gl_matrix[16];
1821 ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix);
1822 GLC(context_,
1823 context_->uniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0]));
1825 GLC(context_, context_->drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
1828 void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
1829 int texture_id,
1830 gfx::Rect rect,
1831 const gfx::Transform& draw_matrix) {
1832 TexCoordPrecision texCoordPrecision = TexCoordPrecisionRequired(
1833 context_, highp_threshold_min_, rect.bottom_right());
1834 const RenderPassProgram* program = GetRenderPassProgram(texCoordPrecision);
1836 GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, texture_id));
1838 SetUseProgram(program->program());
1839 GLC(Context(),
1840 Context()->uniform1i(program->fragment_shader().sampler_location(), 0));
1841 GLC(Context(),
1842 Context()->uniform4f(program->vertex_shader().tex_transform_location(),
1843 0.0f,
1844 0.0f,
1845 1.0f,
1846 1.0f));
1847 SetShaderOpacity(1, program->fragment_shader().alpha_location());
1848 DrawQuadGeometry(
1849 frame, draw_matrix, rect, program->vertex_shader().matrix_location());
1852 void GLRenderer::Finish() {
1853 TRACE_EVENT0("cc", "GLRenderer::finish");
1854 context_->finish();
1857 bool GLRenderer::SwapBuffers() {
1858 DCHECK(visible_);
1859 DCHECK(!is_backbuffer_discarded_);
1861 TRACE_EVENT0("cc", "GLRenderer::SwapBuffers");
1862 // We're done! Time to swapbuffers!
1864 if (capabilities_.using_partial_swap && client_->AllowPartialSwap()) {
1865 // If supported, we can save significant bandwidth by only swapping the
1866 // damaged/scissored region (clamped to the viewport)
1867 swap_buffer_rect_.Intersect(gfx::Rect(ViewportSize()));
1868 int flipped_y_pos_of_rect_bottom =
1869 ViewportHeight() - swap_buffer_rect_.y() - swap_buffer_rect_.height();
1870 output_surface_->PostSubBuffer(gfx::Rect(swap_buffer_rect_.x(),
1871 flipped_y_pos_of_rect_bottom,
1872 swap_buffer_rect_.width(),
1873 swap_buffer_rect_.height()),
1874 LatencyInfo());
1875 } else {
1876 output_surface_->SwapBuffers(LatencyInfo());
1879 swap_buffer_rect_ = gfx::Rect();
1881 // We don't have real fences, so we mark read fences as passed
1882 // assuming a double-buffered GPU pipeline. A texture can be
1883 // written to after one full frame has past since it was last read.
1884 if (last_swap_fence_)
1885 static_cast<SimpleSwapFence*>(last_swap_fence_.get())->SetHasPassed();
1886 last_swap_fence_ = resource_provider_->GetReadLockFence();
1887 resource_provider_->SetReadLockFence(new SimpleSwapFence());
1889 return true;
1892 void GLRenderer::ReceiveCompositorFrameAck(const CompositorFrameAck& ack) {
1893 onSwapBuffersComplete();
1896 void GLRenderer::onSwapBuffersComplete() { client_->OnSwapBuffersComplete(); }
1898 void GLRenderer::onMemoryAllocationChanged(
1899 WebGraphicsMemoryAllocation allocation) {
1900 // Just ignore the memory manager when it says to set the limit to zero
1901 // bytes. This will happen when the memory manager thinks that the renderer
1902 // is not visible (which the renderer knows better).
1903 if (allocation.bytesLimitWhenVisible) {
1904 ManagedMemoryPolicy policy(
1905 allocation.bytesLimitWhenVisible,
1906 PriorityCutoff(allocation.priorityCutoffWhenVisible),
1907 allocation.bytesLimitWhenNotVisible,
1908 PriorityCutoff(allocation.priorityCutoffWhenNotVisible));
1910 if (allocation.enforceButDoNotKeepAsPolicy)
1911 client_->EnforceManagedMemoryPolicy(policy);
1912 else
1913 client_->SetManagedMemoryPolicy(policy);
1916 bool old_discard_backbuffer_when_not_visible =
1917 discard_backbuffer_when_not_visible_;
1918 discard_backbuffer_when_not_visible_ = !allocation.suggestHaveBackbuffer;
1919 EnforceMemoryPolicy();
1920 if (allocation.enforceButDoNotKeepAsPolicy)
1921 discard_backbuffer_when_not_visible_ =
1922 old_discard_backbuffer_when_not_visible;
1925 ManagedMemoryPolicy::PriorityCutoff GLRenderer::PriorityCutoff(
1926 WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priority_cutoff) {
1927 // This is simple a 1:1 map, the names differ only because the WebKit names
1928 // should be to match the cc names.
1929 switch (priority_cutoff) {
1930 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing:
1931 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
1932 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly:
1933 return ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
1934 case WebKit::WebGraphicsMemoryAllocation::
1935 PriorityCutoffAllowVisibleAndNearby:
1936 return ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
1937 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything:
1938 return ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING;
1940 NOTREACHED();
1941 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
1944 void GLRenderer::EnforceMemoryPolicy() {
1945 if (!visible_) {
1946 TRACE_EVENT0("cc", "GLRenderer::EnforceMemoryPolicy dropping resources");
1947 ReleaseRenderPassTextures();
1948 if (discard_backbuffer_when_not_visible_)
1949 DiscardBackbuffer();
1950 resource_provider_->ReleaseCachedData();
1951 GLC(context_, context_->flush());
1955 void GLRenderer::DiscardBackbuffer() {
1956 if (is_backbuffer_discarded_)
1957 return;
1959 output_surface_->DiscardBackbuffer();
1961 is_backbuffer_discarded_ = true;
1963 // Damage tracker needs a full reset every time framebuffer is discarded.
1964 client_->SetFullRootLayerDamage();
1967 void GLRenderer::EnsureBackbuffer() {
1968 if (!is_backbuffer_discarded_)
1969 return;
1971 output_surface_->EnsureBackbuffer();
1972 is_backbuffer_discarded_ = false;
1975 void GLRenderer::onContextLost() { client_->DidLoseOutputSurface(); }
1977 void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
1978 DCHECK(rect.right() <= ViewportWidth());
1979 DCHECK(rect.bottom() <= ViewportHeight());
1981 if (!pixels)
1982 return;
1984 MakeContextCurrent();
1986 bool do_workaround = NeedsIOSurfaceReadbackWorkaround();
1988 GLuint temporary_texture = 0;
1989 GLuint temporary_fbo = 0;
1991 if (do_workaround) {
1992 // On Mac OS X, calling glReadPixels() against an FBO whose color attachment
1993 // is an IOSurface-backed texture causes corruption of future glReadPixels()
1994 // calls, even those on different OpenGL contexts. It is believed that this
1995 // is the root cause of top crasher
1996 // http://crbug.com/99393. <rdar://problem/10949687>
1998 temporary_texture = context_->createTexture();
1999 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture));
2000 GLC(context_,
2001 context_->texParameteri(
2002 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2003 GLC(context_,
2004 context_->texParameteri(
2005 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2006 GLC(context_,
2007 context_->texParameteri(
2008 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2009 GLC(context_,
2010 context_->texParameteri(
2011 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2012 // Copy the contents of the current (IOSurface-backed) framebuffer into a
2013 // temporary texture.
2014 GLC(context_,
2015 context_->copyTexImage2D(GL_TEXTURE_2D,
2017 GL_RGBA,
2020 ViewportSize().width(),
2021 ViewportSize().height(),
2022 0));
2023 temporary_fbo = context_->createFramebuffer();
2024 // Attach this texture to an FBO, and perform the readback from that FBO.
2025 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
2026 GLC(context_,
2027 context_->framebufferTexture2D(GL_FRAMEBUFFER,
2028 GL_COLOR_ATTACHMENT0,
2029 GL_TEXTURE_2D,
2030 temporary_texture,
2031 0));
2033 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
2034 GL_FRAMEBUFFER_COMPLETE);
2037 scoped_ptr<uint8_t[]> src_pixels(
2038 new uint8_t[rect.width() * rect.height() * 4]);
2039 GLC(context_,
2040 context_->readPixels(rect.x(),
2041 ViewportSize().height() - rect.bottom(),
2042 rect.width(),
2043 rect.height(),
2044 GL_RGBA,
2045 GL_UNSIGNED_BYTE,
2046 src_pixels.get()));
2048 uint8_t* dest_pixels = static_cast<uint8_t*>(pixels);
2049 size_t row_bytes = rect.width() * 4;
2050 int num_rows = rect.height();
2051 size_t total_bytes = num_rows * row_bytes;
2052 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
2053 // Flip Y axis.
2054 size_t src_y = total_bytes - dest_y - row_bytes;
2055 // Swizzle BGRA -> RGBA.
2056 for (size_t x = 0; x < row_bytes; x += 4) {
2057 dest_pixels[dest_y + (x + 0)] = src_pixels.get()[src_y + (x + 2)];
2058 dest_pixels[dest_y + (x + 1)] = src_pixels.get()[src_y + (x + 1)];
2059 dest_pixels[dest_y + (x + 2)] = src_pixels.get()[src_y + (x + 0)];
2060 dest_pixels[dest_y + (x + 3)] = src_pixels.get()[src_y + (x + 3)];
2064 if (do_workaround) {
2065 // Clean up.
2066 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0));
2067 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2068 GLC(context_, context_->deleteFramebuffer(temporary_fbo));
2069 GLC(context_, context_->deleteTexture(temporary_texture));
2072 EnforceMemoryPolicy();
2075 bool GLRenderer::GetFramebufferTexture(ScopedResource* texture,
2076 gfx::Rect device_rect) {
2077 DCHECK(!texture->id() || (texture->size() == device_rect.size() &&
2078 texture->format() == GL_RGB));
2080 if (!texture->id() && !texture->Allocate(device_rect.size(),
2081 GL_RGB,
2082 ResourceProvider::TextureUsageAny))
2083 return false;
2085 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, texture->id());
2086 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, lock.texture_id()));
2087 GLC(context_,
2088 context_->copyTexImage2D(GL_TEXTURE_2D,
2090 texture->format(),
2091 device_rect.x(),
2092 device_rect.y(),
2093 device_rect.width(),
2094 device_rect.height(),
2095 0));
2096 return true;
2099 bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
2100 const ScopedResource* texture,
2101 gfx::Rect viewport_rect) {
2102 DCHECK(texture->id());
2103 frame->current_render_pass = NULL;
2104 frame->current_texture = texture;
2106 return BindFramebufferToTexture(frame, texture, viewport_rect);
2109 void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
2110 current_framebuffer_lock_.reset();
2111 output_surface_->BindFramebuffer();
2114 bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
2115 const ScopedResource* texture,
2116 gfx::Rect framebuffer_rect) {
2117 DCHECK(texture->id());
2119 GLC(context_,
2120 context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_));
2121 current_framebuffer_lock_ =
2122 make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL(
2123 resource_provider_, texture->id()));
2124 unsigned texture_id = current_framebuffer_lock_->texture_id();
2125 GLC(context_,
2126 context_->framebufferTexture2D(
2127 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0));
2129 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) ==
2130 GL_FRAMEBUFFER_COMPLETE || IsContextLost());
2132 InitializeMatrices(frame, framebuffer_rect, false);
2133 SetDrawViewportSize(framebuffer_rect.size());
2135 return true;
2138 void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
2139 EnsureScissorTestEnabled();
2141 // Don't unnecessarily ask the context to change the scissor, because it
2142 // may cause undesired GPU pipeline flushes.
2143 if (scissor_rect == scissor_rect_)
2144 return;
2146 scissor_rect_ = scissor_rect;
2147 FlushTextureQuadCache();
2148 GLC(context_,
2149 context_->scissor(scissor_rect.x(),
2150 scissor_rect.y(),
2151 scissor_rect.width(),
2152 scissor_rect.height()));
2155 void GLRenderer::SetDrawViewportSize(gfx::Size viewport_size) {
2156 GLC(context_,
2157 context_->viewport(0, 0, viewport_size.width(), viewport_size.height()));
2160 bool GLRenderer::MakeContextCurrent() { return context_->makeContextCurrent(); }
2162 bool GLRenderer::InitializeSharedObjects() {
2163 TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects");
2164 MakeContextCurrent();
2166 // Create an FBO for doing offscreen rendering.
2167 GLC(context_, offscreen_framebuffer_id_ = context_->createFramebuffer());
2169 // We will always need these programs to render, so create the programs
2170 // eagerly so that the shader compilation can start while we do other work.
2171 // Other programs are created lazily on first access.
2172 shared_geometry_ = make_scoped_ptr(
2173 new GeometryBinding(context_, QuadVertexRect()));
2174 render_pass_program_ = make_scoped_ptr(
2175 new RenderPassProgram(context_, TexCoordPrecisionMedium));
2176 render_pass_program_highp_ = make_scoped_ptr(
2177 new RenderPassProgram(context_, TexCoordPrecisionHigh));
2178 tile_program_ = make_scoped_ptr(
2179 new TileProgram(context_, TexCoordPrecisionMedium));
2180 tile_program_opaque_ = make_scoped_ptr(
2181 new TileProgramOpaque(context_, TexCoordPrecisionMedium));
2183 GLC(context_, context_->flush());
2185 return true;
2188 const GLRenderer::TileCheckerboardProgram*
2189 GLRenderer::GetTileCheckerboardProgram() {
2190 if (!tile_checkerboard_program_)
2191 tile_checkerboard_program_ = make_scoped_ptr(
2192 new TileCheckerboardProgram(context_, TexCoordPrecisionNA));
2193 if (!tile_checkerboard_program_->initialized()) {
2194 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
2195 tile_checkerboard_program_->Initialize(context_, is_using_bind_uniform_);
2197 return tile_checkerboard_program_.get();
2200 const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() {
2201 if (!debug_border_program_)
2202 debug_border_program_ = make_scoped_ptr(
2203 new DebugBorderProgram(context_, TexCoordPrecisionNA));
2204 if (!debug_border_program_->initialized()) {
2205 TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize");
2206 debug_border_program_->Initialize(context_, is_using_bind_uniform_);
2208 return debug_border_program_.get();
2211 const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() {
2212 if (!solid_color_program_)
2213 solid_color_program_ = make_scoped_ptr(
2214 new SolidColorProgram(context_, TexCoordPrecisionNA));
2215 if (!solid_color_program_->initialized()) {
2216 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
2217 solid_color_program_->Initialize(context_, is_using_bind_uniform_);
2219 return solid_color_program_.get();
2222 const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() {
2223 if (!solid_color_program_aa_) {
2224 solid_color_program_aa_ =
2225 make_scoped_ptr(new SolidColorProgramAA(context_, TexCoordPrecisionNA));
2227 if (!solid_color_program_aa_->initialized()) {
2228 TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize");
2229 solid_color_program_aa_->Initialize(context_, is_using_bind_uniform_);
2231 return solid_color_program_aa_.get();
2234 const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram(
2235 TexCoordPrecision precision) {
2236 scoped_ptr<RenderPassProgram> &program =
2237 (precision == TexCoordPrecisionHigh) ? render_pass_program_highp_
2238 : render_pass_program_;
2239 DCHECK(program);
2240 if (!program->initialized()) {
2241 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
2242 program->Initialize(context_, is_using_bind_uniform_);
2244 return program.get();
2247 const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
2248 TexCoordPrecision precision) {
2249 scoped_ptr<RenderPassProgramAA> &program =
2250 (precision == TexCoordPrecisionHigh) ? render_pass_program_aa_highp_
2251 : render_pass_program_aa_;
2252 if (!program)
2253 program =
2254 make_scoped_ptr(new RenderPassProgramAA(context_, precision));
2255 if (!program->initialized()) {
2256 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
2257 program->Initialize(context_, is_using_bind_uniform_);
2259 return program.get();
2262 const GLRenderer::RenderPassMaskProgram*
2263 GLRenderer::GetRenderPassMaskProgram(TexCoordPrecision precision) {
2264 scoped_ptr<RenderPassMaskProgram> &program =
2265 (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_highp_
2266 : render_pass_mask_program_;
2267 if (!program)
2268 program = make_scoped_ptr(new RenderPassMaskProgram(context_, precision));
2269 if (!program->initialized()) {
2270 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
2271 program->Initialize(context_, is_using_bind_uniform_);
2273 return program.get();
2276 const GLRenderer::RenderPassMaskProgramAA*
2277 GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision) {
2278 scoped_ptr<RenderPassMaskProgramAA> &program =
2279 (precision == TexCoordPrecisionHigh) ? render_pass_mask_program_aa_highp_
2280 : render_pass_mask_program_aa_;
2281 if (!program)
2282 program =
2283 make_scoped_ptr(new RenderPassMaskProgramAA(context_, precision));
2284 if (!program->initialized()) {
2285 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
2286 program->Initialize(context_, is_using_bind_uniform_);
2288 return program.get();
2291 const GLRenderer::RenderPassColorMatrixProgram*
2292 GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision) {
2293 scoped_ptr<RenderPassColorMatrixProgram> &program =
2294 (precision == TexCoordPrecisionHigh) ?
2295 render_pass_color_matrix_program_highp_ :
2296 render_pass_color_matrix_program_;
2297 if (!program)
2298 program = make_scoped_ptr(
2299 new RenderPassColorMatrixProgram(context_, precision));
2300 if (!program->initialized()) {
2301 TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize");
2302 program->Initialize(context_, is_using_bind_uniform_);
2304 return program.get();
2307 const GLRenderer::RenderPassColorMatrixProgramAA*
2308 GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
2309 scoped_ptr<RenderPassColorMatrixProgramAA> &program =
2310 (precision == TexCoordPrecisionHigh) ?
2311 render_pass_color_matrix_program_aa_highp_ :
2312 render_pass_color_matrix_program_aa_;
2313 if (!program)
2314 program = make_scoped_ptr(
2315 new RenderPassColorMatrixProgramAA(context_, precision));
2316 if (!program->initialized()) {
2317 TRACE_EVENT0("cc",
2318 "GLRenderer::renderPassColorMatrixProgramAA::initialize");
2319 program->Initialize(context_, is_using_bind_uniform_);
2321 return program.get();
2324 const GLRenderer::RenderPassMaskColorMatrixProgram*
2325 GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
2326 scoped_ptr<RenderPassMaskColorMatrixProgram> &program =
2327 (precision == TexCoordPrecisionHigh) ?
2328 render_pass_mask_color_matrix_program_highp_ :
2329 render_pass_mask_color_matrix_program_;
2330 if (!program)
2331 program = make_scoped_ptr(
2332 new RenderPassMaskColorMatrixProgram(context_, precision));
2333 if (!program->initialized()) {
2334 TRACE_EVENT0("cc",
2335 "GLRenderer::renderPassMaskColorMatrixProgram::initialize");
2336 program->Initialize(context_, is_using_bind_uniform_);
2338 return program.get();
2341 const GLRenderer::RenderPassMaskColorMatrixProgramAA*
2342 GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
2343 scoped_ptr<RenderPassMaskColorMatrixProgramAA> &program =
2344 (precision == TexCoordPrecisionHigh) ?
2345 render_pass_mask_color_matrix_program_aa_highp_ :
2346 render_pass_mask_color_matrix_program_aa_;
2347 if (!program)
2348 program = make_scoped_ptr(
2349 new RenderPassMaskColorMatrixProgramAA(context_, precision));
2350 if (!program->initialized()) {
2351 TRACE_EVENT0("cc",
2352 "GLRenderer::renderPassMaskColorMatrixProgramAA::initialize");
2353 program->Initialize(context_, is_using_bind_uniform_);
2355 return program.get();
2358 const GLRenderer::TileProgram* GLRenderer::GetTileProgram() {
2359 DCHECK(tile_program_);
2360 if (!tile_program_->initialized()) {
2361 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
2362 tile_program_->Initialize(context_, is_using_bind_uniform_);
2364 return tile_program_.get();
2367 const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque() {
2368 DCHECK(tile_program_opaque_);
2369 if (!tile_program_opaque_->initialized()) {
2370 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
2371 tile_program_opaque_->Initialize(context_, is_using_bind_uniform_);
2373 return tile_program_opaque_.get();
2376 const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA() {
2377 if (!tile_program_aa_)
2378 tile_program_aa_ = make_scoped_ptr(
2379 new TileProgramAA(context_, TexCoordPrecisionMedium));
2380 if (!tile_program_aa_->initialized()) {
2381 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
2382 tile_program_aa_->Initialize(context_, is_using_bind_uniform_);
2384 return tile_program_aa_.get();
2387 const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle() {
2388 if (!tile_program_swizzle_)
2389 tile_program_swizzle_ = make_scoped_ptr(
2390 new TileProgramSwizzle(context_, TexCoordPrecisionMedium));
2391 if (!tile_program_swizzle_->initialized()) {
2392 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
2393 tile_program_swizzle_->Initialize(context_, is_using_bind_uniform_);
2395 return tile_program_swizzle_.get();
2398 const GLRenderer::TileProgramSwizzleOpaque*
2399 GLRenderer::GetTileProgramSwizzleOpaque() {
2400 if (!tile_program_swizzle_opaque_)
2401 tile_program_swizzle_opaque_ = make_scoped_ptr(
2402 new TileProgramSwizzleOpaque(context_, TexCoordPrecisionMedium));
2403 if (!tile_program_swizzle_opaque_->initialized()) {
2404 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize");
2405 tile_program_swizzle_opaque_->Initialize(context_, is_using_bind_uniform_);
2407 return tile_program_swizzle_opaque_.get();
2410 const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA() {
2411 if (!tile_program_swizzle_aa_)
2412 tile_program_swizzle_aa_ = make_scoped_ptr(
2413 new TileProgramSwizzleAA(context_, TexCoordPrecisionMedium));
2414 if (!tile_program_swizzle_aa_->initialized()) {
2415 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
2416 tile_program_swizzle_aa_->Initialize(context_, is_using_bind_uniform_);
2418 return tile_program_swizzle_aa_.get();
2421 const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram(
2422 TexCoordPrecision precision) {
2423 scoped_ptr<TextureProgram> &program =
2424 (precision == TexCoordPrecisionHigh) ? texture_program_highp_
2425 : texture_program_;
2426 if (!program)
2427 program = make_scoped_ptr(new TextureProgram(context_, precision));
2428 if (!program->initialized()) {
2429 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
2430 program->Initialize(context_, is_using_bind_uniform_);
2432 return program.get();
2435 const GLRenderer::TextureProgramFlip* GLRenderer::GetTextureProgramFlip(
2436 TexCoordPrecision precision) {
2437 scoped_ptr<TextureProgramFlip> &program =
2438 (precision == TexCoordPrecisionHigh) ? texture_program_flip_highp_
2439 : texture_program_flip_;
2440 if (!program)
2441 program = make_scoped_ptr(new TextureProgramFlip(context_, precision));
2442 if (!program->initialized()) {
2443 TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize");
2444 program->Initialize(context_, is_using_bind_uniform_);
2446 return program.get();
2449 const GLRenderer::TextureIOSurfaceProgram*
2450 GLRenderer::GetTextureIOSurfaceProgram(TexCoordPrecision precision) {
2451 scoped_ptr<TextureIOSurfaceProgram> &program =
2452 (precision == TexCoordPrecisionHigh) ? texture_io_surface_program_highp_
2453 : texture_io_surface_program_;
2454 if (!program)
2455 program =
2456 make_scoped_ptr(new TextureIOSurfaceProgram(context_, precision));
2457 if (!program->initialized()) {
2458 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
2459 program->Initialize(context_, is_using_bind_uniform_);
2461 return program.get();
2464 const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram(
2465 TexCoordPrecision precision) {
2466 scoped_ptr<VideoYUVProgram> &program =
2467 (precision == TexCoordPrecisionHigh) ? video_yuv_program_highp_
2468 : video_yuv_program_;
2469 if (!program)
2470 program = make_scoped_ptr(new VideoYUVProgram(context_, precision));
2471 if (!program->initialized()) {
2472 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
2473 program->Initialize(context_, is_using_bind_uniform_);
2475 return program.get();
2478 const GLRenderer::VideoStreamTextureProgram*
2479 GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) {
2480 if (!Capabilities().using_egl_image)
2481 return NULL;
2482 scoped_ptr<VideoStreamTextureProgram> &program =
2483 (precision == TexCoordPrecisionHigh) ? video_stream_texture_program_highp_
2484 : video_stream_texture_program_;
2485 if (!program)
2486 program =
2487 make_scoped_ptr(new VideoStreamTextureProgram(context_, precision));
2488 if (!program->initialized()) {
2489 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
2490 program->Initialize(context_, is_using_bind_uniform_);
2492 return program.get();
2495 void GLRenderer::CleanupSharedObjects() {
2496 MakeContextCurrent();
2498 shared_geometry_.reset();
2500 if (tile_program_)
2501 tile_program_->Cleanup(context_);
2502 if (tile_program_opaque_)
2503 tile_program_opaque_->Cleanup(context_);
2504 if (tile_program_swizzle_)
2505 tile_program_swizzle_->Cleanup(context_);
2506 if (tile_program_swizzle_opaque_)
2507 tile_program_swizzle_opaque_->Cleanup(context_);
2508 if (tile_program_aa_)
2509 tile_program_aa_->Cleanup(context_);
2510 if (tile_program_swizzle_aa_)
2511 tile_program_swizzle_aa_->Cleanup(context_);
2512 if (tile_checkerboard_program_)
2513 tile_checkerboard_program_->Cleanup(context_);
2515 if (render_pass_mask_program_)
2516 render_pass_mask_program_->Cleanup(context_);
2517 if (render_pass_program_)
2518 render_pass_program_->Cleanup(context_);
2519 if (render_pass_mask_program_aa_)
2520 render_pass_mask_program_aa_->Cleanup(context_);
2521 if (render_pass_program_aa_)
2522 render_pass_program_aa_->Cleanup(context_);
2523 if (render_pass_color_matrix_program_)
2524 render_pass_color_matrix_program_->Cleanup(context_);
2525 if (render_pass_mask_color_matrix_program_aa_)
2526 render_pass_mask_color_matrix_program_aa_->Cleanup(context_);
2527 if (render_pass_color_matrix_program_aa_)
2528 render_pass_color_matrix_program_aa_->Cleanup(context_);
2529 if (render_pass_mask_color_matrix_program_)
2530 render_pass_mask_color_matrix_program_->Cleanup(context_);
2532 if (render_pass_mask_program_highp_)
2533 render_pass_mask_program_highp_->Cleanup(context_);
2534 if (render_pass_program_highp_)
2535 render_pass_program_highp_->Cleanup(context_);
2536 if (render_pass_mask_program_aa_highp_)
2537 render_pass_mask_program_aa_highp_->Cleanup(context_);
2538 if (render_pass_program_aa_highp_)
2539 render_pass_program_aa_highp_->Cleanup(context_);
2540 if (render_pass_color_matrix_program_highp_)
2541 render_pass_color_matrix_program_highp_->Cleanup(context_);
2542 if (render_pass_mask_color_matrix_program_aa_highp_)
2543 render_pass_mask_color_matrix_program_aa_highp_->Cleanup(context_);
2544 if (render_pass_color_matrix_program_aa_highp_)
2545 render_pass_color_matrix_program_aa_highp_->Cleanup(context_);
2546 if (render_pass_mask_color_matrix_program_highp_)
2547 render_pass_mask_color_matrix_program_highp_->Cleanup(context_);
2549 if (texture_program_)
2550 texture_program_->Cleanup(context_);
2551 if (texture_program_flip_)
2552 texture_program_flip_->Cleanup(context_);
2553 if (texture_io_surface_program_)
2554 texture_io_surface_program_->Cleanup(context_);
2556 if (texture_program_highp_)
2557 texture_program_highp_->Cleanup(context_);
2558 if (texture_program_flip_highp_)
2559 texture_program_flip_highp_->Cleanup(context_);
2560 if (texture_io_surface_program_highp_)
2561 texture_io_surface_program_highp_->Cleanup(context_);
2563 if (video_yuv_program_)
2564 video_yuv_program_->Cleanup(context_);
2565 if (video_stream_texture_program_)
2566 video_stream_texture_program_->Cleanup(context_);
2568 if (video_yuv_program_highp_)
2569 video_yuv_program_highp_->Cleanup(context_);
2570 if (video_stream_texture_program_highp_)
2571 video_stream_texture_program_highp_->Cleanup(context_);
2573 if (debug_border_program_)
2574 debug_border_program_->Cleanup(context_);
2575 if (solid_color_program_)
2576 solid_color_program_->Cleanup(context_);
2577 if (solid_color_program_aa_)
2578 solid_color_program_aa_->Cleanup(context_);
2580 if (offscreen_framebuffer_id_)
2581 GLC(context_, context_->deleteFramebuffer(offscreen_framebuffer_id_));
2583 if (on_demand_tile_raster_resource_id_)
2584 resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
2586 ReleaseRenderPassTextures();
2589 bool GLRenderer::IsContextLost() {
2590 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR);
2593 } // namespace cc