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

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: removed src/webkit/renderer/compositor_bindings 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 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 // Flush the GL context so rendering results from this context are 555 // Flush the GL context so rendering results from this context are
556 // visible in the compositor's context. 556 // visible in the compositor's context.
557 offscreen_contexts->Context3d()->flush(); 557 offscreen_contexts->Context3d()->flush();
558 558
559 // Use the compositor's GL context again. 559 // Use the compositor's GL context again.
560 renderer->Context()->makeContextCurrent(); 560 renderer->Context()->makeContextCurrent();
561 561
562 return device.accessBitmap(false); 562 return device.accessBitmap(false);
563 } 563 }
564 564
565 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( 565 static SkBitmap ApplyBlendModeWithBackdrop(
566 GLRenderer* renderer,
567 ContextProvider* offscreen_contexts,
568 SkBitmap source_bitmap_with_filters,
569 ScopedResource* source_texture_resource,
570 ScopedResource* background_texture_resource,
571 SkXfermode::Mode blend_mode) {
572 if (!offscreen_contexts || !offscreen_contexts->GrContext())
573 return source_bitmap_with_filters;
574
575 DCHECK(background_texture_resource);
576 DCHECK(source_texture_resource);
577
578 gfx::Size source_size = source_texture_resource->size();
579 gfx::Size background_size = background_texture_resource->size();
580
581 DCHECK_LE(background_size.width(), source_size.width());
582 DCHECK_LE(background_size.height(), source_size.height());
583
584 int source_texture_with_filters_id;
585 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
586 if (source_bitmap_with_filters.getTexture()) {
587 DCHECK_EQ(source_size.width(), source_bitmap_with_filters.width());
588 DCHECK_EQ(source_size.height(), source_bitmap_with_filters.height());
589 GrTexture* texture =
590 reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture());
591 source_texture_with_filters_id = texture->getTextureHandle();
592 } else {
593 lock.reset(new ResourceProvider::ScopedReadLockGL(
594 renderer->resource_provider(), source_texture_resource->id()));
595 source_texture_with_filters_id = lock->texture_id();
596 }
597
598 ResourceProvider::ScopedReadLockGL lock_background(
599 renderer->resource_provider(), background_texture_resource->id());
600
601 // Flush the compositor context to ensure that textures there are available
602 // in the shared context. Do this after locking/creating the compositor
603 // texture.
604 renderer->resource_provider()->Flush();
605
606 // Make sure skia uses the correct GL context.
607 offscreen_contexts->Context3d()->makeContextCurrent();
608
609 // Wrap the source texture in a Ganesh platform texture.
610 GrBackendTextureDesc backend_texture_description;
611 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
612 backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
613
614 backend_texture_description.fWidth = source_size.width();
615 backend_texture_description.fHeight = source_size.height();
616 backend_texture_description.fTextureHandle = source_texture_with_filters_id;
617 skia::RefPtr<GrTexture> source_texture =
618 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
619 backend_texture_description));
620
621 backend_texture_description.fWidth = background_size.width();
622 backend_texture_description.fHeight = background_size.height();
623 backend_texture_description.fTextureHandle = lock_background.texture_id();
624 skia::RefPtr<GrTexture> background_texture =
625 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
626 backend_texture_description));
627
628 // Place the platform texture inside an SkBitmap.
629 SkBitmap source;
630 source.setConfig(
631 SkBitmap::kARGB_8888_Config, source_size.width(), source_size.height());
632 skia::RefPtr<SkGrPixelRef> source_pixel_ref =
633 skia::AdoptRef(new SkGrPixelRef(source_texture.get()));
634 source.setPixelRef(source_pixel_ref.get());
635
636 SkBitmap background;
637 background.setConfig(SkBitmap::kARGB_8888_Config,
638 background_size.width(),
639 background_size.height());
640 skia::RefPtr<SkGrPixelRef> background_pixel_ref =
641 skia::AdoptRef(new SkGrPixelRef(background_texture.get()));
642 background.setPixelRef(background_pixel_ref.get());
643
644 // Create a scratch texture for backing store.
645 GrTextureDesc desc;
646 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
647 desc.fSampleCnt = 0;
648 desc.fWidth = source.width();
649 desc.fHeight = source.height();
650 desc.fConfig = kSkia8888_GrPixelConfig;
651 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
652 GrAutoScratchTexture scratch_texture(
653 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
654 skia::RefPtr<GrTexture> backing_store =
655 skia::AdoptRef(scratch_texture.detach());
656
657 // Create a device and canvas using that backing store.
658 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
659 SkCanvas canvas(&device);
660
661 // Draw the source bitmap through the filter to the canvas.
662 canvas.clear(SK_ColorTRANSPARENT);
663 canvas.drawSprite(background, 0, 0);
664 SkPaint paint;
665 paint.setXfermodeMode(blend_mode);
666 canvas.drawSprite(source, 0, 0, &paint);
667
668 // Flush skia context so that all the rendered stuff appears on the
669 // texture.
670 offscreen_contexts->GrContext()->flush();
671
672 // Flush the GL context so rendering results from this context are
673 // visible in the compositor's context.
674 offscreen_contexts->Context3d()->flush();
675
676 // Use the compositor's GL context again.
677 renderer->Context()->makeContextCurrent();
678
679 return device.accessBitmap(false);
680 }
681
682 scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
566 DrawingFrame* frame, 683 DrawingFrame* frame,
567 const RenderPassDrawQuad* quad, 684 const RenderPassDrawQuad* quad,
568 const gfx::Transform& contents_device_transform, 685 const gfx::Transform& contents_device_transform,
569 const gfx::Transform& contents_device_transform_inverse) { 686 const gfx::Transform& contents_device_transform_inverse,
687 bool* background_changed) {
570 // This method draws a background filter, which applies a filter to any pixels 688 // This method draws a background filter, which applies a filter to any pixels
571 // behind the quad and seen through its background. The algorithm works as 689 // behind the quad and seen through its background. The algorithm works as
572 // follows: 690 // follows:
573 // 1. Compute a bounding box around the pixels that will be visible through 691 // 1. Compute a bounding box around the pixels that will be visible through
574 // the quad. 692 // the quad.
575 // 2. Read the pixels in the bounding box into a buffer R. 693 // 2. Read the pixels in the bounding box into a buffer R.
576 // 3. Apply the background filter to R, so that it is applied in the pixels' 694 // 3. Apply the background filter to R, so that it is applied in the pixels'
577 // coordinate space. 695 // coordinate space.
578 // 4. Apply the quad's inverse transform to map the pixels in R into the 696 // 4. Apply the quad's inverse transform to map the pixels in R into the
579 // quad's content space. This implicitly clips R by the content bounds of the 697 // quad's content space. This implicitly clips R by the content bounds of the
580 // quad since the destination texture has bounds matching the quad's content. 698 // quad since the destination texture has bounds matching the quad's content.
581 // 5. Draw the background texture for the contents using the same transform as 699 // 5. Draw the background texture for the contents using the same transform as
582 // used to draw the contents itself. This is done without blending to replace 700 // used to draw the contents itself. This is done without blending to replace
583 // the current background pixels with the new filtered background. 701 // the current background pixels with the new filtered background.
584 // 6. Draw the contents of the quad over drop of the new background with 702 // 6. Draw the contents of the quad over drop of the new background with
585 // blending, as per usual. The filtered background pixels will show through 703 // blending, as per usual. The filtered background pixels will show through
586 // any non-opaque pixels in this draws. 704 // any non-opaque pixels in this draws.
587 // 705 //
588 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5. 706 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
589 707
590 // TODO(danakj): When this algorithm changes, update 708 // TODO(danakj): When this algorithm changes, update
591 // LayerTreeHost::PrioritizeTextures() accordingly. 709 // LayerTreeHost::PrioritizeTextures() accordingly.
592 710
593 // TODO(danakj): We only allow background filters on an opaque render surface 711 // TODO(danakj): We only allow background filters on an opaque render surface
594 // because other surfaces may contain translucent pixels, and the contents 712 // because other surfaces may contain translucent pixels, and the contents
595 // behind those translucent pixels wouldn't have the filter applied. 713 // behind those translucent pixels wouldn't have the filter applied.
596 if (frame->current_render_pass->has_transparent_background) 714 bool apply_background_filters =
597 return scoped_ptr<ScopedResource>(); 715 !frame->current_render_pass->has_transparent_background;
598 DCHECK(!frame->current_texture); 716 DCHECK(!frame->current_texture);
599 717
600 // TODO(ajuma): Add support for reference filters once 718 // TODO(ajuma): Add support for reference filters once
601 // FilterOperations::GetOutsets supports reference filters. 719 // FilterOperations::GetOutsets supports reference filters.
602 if (quad->background_filters.HasReferenceFilter()) 720 if (apply_background_filters && quad->background_filters.HasReferenceFilter())
603 return scoped_ptr<ScopedResource>(); 721 apply_background_filters = false;
604 722
605 // TODO(danakj): Do a single readback for both the surface and replica and 723 // TODO(danakj): Do a single readback for both the surface and replica and
606 // cache the filtered results (once filter textures are not reused). 724 // cache the filtered results (once filter textures are not reused).
607 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( 725 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
608 contents_device_transform, SharedGeometryQuad().BoundingBox())); 726 contents_device_transform, SharedGeometryQuad().BoundingBox()));
609 727
610 int top, right, bottom, left; 728 int top, right, bottom, left;
611 quad->background_filters.GetOutsets(&top, &right, &bottom, &left); 729 quad->background_filters.GetOutsets(&top, &right, &bottom, &left);
612 window_rect.Inset(-left, -top, -right, -bottom); 730 window_rect.Inset(-left, -top, -right, -bottom);
613 731
614 window_rect.Intersect( 732 window_rect.Intersect(
615 MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect)); 733 MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
616 734
617 scoped_ptr<ScopedResource> device_background_texture = 735 scoped_ptr<ScopedResource> device_background_texture =
618 ScopedResource::create(resource_provider_); 736 ScopedResource::create(resource_provider_);
619 if (!device_background_texture->Allocate(window_rect.size(), 737 if (!device_background_texture->Allocate(
620 ResourceProvider::TextureUsageAny, 738 window_rect.size(),
621 RGBA_8888)) { 739 ResourceProvider::TextureUsageFramebuffer,
danakj 2013/11/13 21:02:03 Why this change? We don't bind this texture to be
rosca 2013/11/14 21:56:34 The device_background_texture's format has been re
danakj 2013/11/20 03:32:50 If this is fixing background filters entirely, the
rosca 2013/11/20 21:52:04 I run into this problem by forcing some background
740 RGBA_8888)) {
622 return scoped_ptr<ScopedResource>(); 741 return scoped_ptr<ScopedResource>();
623 } else { 742 } else {
624 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, 743 ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
625 device_background_texture->id()); 744 device_background_texture->id());
626 GetFramebufferTexture(lock.texture_id(), 745 GetFramebufferTexture(lock.texture_id(),
627 device_background_texture->format(), 746 device_background_texture->format(),
628 window_rect); 747 window_rect);
629 } 748 }
630 749
750 int filtered_device_background_texture_id = 0;
danakj 2013/11/13 21:02:03 move this down to above line 765?
rosca 2013/11/14 21:56:34 Done.
631 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( 751 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
632 quad->background_filters, device_background_texture->size()); 752 quad->background_filters, device_background_texture->size());
633 753
634 SkBitmap filtered_device_background = 754 SkBitmap filtered_device_background;
635 ApplyImageFilter(this, 755 if (apply_background_filters)
danakj 2013/11/13 21:02:03 need {}
rosca 2013/11/14 21:56:34 Done.
636 frame->offscreen_context_provider, 756 filtered_device_background =
637 quad->rect.origin(), 757 ApplyImageFilter(this,
638 filter.get(), 758 frame->offscreen_context_provider,
639 device_background_texture.get()); 759 quad->rect.origin(),
640 if (!filtered_device_background.getTexture()) 760 filter.get(),
641 return scoped_ptr<ScopedResource>(); 761 device_background_texture.get());
762 if (background_changed)
danakj 2013/11/13 21:02:03 why make this optional? i'd prefer to just always
rosca 2013/11/14 21:56:34 Done.
763 *background_changed = (filtered_device_background.getTexture() != NULL);
642 764
643 GrTexture* texture = 765 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
644 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); 766 if (filtered_device_background.getTexture()) {
645 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 }
646 775
647 scoped_ptr<ScopedResource> background_texture = 776 scoped_ptr<ScopedResource> background_texture =
648 ScopedResource::create(resource_provider_); 777 ScopedResource::create(resource_provider_);
649 if (!background_texture->Allocate(quad->rect.size(), 778 if (!background_texture->Allocate(quad->rect.size(),
650 ResourceProvider::TextureUsageFramebuffer, 779 ResourceProvider::TextureUsageFramebuffer,
651 RGBA_8888)) 780 RGBA_8888))
652 return scoped_ptr<ScopedResource>(); 781 return scoped_ptr<ScopedResource>();
653 782
654 const RenderPass* target_render_pass = frame->current_render_pass; 783 const RenderPass* target_render_pass = frame->current_render_pass;
655 bool using_background_texture = 784 bool using_background_texture =
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 gfx::Transform contents_device_transform = 835 gfx::Transform contents_device_transform =
707 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; 836 frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
708 contents_device_transform.FlattenTo2d(); 837 contents_device_transform.FlattenTo2d();
709 838
710 // Can only draw surface if device matrix is invertible. 839 // Can only draw surface if device matrix is invertible.
711 gfx::Transform contents_device_transform_inverse( 840 gfx::Transform contents_device_transform_inverse(
712 gfx::Transform::kSkipInitialization); 841 gfx::Transform::kSkipInitialization);
713 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) 842 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
714 return; 843 return;
715 844
845 bool apply_blend_mode =
danakj 2013/11/13 21:02:03 can this be bool need_background_texture = blen
rosca 2013/11/14 21:56:34 Done.
846 quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode;
847 bool background_changed = false;
716 scoped_ptr<ScopedResource> background_texture; 848 scoped_ptr<ScopedResource> background_texture;
717 if (!quad->background_filters.IsEmpty()) { 849 if (!quad->background_filters.IsEmpty() || apply_blend_mode) {
718 // The pixels from the filtered background should completely replace the 850 // The pixels from the filtered background should completely replace the
719 // current pixel values. 851 // current pixel values.
720 bool disable_blending = blend_enabled(); 852 bool disable_blending = blend_enabled();
721 if (disable_blending) 853 if (disable_blending)
722 SetBlendEnabled(false); 854 SetBlendEnabled(false);
723 855
724 background_texture = DrawBackgroundFilters( 856 background_texture =
725 frame, 857 GetBackgroundWithFilters(frame,
726 quad, 858 quad,
727 contents_device_transform, 859 contents_device_transform,
728 contents_device_transform_inverse); 860 contents_device_transform_inverse,
861 &background_changed);
729 862
730 if (disable_blending) 863 if (disable_blending)
731 SetBlendEnabled(true); 864 SetBlendEnabled(true);
732 } 865 }
733 866
734 // 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
735 // the surface and its replica. Apply filters to the contents texture. 868 // the surface and its replica. Apply filters to the contents texture.
736 SkBitmap filter_bitmap; 869 SkBitmap filter_bitmap;
737 SkScalar color_matrix[20]; 870 SkScalar color_matrix[20];
738 bool use_color_matrix = false; 871 bool use_color_matrix = false;
(...skipping 18 matching lines...) Expand all
757 } else { 890 } else {
758 filter_bitmap = ApplyImageFilter(this, 891 filter_bitmap = ApplyImageFilter(this,
759 frame->offscreen_context_provider, 892 frame->offscreen_context_provider,
760 quad->rect.origin(), 893 quad->rect.origin(),
761 filter.get(), 894 filter.get(),
762 contents_texture); 895 contents_texture);
763 } 896 }
764 } 897 }
765 } 898 }
766 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
767 // Draw the background texture if there is one. 910 // Draw the background texture if there is one.
danakj 2013/11/13 21:02:03 update this comment
rosca 2013/11/14 21:56:34 Done.
768 if (background_texture) { 911 if (background_texture && background_changed) {
769 DCHECK(background_texture->size() == quad->rect.size()); 912 DCHECK(background_texture->size() == quad->rect.size());
770 ResourceProvider::ScopedReadLockGL lock(resource_provider_, 913 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
771 background_texture->id()); 914 background_texture->id());
772 915
773 // 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
774 // 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
775 // in the shader to maintain orientation 918 // in the shader to maintain orientation
776 bool flip_vertically = true; 919 bool flip_vertically = true;
777 920
778 CopyTextureToFramebuffer(frame, 921 CopyTextureToFramebuffer(frame,
(...skipping 2186 matching lines...) Expand 10 before | Expand all | Expand 10 after
2965 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas 3108 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas
2966 // implementation. 3109 // implementation.
2967 return gr_context_ && context_->getContextAttributes().stencil; 3110 return gr_context_ && context_->getContextAttributes().stencil;
2968 } 3111 }
2969 3112
2970 bool GLRenderer::IsContextLost() { 3113 bool GLRenderer::IsContextLost() {
2971 return output_surface_->context_provider()->IsContextLost(); 3114 return output_surface_->context_provider()->IsContextLost();
2972 } 3115 }
2973 3116
2974 } // namespace cc 3117 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698