Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(501)

Side by Side Diff: cc/output/gl_renderer.cc

Issue 23455060: mix-blend-mode implementation for accelerated layers (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/output/gl_renderer.h" 5 #include "cc/output/gl_renderer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 // Flush the GL context so rendering results from this context are 558 // Flush the GL context so rendering results from this context are
559 // visible in the compositor's context. 559 // visible in the compositor's context.
560 offscreen_contexts->Context3d()->flush(); 560 offscreen_contexts->Context3d()->flush();
561 561
562 // Use the compositor's GL context again. 562 // Use the compositor's GL context again.
563 renderer->Context()->makeContextCurrent(); 563 renderer->Context()->makeContextCurrent();
564 564
565 return device.accessBitmap(false); 565 return device.accessBitmap(false);
566 } 566 }
567 567
568 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( 568 static SkBitmap ApplyBlendModeWithBackdrop(
569 GLRenderer* renderer,
570 ContextProvider* offscreen_contexts,
571 SkBitmap source_bitmap_with_filters,
572 ScopedResource* source_texture_resource,
573 ScopedResource* background_texture_resource,
574 SkXfermode::Mode blendMode) {
575 if (!offscreen_contexts || !offscreen_contexts->GrContext())
576 return source_bitmap_with_filters;
577
578 DCHECK(background_texture_resource);
579 DCHECK(source_texture_resource);
580
581 gfx::Size source_size = source_texture_resource->size();
582 gfx::Size background_size = background_texture_resource->size();
583
584 DCHECK_LE(background_size.width(), source_size.width());
585 DCHECK_LE(background_size.height(), source_size.height());
586
587 int source_texture_with_filters_id;
588 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
589 if (source_bitmap_with_filters.getTexture()) {
590 DCHECK_EQ(source_size.width(), source_bitmap_with_filters.width());
591 DCHECK_EQ(source_size.height(), source_bitmap_with_filters.height());
592 GrTexture* texture =
593 reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture());
594 source_texture_with_filters_id = texture->getTextureHandle();
595 } else {
596 lock.reset(new ResourceProvider::ScopedReadLockGL(
597 renderer->resource_provider(), source_texture_resource->id()));
598 source_texture_with_filters_id = lock->texture_id();
599 }
600
601 ResourceProvider::ScopedReadLockGL lock_background(
602 renderer->resource_provider(), background_texture_resource->id());
603
604 // Flush the compositor context to ensure that textures there are available
605 // in the shared context. Do this after locking/creating the compositor
606 // texture.
607 renderer->resource_provider()->Flush();
608
609 // Make sure skia uses the correct GL context.
610 offscreen_contexts->Context3d()->makeContextCurrent();
611
612 // Wrap the source texture in a Ganesh platform texture.
613 GrBackendTextureDesc backend_texture_description;
614 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
615 backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
616
617 backend_texture_description.fWidth = source_size.width();
618 backend_texture_description.fHeight = source_size.height();
619 backend_texture_description.fTextureHandle = source_texture_with_filters_id;
620 skia::RefPtr<GrTexture> source_texture =
621 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
622 backend_texture_description));
623
624 backend_texture_description.fWidth = background_size.width();
625 backend_texture_description.fHeight = background_size.height();
626 backend_texture_description.fTextureHandle = lock_background.texture_id();
627 skia::RefPtr<GrTexture> background_texture =
628 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
629 backend_texture_description));
630
631 // Place the platform texture inside an SkBitmap.
632 SkBitmap source;
633 source.setConfig(
634 SkBitmap::kARGB_8888_Config, source_size.width(), source_size.height());
635 skia::RefPtr<SkGrPixelRef> source_pixel_ref =
636 skia::AdoptRef(new SkGrPixelRef(source_texture.get()));
637 source.setPixelRef(source_pixel_ref.get());
638
639 SkBitmap background;
640 background.setConfig(SkBitmap::kARGB_8888_Config,
641 background_size.width(),
642 background_size.height());
643 skia::RefPtr<SkGrPixelRef> background_pixel_ref =
644 skia::AdoptRef(new SkGrPixelRef(background_texture.get()));
645 background.setPixelRef(background_pixel_ref.get());
646
647 // Create a scratch texture for backing store.
648 GrTextureDesc desc;
649 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
650 desc.fSampleCnt = 0;
651 desc.fWidth = source.width();
652 desc.fHeight = source.height();
653 desc.fConfig = kSkia8888_GrPixelConfig;
654 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
655 GrAutoScratchTexture scratch_texture(
656 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
657 skia::RefPtr<GrTexture> backing_store =
658 skia::AdoptRef(scratch_texture.detach());
659
660 // Create a device and canvas using that backing store.
661 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
662 SkCanvas canvas(&device);
663
664 // Draw the source bitmap through the filter to the canvas.
665 canvas.clear(SK_ColorTRANSPARENT);
666 canvas.drawSprite(background, 0, 0);
667 SkPaint paint;
668 paint.setXfermodeMode(blendMode);
669 canvas.drawSprite(source, 0, 0, &paint);
670
671 // Flush skia context so that all the rendered stuff appears on the
672 // texture.
673 offscreen_contexts->GrContext()->flush();
674
675 // Flush the GL context so rendering results from this context are
676 // visible in the compositor's context.
677 offscreen_contexts->Context3d()->flush();
678
679 // Use the compositor's GL context again.
680 renderer->Context()->makeContextCurrent();
681
682 return device.accessBitmap(false);
683 }
684
685 scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
569 DrawingFrame* frame, 686 DrawingFrame* frame,
570 const RenderPassDrawQuad* quad, 687 const RenderPassDrawQuad* quad,
571 const gfx::Transform& contents_device_transform, 688 const gfx::Transform& contents_device_transform,
572 const gfx::Transform& contents_device_transform_inverse) { 689 const gfx::Transform& contents_device_transform_inverse,
690 bool* background_changed) {
573 // This method draws a background filter, which applies a filter to any pixels 691 // This method draws a background filter, which applies a filter to any pixels
574 // behind the quad and seen through its background. The algorithm works as 692 // behind the quad and seen through its background. The algorithm works as
575 // follows: 693 // follows:
576 // 1. Compute a bounding box around the pixels that will be visible through 694 // 1. Compute a bounding box around the pixels that will be visible through
577 // the quad. 695 // the quad.
578 // 2. Read the pixels in the bounding box into a buffer R. 696 // 2. Read the pixels in the bounding box into a buffer R.
579 // 3. Apply the background filter to R, so that it is applied in the pixels' 697 // 3. Apply the background filter to R, so that it is applied in the pixels'
580 // coordinate space. 698 // coordinate space.
581 // 4. Apply the quad's inverse transform to map the pixels in R into the 699 // 4. Apply the quad's inverse transform to map the pixels in R into the
582 // quad's content space. This implicitly clips R by the content bounds of the 700 // quad's content space. This implicitly clips R by the content bounds of the
583 // quad since the destination texture has bounds matching the quad's content. 701 // quad since the destination texture has bounds matching the quad's content.
584 // 5. Draw the background texture for the contents using the same transform as 702 // 5. Draw the background texture for the contents using the same transform as
585 // used to draw the contents itself. This is done without blending to replace 703 // used to draw the contents itself. This is done without blending to replace
586 // the current background pixels with the new filtered background. 704 // the current background pixels with the new filtered background.
587 // 6. Draw the contents of the quad over drop of the new background with 705 // 6. Draw the contents of the quad over drop of the new background with
588 // blending, as per usual. The filtered background pixels will show through 706 // blending, as per usual. The filtered background pixels will show through
589 // any non-opaque pixels in this draws. 707 // any non-opaque pixels in this draws.
590 // 708 //
591 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5. 709 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
592 710
593 // TODO(danakj): When this algorithm changes, update 711 // TODO(danakj): When this algorithm changes, update
594 // LayerTreeHost::PrioritizeTextures() accordingly. 712 // LayerTreeHost::PrioritizeTextures() accordingly.
595 713
596 // TODO(danakj): We only allow background filters on an opaque render surface 714 // TODO(danakj): We only allow background filters on an opaque render surface
597 // because other surfaces may contain translucent pixels, and the contents 715 // because other surfaces may contain translucent pixels, and the contents
598 // behind those translucent pixels wouldn't have the filter applied. 716 // behind those translucent pixels wouldn't have the filter applied.
599 if (frame->current_render_pass->has_transparent_background) 717 bool apply_background_filters =
600 return scoped_ptr<ScopedResource>(); 718 !frame->current_render_pass->has_transparent_background;
601 DCHECK(!frame->current_texture); 719 DCHECK(!frame->current_texture);
602 720
603 // TODO(ajuma): Add support for reference filters once 721 // TODO(ajuma): Add support for reference filters once
604 // FilterOperations::GetOutsets supports reference filters. 722 // FilterOperations::GetOutsets supports reference filters.
605 if (quad->background_filters.HasReferenceFilter()) 723 if (apply_background_filters && quad->background_filters.HasReferenceFilter())
606 return scoped_ptr<ScopedResource>(); 724 apply_background_filters = false;
607 725
608 // TODO(danakj): Do a single readback for both the surface and replica and 726 // TODO(danakj): Do a single readback for both the surface and replica and
609 // cache the filtered results (once filter textures are not reused). 727 // cache the filtered results (once filter textures are not reused).
610 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( 728 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
611 contents_device_transform, SharedGeometryQuad().BoundingBox())); 729 contents_device_transform, SharedGeometryQuad().BoundingBox()));
612 730
613 int top, right, bottom, left; 731 int top, right, bottom, left;
614 quad->background_filters.GetOutsets(&top, &right, &bottom, &left); 732 quad->background_filters.GetOutsets(&top, &right, &bottom, &left);
615 window_rect.Inset(-left, -top, -right, -bottom); 733 window_rect.Inset(-left, -top, -right, -bottom);
616 734
617 window_rect.Intersect( 735 window_rect.Intersect(
618 MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect)); 736 MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
619 737
620 scoped_ptr<ScopedResource> device_background_texture = 738 scoped_ptr<ScopedResource> device_background_texture =
621 ScopedResource::create(resource_provider_); 739 ScopedResource::create(resource_provider_);
622 if (!device_background_texture->Allocate(window_rect.size(), 740 if (!device_background_texture->Allocate(window_rect.size(),
623 ResourceProvider::TextureUsageAny, 741 ResourceProvider::TextureUsageAny,
624 RGBA_8888)) { 742 RGBA_8888)) {
625 return scoped_ptr<ScopedResource>(); 743 return scoped_ptr<ScopedResource>();
626 } else { 744 } else {
627 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, 745 ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
628 device_background_texture->id()); 746 device_background_texture->id());
629 GetFramebufferTexture(lock.texture_id(), 747 GetFramebufferTextureSubImage(lock.texture_id(), window_rect);
630 device_background_texture->format(),
631 window_rect);
632 } 748 }
633 749
750 int filtered_device_background_texture_id = 0;
634 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( 751 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
635 quad->background_filters, device_background_texture->size()); 752 quad->background_filters, device_background_texture->size());
636 753
637 SkBitmap filtered_device_background = 754 SkBitmap filtered_device_background;
638 ApplyImageFilter(this, 755 if (apply_background_filters)
639 frame->offscreen_context_provider, 756 filtered_device_background =
640 quad->rect.origin(), 757 ApplyImageFilter(this,
641 filter.get(), 758 frame->offscreen_context_provider,
642 device_background_texture.get()); 759 quad->rect.origin(),
643 if (!filtered_device_background.getTexture()) 760 filter.get(),
644 return scoped_ptr<ScopedResource>(); 761 device_background_texture.get());
762 if (background_changed)
763 *background_changed = (filtered_device_background.getTexture() != NULL);
645 764
646 GrTexture* texture = 765 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
647 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); 766 if (filtered_device_background.getTexture()) {
648 int filtered_device_background_texture_id = texture->getTextureHandle(); 767 GrTexture* texture =
768 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
769 filtered_device_background_texture_id = texture->getTextureHandle();
770 } else {
771 lock.reset(new ResourceProvider::ScopedReadLockGL(
772 resource_provider_, device_background_texture->id()));
773 filtered_device_background_texture_id = lock->texture_id();
774 }
649 775
650 scoped_ptr<ScopedResource> background_texture = 776 scoped_ptr<ScopedResource> background_texture =
651 ScopedResource::create(resource_provider_); 777 ScopedResource::create(resource_provider_);
652 if (!background_texture->Allocate(quad->rect.size(), 778 if (!background_texture->Allocate(quad->rect.size(),
653 ResourceProvider::TextureUsageFramebuffer, 779 ResourceProvider::TextureUsageFramebuffer,
654 RGBA_8888)) 780 RGBA_8888))
655 return scoped_ptr<ScopedResource>(); 781 return scoped_ptr<ScopedResource>();
656 782
657 const RenderPass* target_render_pass = frame->current_render_pass; 783 const RenderPass* target_render_pass = frame->current_render_pass;
658 bool using_background_texture = 784 bool using_background_texture =
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 gfx::Transform contents_device_transform = 835 gfx::Transform contents_device_transform =
710 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; 836 frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
711 contents_device_transform.FlattenTo2d(); 837 contents_device_transform.FlattenTo2d();
712 838
713 // Can only draw surface if device matrix is invertible. 839 // Can only draw surface if device matrix is invertible.
714 gfx::Transform contents_device_transform_inverse( 840 gfx::Transform contents_device_transform_inverse(
715 gfx::Transform::kSkipInitialization); 841 gfx::Transform::kSkipInitialization);
716 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) 842 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
717 return; 843 return;
718 844
845 bool apply_blend_mode =
846 quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode;
847 bool background_changed = false;
719 scoped_ptr<ScopedResource> background_texture; 848 scoped_ptr<ScopedResource> background_texture;
720 if (!quad->background_filters.IsEmpty()) { 849 if (!quad->background_filters.IsEmpty() || apply_blend_mode) {
721 // The pixels from the filtered background should completely replace the 850 // The pixels from the filtered background should completely replace the
722 // current pixel values. 851 // current pixel values.
723 bool disable_blending = blend_enabled(); 852 bool disable_blending = blend_enabled();
724 if (disable_blending) 853 if (disable_blending)
725 SetBlendEnabled(false); 854 SetBlendEnabled(false);
726 855
727 background_texture = DrawBackgroundFilters( 856 background_texture =
728 frame, 857 GetBackgroundWithFilters(frame,
729 quad, 858 quad,
730 contents_device_transform, 859 contents_device_transform,
731 contents_device_transform_inverse); 860 contents_device_transform_inverse,
861 &background_changed);
732 862
733 if (disable_blending) 863 if (disable_blending)
734 SetBlendEnabled(true); 864 SetBlendEnabled(true);
735 } 865 }
736 866
737 // TODO(senorblanco): Cache this value so that we don't have to do it for both 867 // TODO(senorblanco): Cache this value so that we don't have to do it for both
738 // the surface and its replica. Apply filters to the contents texture. 868 // the surface and its replica. Apply filters to the contents texture.
739 SkBitmap filter_bitmap; 869 SkBitmap filter_bitmap;
740 SkScalar color_matrix[20]; 870 SkScalar color_matrix[20];
741 bool use_color_matrix = false; 871 bool use_color_matrix = false;
(...skipping 18 matching lines...) Expand all
760 } else { 890 } else {
761 filter_bitmap = ApplyImageFilter(this, 891 filter_bitmap = ApplyImageFilter(this,
762 frame->offscreen_context_provider, 892 frame->offscreen_context_provider,
763 quad->rect.origin(), 893 quad->rect.origin(),
764 filter.get(), 894 filter.get(),
765 contents_texture); 895 contents_texture);
766 } 896 }
767 } 897 }
768 } 898 }
769 899
900 if (background_texture && apply_blend_mode) {
901 filter_bitmap =
902 ApplyBlendModeWithBackdrop(this,
903 frame->offscreen_context_provider,
904 filter_bitmap,
905 contents_texture,
906 background_texture.get(),
907 quad->shared_quad_state->blend_mode);
908 }
909
770 // Draw the background texture if there is one. 910 // Draw the background texture if there is one.
771 if (background_texture) { 911 if (background_texture && background_changed) {
772 DCHECK(background_texture->size() == quad->rect.size()); 912 DCHECK(background_texture->size() == quad->rect.size());
773 ResourceProvider::ScopedReadLockGL lock(resource_provider_, 913 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
774 background_texture->id()); 914 background_texture->id());
775 915
776 // The background_texture is oriented the same as the frame buffer. The 916 // The background_texture is oriented the same as the frame buffer. The
777 // transform we are copying with has a vertical flip, so flip the contents 917 // transform we are copying with has a vertical flip, so flip the contents
778 // in the shader to maintain orientation 918 // in the shader to maintain orientation
779 bool flip_vertically = true; 919 bool flip_vertically = true;
780 920
781 CopyTextureToFramebuffer(frame, 921 CopyTextureToFramebuffer(frame,
(...skipping 1627 matching lines...) Expand 10 before | Expand all | Expand 10 after
2409 scoped_ptr<SkAutoLockPixels> lock, 2549 scoped_ptr<SkAutoLockPixels> lock,
2410 scoped_ptr<CopyOutputRequest> request, 2550 scoped_ptr<CopyOutputRequest> request,
2411 bool success) { 2551 bool success) {
2412 DCHECK(request->force_bitmap_result()); 2552 DCHECK(request->force_bitmap_result());
2413 2553
2414 lock.reset(); 2554 lock.reset();
2415 if (success) 2555 if (success)
2416 request->SendBitmapResult(bitmap.Pass()); 2556 request->SendBitmapResult(bitmap.Pass());
2417 } 2557 }
2418 2558
2559 void GLRenderer::GetFramebufferTextureSubImage(unsigned texture_id,
2560 gfx::Rect window_rect) {
2561 DCHECK(texture_id);
2562 DCHECK_GE(window_rect.x(), 0);
2563 DCHECK_GE(window_rect.y(), 0);
2564 DCHECK_LE(window_rect.right(), current_surface_size_.width());
2565 DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
2566
2567 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2568 GLC(context_,
2569 context_->copyTexSubImage2D(GL_TEXTURE_2D,
2570 0,
2571 0,
2572 0,
2573 window_rect.x(),
2574 window_rect.y(),
2575 window_rect.width(),
2576 window_rect.height()));
2577 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2578 }
2579
2419 void GLRenderer::GetFramebufferTexture( 2580 void GLRenderer::GetFramebufferTexture(
2420 unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) { 2581 unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) {
2421 DCHECK(texture_id); 2582 DCHECK(texture_id);
2422 DCHECK_GE(window_rect.x(), 0); 2583 DCHECK_GE(window_rect.x(), 0);
2423 DCHECK_GE(window_rect.y(), 0); 2584 DCHECK_GE(window_rect.y(), 0);
2424 DCHECK_LE(window_rect.right(), current_surface_size_.width()); 2585 DCHECK_LE(window_rect.right(), current_surface_size_.width());
2425 DCHECK_LE(window_rect.bottom(), current_surface_size_.height()); 2586 DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
2426 2587
2427 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id)); 2588 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2428 GLC(context_, 2589 GLC(context_,
(...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after
3088 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas 3249 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas
3089 // implementation. 3250 // implementation.
3090 return gr_context_ && context_->getContextAttributes().stencil; 3251 return gr_context_ && context_->getContextAttributes().stencil;
3091 } 3252 }
3092 3253
3093 bool GLRenderer::IsContextLost() { 3254 bool GLRenderer::IsContextLost() {
3094 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR); 3255 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR);
3095 } 3256 }
3096 3257
3097 } // namespace cc 3258 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698