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

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: unittests fixed Created 7 years 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
« no previous file with comments | « cc/output/gl_renderer.h ('k') | cc/output/renderer_pixeltest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 558 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 // Flush the GL context so rendering results from this context are 569 // Flush the GL context so rendering results from this context are
570 // visible in the compositor's context. 570 // visible in the compositor's context.
571 offscreen_contexts->Context3d()->flush(); 571 offscreen_contexts->Context3d()->flush();
572 572
573 // Use the compositor's GL context again. 573 // Use the compositor's GL context again.
574 renderer->Context()->makeContextCurrent(); 574 renderer->Context()->makeContextCurrent();
575 575
576 return device.accessBitmap(false); 576 return device.accessBitmap(false);
577 } 577 }
578 578
579 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( 579 static SkBitmap ApplyBlendModeWithBackdrop(
580 GLRenderer* renderer,
581 ContextProvider* offscreen_contexts,
582 SkBitmap source_bitmap_with_filters,
583 ScopedResource* source_texture_resource,
584 ScopedResource* background_texture_resource,
585 SkXfermode::Mode blend_mode) {
586 if (!offscreen_contexts || !offscreen_contexts->GrContext())
587 return source_bitmap_with_filters;
588
589 DCHECK(background_texture_resource);
590 DCHECK(source_texture_resource);
591
592 gfx::Size source_size = source_texture_resource->size();
593 gfx::Size background_size = background_texture_resource->size();
594
595 DCHECK_LE(background_size.width(), source_size.width());
596 DCHECK_LE(background_size.height(), source_size.height());
597
598 int source_texture_with_filters_id;
599 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
600 if (source_bitmap_with_filters.getTexture()) {
601 DCHECK_EQ(source_size.width(), source_bitmap_with_filters.width());
602 DCHECK_EQ(source_size.height(), source_bitmap_with_filters.height());
603 GrTexture* texture =
604 reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture());
605 source_texture_with_filters_id = texture->getTextureHandle();
606 } else {
607 lock.reset(new ResourceProvider::ScopedReadLockGL(
608 renderer->resource_provider(), source_texture_resource->id()));
609 source_texture_with_filters_id = lock->texture_id();
610 }
611
612 ResourceProvider::ScopedReadLockGL lock_background(
613 renderer->resource_provider(), background_texture_resource->id());
614
615 // Flush the compositor context to ensure that textures there are available
616 // in the shared context. Do this after locking/creating the compositor
617 // texture.
618 renderer->resource_provider()->Flush();
619
620 // Make sure skia uses the correct GL context.
621 offscreen_contexts->Context3d()->makeContextCurrent();
622
623 // Wrap the source texture in a Ganesh platform texture.
624 GrBackendTextureDesc backend_texture_description;
625 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
626 backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
627
628 backend_texture_description.fWidth = source_size.width();
629 backend_texture_description.fHeight = source_size.height();
630 backend_texture_description.fTextureHandle = source_texture_with_filters_id;
631 skia::RefPtr<GrTexture> source_texture =
632 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
633 backend_texture_description));
634
635 backend_texture_description.fWidth = background_size.width();
636 backend_texture_description.fHeight = background_size.height();
637 backend_texture_description.fTextureHandle = lock_background.texture_id();
638 skia::RefPtr<GrTexture> background_texture =
639 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
640 backend_texture_description));
641
642 // Place the platform texture inside an SkBitmap.
643 SkBitmap source;
644 source.setConfig(
645 SkBitmap::kARGB_8888_Config, source_size.width(), source_size.height());
646 skia::RefPtr<SkGrPixelRef> source_pixel_ref =
647 skia::AdoptRef(new SkGrPixelRef(source_texture.get()));
648 source.setPixelRef(source_pixel_ref.get());
649
650 SkBitmap background;
651 background.setConfig(SkBitmap::kARGB_8888_Config,
652 background_size.width(),
653 background_size.height());
654 skia::RefPtr<SkGrPixelRef> background_pixel_ref =
655 skia::AdoptRef(new SkGrPixelRef(background_texture.get()));
656 background.setPixelRef(background_pixel_ref.get());
657
658 // Create a scratch texture for backing store.
659 GrTextureDesc desc;
660 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
661 desc.fSampleCnt = 0;
662 desc.fWidth = source.width();
663 desc.fHeight = source.height();
664 desc.fConfig = kSkia8888_GrPixelConfig;
665 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
666 GrAutoScratchTexture scratch_texture(
667 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
668 skia::RefPtr<GrTexture> backing_store =
669 skia::AdoptRef(scratch_texture.detach());
670
671 // Create a device and canvas using that backing store.
672 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
673 SkCanvas canvas(&device);
674
675 // Draw the source bitmap through the filter to the canvas.
676 canvas.clear(SK_ColorTRANSPARENT);
677 canvas.drawSprite(background, 0, 0);
678 SkPaint paint;
679 paint.setXfermodeMode(blend_mode);
680 canvas.drawSprite(source, 0, 0, &paint);
681
682 // Flush skia context so that all the rendered stuff appears on the
683 // texture.
684 offscreen_contexts->GrContext()->flush();
685
686 // Flush the GL context so rendering results from this context are
687 // visible in the compositor's context.
688 offscreen_contexts->Context3d()->flush();
689
690 // Use the compositor's GL context again.
691 renderer->Context()->makeContextCurrent();
692
693 return device.accessBitmap(false);
694 }
695
696 scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
580 DrawingFrame* frame, 697 DrawingFrame* frame,
581 const RenderPassDrawQuad* quad, 698 const RenderPassDrawQuad* quad,
582 const gfx::Transform& contents_device_transform, 699 const gfx::Transform& contents_device_transform,
583 const gfx::Transform& contents_device_transform_inverse) { 700 const gfx::Transform& contents_device_transform_inverse,
701 bool* background_changed) {
584 // This method draws a background filter, which applies a filter to any pixels 702 // This method draws a background filter, which applies a filter to any pixels
585 // behind the quad and seen through its background. The algorithm works as 703 // behind the quad and seen through its background. The algorithm works as
586 // follows: 704 // follows:
587 // 1. Compute a bounding box around the pixels that will be visible through 705 // 1. Compute a bounding box around the pixels that will be visible through
588 // the quad. 706 // the quad.
589 // 2. Read the pixels in the bounding box into a buffer R. 707 // 2. Read the pixels in the bounding box into a buffer R.
590 // 3. Apply the background filter to R, so that it is applied in the pixels' 708 // 3. Apply the background filter to R, so that it is applied in the pixels'
591 // coordinate space. 709 // coordinate space.
592 // 4. Apply the quad's inverse transform to map the pixels in R into the 710 // 4. Apply the quad's inverse transform to map the pixels in R into the
593 // quad's content space. This implicitly clips R by the content bounds of the 711 // quad's content space. This implicitly clips R by the content bounds of the
594 // quad since the destination texture has bounds matching the quad's content. 712 // quad since the destination texture has bounds matching the quad's content.
595 // 5. Draw the background texture for the contents using the same transform as 713 // 5. Draw the background texture for the contents using the same transform as
596 // used to draw the contents itself. This is done without blending to replace 714 // used to draw the contents itself. This is done without blending to replace
597 // the current background pixels with the new filtered background. 715 // the current background pixels with the new filtered background.
598 // 6. Draw the contents of the quad over drop of the new background with 716 // 6. Draw the contents of the quad over drop of the new background with
599 // blending, as per usual. The filtered background pixels will show through 717 // blending, as per usual. The filtered background pixels will show through
600 // any non-opaque pixels in this draws. 718 // any non-opaque pixels in this draws.
601 // 719 //
602 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5. 720 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
603 721
604 // TODO(danakj): When this algorithm changes, update 722 // TODO(danakj): When this algorithm changes, update
605 // LayerTreeHost::PrioritizeTextures() accordingly. 723 // LayerTreeHost::PrioritizeTextures() accordingly.
606 724
607 // TODO(danakj): We only allow background filters on an opaque render surface 725 // TODO(danakj): We only allow background filters on an opaque render surface
608 // because other surfaces may contain translucent pixels, and the contents 726 // because other surfaces may contain translucent pixels, and the contents
609 // behind those translucent pixels wouldn't have the filter applied. 727 // behind those translucent pixels wouldn't have the filter applied.
610 if (frame->current_render_pass->has_transparent_background) 728 bool apply_background_filters =
611 return scoped_ptr<ScopedResource>(); 729 !frame->current_render_pass->has_transparent_background;
612 DCHECK(!frame->current_texture); 730 DCHECK(!frame->current_texture);
613 731
614 // TODO(ajuma): Add support for reference filters once 732 // TODO(ajuma): Add support for reference filters once
615 // FilterOperations::GetOutsets supports reference filters. 733 // FilterOperations::GetOutsets supports reference filters.
616 if (quad->background_filters.HasReferenceFilter()) 734 if (apply_background_filters && quad->background_filters.HasReferenceFilter())
617 return scoped_ptr<ScopedResource>(); 735 apply_background_filters = false;
618 736
619 // TODO(danakj): Do a single readback for both the surface and replica and 737 // TODO(danakj): Do a single readback for both the surface and replica and
620 // cache the filtered results (once filter textures are not reused). 738 // cache the filtered results (once filter textures are not reused).
621 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( 739 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
622 contents_device_transform, SharedGeometryQuad().BoundingBox())); 740 contents_device_transform, SharedGeometryQuad().BoundingBox()));
623 741
624 int top, right, bottom, left; 742 int top, right, bottom, left;
625 quad->background_filters.GetOutsets(&top, &right, &bottom, &left); 743 quad->background_filters.GetOutsets(&top, &right, &bottom, &left);
626 window_rect.Inset(-left, -top, -right, -bottom); 744 window_rect.Inset(-left, -top, -right, -bottom);
627 745
(...skipping 14 matching lines...) Expand all
642 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, 760 ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
643 device_background_texture->id()); 761 device_background_texture->id());
644 GetFramebufferTexture(lock.texture_id(), 762 GetFramebufferTexture(lock.texture_id(),
645 device_background_texture->format(), 763 device_background_texture->format(),
646 window_rect); 764 window_rect);
647 } 765 }
648 766
649 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( 767 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
650 quad->background_filters, device_background_texture->size()); 768 quad->background_filters, device_background_texture->size());
651 769
652 SkBitmap filtered_device_background = 770 SkBitmap filtered_device_background;
653 ApplyImageFilter(this, 771 if (apply_background_filters) {
654 frame->offscreen_context_provider, 772 filtered_device_background =
655 quad->rect.origin(), 773 ApplyImageFilter(this,
656 filter.get(), 774 frame->offscreen_context_provider,
657 device_background_texture.get()); 775 quad->rect.origin(),
658 if (!filtered_device_background.getTexture()) 776 filter.get(),
659 return scoped_ptr<ScopedResource>(); 777 device_background_texture.get());
778 }
779 *background_changed = (filtered_device_background.getTexture() != NULL);
660 780
661 GrTexture* texture = 781 int filtered_device_background_texture_id = 0;
662 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); 782 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
663 int filtered_device_background_texture_id = texture->getTextureHandle(); 783 if (filtered_device_background.getTexture()) {
784 GrTexture* texture =
785 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
786 filtered_device_background_texture_id = texture->getTextureHandle();
787 } else {
788 lock.reset(new ResourceProvider::ScopedReadLockGL(
789 resource_provider_, device_background_texture->id()));
790 filtered_device_background_texture_id = lock->texture_id();
791 }
664 792
665 scoped_ptr<ScopedResource> background_texture = 793 scoped_ptr<ScopedResource> background_texture =
666 ScopedResource::create(resource_provider_); 794 ScopedResource::create(resource_provider_);
667 if (!background_texture->Allocate(quad->rect.size(), 795 if (!background_texture->Allocate(quad->rect.size(),
668 ResourceProvider::TextureUsageFramebuffer, 796 ResourceProvider::TextureUsageFramebuffer,
669 RGBA_8888)) 797 RGBA_8888))
670 return scoped_ptr<ScopedResource>(); 798 return scoped_ptr<ScopedResource>();
671 799
672 const RenderPass* target_render_pass = frame->current_render_pass; 800 const RenderPass* target_render_pass = frame->current_render_pass;
673 bool using_background_texture = 801 bool using_background_texture =
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 gfx::Transform contents_device_transform = 852 gfx::Transform contents_device_transform =
725 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; 853 frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
726 contents_device_transform.FlattenTo2d(); 854 contents_device_transform.FlattenTo2d();
727 855
728 // Can only draw surface if device matrix is invertible. 856 // Can only draw surface if device matrix is invertible.
729 gfx::Transform contents_device_transform_inverse( 857 gfx::Transform contents_device_transform_inverse(
730 gfx::Transform::kSkipInitialization); 858 gfx::Transform::kSkipInitialization);
731 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) 859 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
732 return; 860 return;
733 861
862 bool need_background_texture =
863 quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode ||
864 !quad->background_filters.IsEmpty();
865 bool background_changed = false;
734 scoped_ptr<ScopedResource> background_texture; 866 scoped_ptr<ScopedResource> background_texture;
735 if (!quad->background_filters.IsEmpty()) { 867 if (need_background_texture) {
736 // The pixels from the filtered background should completely replace the 868 // The pixels from the filtered background should completely replace the
737 // current pixel values. 869 // current pixel values.
738 bool disable_blending = blend_enabled(); 870 bool disable_blending = blend_enabled();
739 if (disable_blending) 871 if (disable_blending)
740 SetBlendEnabled(false); 872 SetBlendEnabled(false);
741 873
742 background_texture = DrawBackgroundFilters( 874 background_texture =
743 frame, 875 GetBackgroundWithFilters(frame,
744 quad, 876 quad,
745 contents_device_transform, 877 contents_device_transform,
746 contents_device_transform_inverse); 878 contents_device_transform_inverse,
879 &background_changed);
747 880
748 if (disable_blending) 881 if (disable_blending)
749 SetBlendEnabled(true); 882 SetBlendEnabled(true);
750 } 883 }
751 884
752 // TODO(senorblanco): Cache this value so that we don't have to do it for both 885 // TODO(senorblanco): Cache this value so that we don't have to do it for both
753 // the surface and its replica. Apply filters to the contents texture. 886 // the surface and its replica. Apply filters to the contents texture.
754 SkBitmap filter_bitmap; 887 SkBitmap filter_bitmap;
755 SkScalar color_matrix[20]; 888 SkScalar color_matrix[20];
756 bool use_color_matrix = false; 889 bool use_color_matrix = false;
(...skipping 18 matching lines...) Expand all
775 } else { 908 } else {
776 filter_bitmap = ApplyImageFilter(this, 909 filter_bitmap = ApplyImageFilter(this,
777 frame->offscreen_context_provider, 910 frame->offscreen_context_provider,
778 quad->rect.origin(), 911 quad->rect.origin(),
779 filter.get(), 912 filter.get(),
780 contents_texture); 913 contents_texture);
781 } 914 }
782 } 915 }
783 } 916 }
784 917
785 // Draw the background texture if there is one. 918 if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode &&
786 if (background_texture) { 919 background_texture) {
920 filter_bitmap =
921 ApplyBlendModeWithBackdrop(this,
922 frame->offscreen_context_provider,
923 filter_bitmap,
924 contents_texture,
925 background_texture.get(),
926 quad->shared_quad_state->blend_mode);
927 }
928
929 // Draw the background texture if it has some filters applied.
930 if (background_texture && background_changed) {
787 DCHECK(background_texture->size() == quad->rect.size()); 931 DCHECK(background_texture->size() == quad->rect.size());
788 ResourceProvider::ScopedReadLockGL lock(resource_provider_, 932 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
789 background_texture->id()); 933 background_texture->id());
790 934
791 // The background_texture is oriented the same as the frame buffer. The 935 // The background_texture is oriented the same as the frame buffer. The
792 // transform we are copying with has a vertical flip, so flip the contents 936 // transform we are copying with has a vertical flip, so flip the contents
793 // in the shader to maintain orientation 937 // in the shader to maintain orientation
794 bool flip_vertically = true; 938 bool flip_vertically = true;
795 939
796 CopyTextureToFramebuffer(frame, 940 CopyTextureToFramebuffer(frame,
(...skipping 2214 matching lines...) Expand 10 before | Expand all | Expand 10 after
3011 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas 3155 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas
3012 // implementation. 3156 // implementation.
3013 return gr_context_ && context_->getContextAttributes().stencil; 3157 return gr_context_ && context_->getContextAttributes().stencil;
3014 } 3158 }
3015 3159
3016 bool GLRenderer::IsContextLost() { 3160 bool GLRenderer::IsContextLost() {
3017 return output_surface_->context_provider()->IsContextLost(); 3161 return output_surface_->context_provider()->IsContextLost();
3018 } 3162 }
3019 3163
3020 } // namespace cc 3164 } // namespace cc
OLDNEW
« no previous file with comments | « cc/output/gl_renderer.h ('k') | cc/output/renderer_pixeltest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698