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