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

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: Created 7 years, 3 months 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 585 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 // Flush the GL context so rendering results from this context are 596 // Flush the GL context so rendering results from this context are
597 // visible in the compositor's context. 597 // visible in the compositor's context.
598 offscreen_contexts->Context3d()->flush(); 598 offscreen_contexts->Context3d()->flush();
599 599
600 // Use the compositor's GL context again. 600 // Use the compositor's GL context again.
601 renderer->Context()->makeContextCurrent(); 601 renderer->Context()->makeContextCurrent();
602 602
603 return device.accessBitmap(false); 603 return device.accessBitmap(false);
604 } 604 }
605 605
606 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( 606 static SkBitmap ApplyBlendModeWithBackdrop(GLRenderer* renderer,
607 ContextProvider* offscreen_contexts,
608 SkBitmap source_bitmap_with_filters,
609 ScopedResource* source_texture_resource,
610 ScopedResource* background_texture_resource,
611 SkXfermode::Mode blendMode) {
612 if (!offscreen_contexts || !offscreen_contexts->GrContext())
613 return source_bitmap_with_filters;
614
615 DCHECK(background_texture_resource);
616 DCHECK(source_texture_resource);
617
618 gfx::Size source_size = source_texture_resource->size();
619 gfx::Size background_size = background_texture_resource->size();
620
621 DCHECK_LE(background_size.width(), source_size.width());
622 DCHECK_LE(background_size.height(), source_size.height());
623
624 int source_texture_with_filters_id;
625 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
626 if (source_bitmap_with_filters.getTexture()) {
627 DCHECK(source_size.width() == source_bitmap_with_filters.width());
628 DCHECK(source_size.height() == source_bitmap_with_filters.height());
629 GrTexture* texture =
630 reinterpret_cast<GrTexture*>(source_bitmap_with_filters.getTexture());
631 source_texture_with_filters_id = texture->getTextureHandle();
632 } else {
633 lock.reset(
634 new ResourceProvider::ScopedReadLockGL(renderer->resource_provider(),
635 source_texture_resource->id()));
636 source_texture_with_filters_id = lock->texture_id();
637 }
638
639 ResourceProvider::ScopedReadLockGL lock_background(
640 renderer->resource_provider(), background_texture_resource->id());
641
642 // Flush the compositor context to ensure that textures there are available
643 // in the shared context. Do this after locking/creating the compositor
644 // texture.
645 renderer->resource_provider()->Flush();
646
647 // Make sure skia uses the correct GL context.
648 offscreen_contexts->Context3d()->makeContextCurrent();
649
650 // Wrap the source texture in a Ganesh platform texture.
651 GrBackendTextureDesc backend_texture_description;
652 backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
653 backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
654
655 backend_texture_description.fWidth = source_size.width();
656 backend_texture_description.fHeight = source_size.height();
657 backend_texture_description.fTextureHandle = source_texture_with_filters_id;
658 skia::RefPtr<GrTexture> source_texture =
659 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
660 backend_texture_description));
661
662 backend_texture_description.fWidth = background_size.width();
663 backend_texture_description.fHeight = background_size.height();
664 backend_texture_description.fTextureHandle = lock_background.texture_id();
665 skia::RefPtr<GrTexture> background_texture =
666 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
667 backend_texture_description));
668
669 // Place the platform texture inside an SkBitmap.
670 SkBitmap source;
671 source.setConfig(SkBitmap::kARGB_8888_Config,
672 source_size.width(), source_size.height());
673 skia::RefPtr<SkGrPixelRef> source_pixel_ref =
674 skia::AdoptRef(new SkGrPixelRef(source_texture.get()));
675 source.setPixelRef(source_pixel_ref.get());
676
677 SkBitmap background;
678 background.setConfig(SkBitmap::kARGB_8888_Config,
679 background_size.width(), background_size.height());
680 skia::RefPtr<SkGrPixelRef> background_pixel_ref =
681 skia::AdoptRef(new SkGrPixelRef(background_texture.get()));
682 background.setPixelRef(background_pixel_ref.get());
683
684 // Create a scratch texture for backing store.
685 GrTextureDesc desc;
686 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
687 desc.fSampleCnt = 0;
688 desc.fWidth = source.width();
689 desc.fHeight = source.height();
690 desc.fConfig = kSkia8888_GrPixelConfig;
691 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
692 GrAutoScratchTexture scratch_texture(
693 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
694 skia::RefPtr<GrTexture> backing_store =
695 skia::AdoptRef(scratch_texture.detach());
696
697 // Create a device and canvas using that backing store.
698 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
699 SkCanvas canvas(&device);
700
701 // Draw the source bitmap through the filter to the canvas.
702 canvas.clear(SK_ColorTRANSPARENT);
703 canvas.drawSprite(background, 0, 0);
704 SkPaint paint;
705 paint.setXfermodeMode(blendMode);
706 canvas.drawSprite(source, 0, 0, &paint);
707
708 // Flush skia context so that all the rendered stuff appears on the
709 // texture.
710 offscreen_contexts->GrContext()->flush();
711
712 // Flush the GL context so rendering results from this context are
713 // visible in the compositor's context.
714 offscreen_contexts->Context3d()->flush();
715
716 // Use the compositor's GL context again.
717 renderer->Context()->makeContextCurrent();
718
719 return device.accessBitmap(false);
720 }
721
722 scoped_ptr<ScopedResource> GLRenderer::CreateBackgroundTextureWithFilters(
607 DrawingFrame* frame, 723 DrawingFrame* frame,
608 const RenderPassDrawQuad* quad, 724 const RenderPassDrawQuad* quad,
609 const gfx::Transform& contents_device_transform, 725 const gfx::Transform& contents_device_transform,
610 const gfx::Transform& contents_device_transform_inverse) { 726 const gfx::Transform& contents_device_transform_inverse,
727 bool& background_changed) {
611 // This method draws a background filter, which applies a filter to any pixels 728 // This method draws a background filter, which applies a filter to any pixels
612 // behind the quad and seen through its background. The algorithm works as 729 // behind the quad and seen through its background. The algorithm works as
613 // follows: 730 // follows:
614 // 1. Compute a bounding box around the pixels that will be visible through 731 // 1. Compute a bounding box around the pixels that will be visible through
615 // the quad. 732 // the quad.
616 // 2. Read the pixels in the bounding box into a buffer R. 733 // 2. Read the pixels in the bounding box into a buffer R.
617 // 3. Apply the background filter to R, so that it is applied in the pixels' 734 // 3. Apply the background filter to R, so that it is applied in the pixels'
618 // coordinate space. 735 // coordinate space.
619 // 4. Apply the quad's inverse transform to map the pixels in R into the 736 // 4. Apply the quad's inverse transform to map the pixels in R into the
620 // quad's content space. This implicitly clips R by the content bounds of the 737 // quad's content space. This implicitly clips R by the content bounds of the
621 // quad since the destination texture has bounds matching the quad's content. 738 // quad since the destination texture has bounds matching the quad's content.
622 // 5. Draw the background texture for the contents using the same transform as 739 // 5. Draw the background texture for the contents using the same transform as
623 // used to draw the contents itself. This is done without blending to replace 740 // used to draw the contents itself. This is done without blending to replace
624 // the current background pixels with the new filtered background. 741 // the current background pixels with the new filtered background.
625 // 6. Draw the contents of the quad over drop of the new background with 742 // 6. Draw the contents of the quad over drop of the new background with
626 // blending, as per usual. The filtered background pixels will show through 743 // blending, as per usual. The filtered background pixels will show through
627 // any non-opaque pixels in this draws. 744 // any non-opaque pixels in this draws.
628 // 745 //
629 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5. 746 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
630 747
631 // TODO(danakj): When this algorithm changes, update 748 // TODO(danakj): When this algorithm changes, update
632 // LayerTreeHost::PrioritizeTextures() accordingly. 749 // LayerTreeHost::PrioritizeTextures() accordingly.
633 750
634 FilterOperations filters = 751 FilterOperations filters =
635 RenderSurfaceFilters::Optimize(quad->background_filters); 752 RenderSurfaceFilters::Optimize(quad->background_filters);
636 DCHECK(!filters.IsEmpty()); 753 DCHECK(!filters.IsEmpty() || quad->blend_mode != SkXfermode::kSrcOver_Mode);
637 754
638 // TODO(danakj): We only allow background filters on an opaque render surface 755 // TODO(danakj): We only allow background filters on an opaque render surface
639 // because other surfaces may contain translucent pixels, and the contents 756 // because other surfaces may contain translucent pixels, and the contents
640 // behind those translucent pixels wouldn't have the filter applied. 757 // behind those translucent pixels wouldn't have the filter applied.
641 if (frame->current_render_pass->has_transparent_background) 758 bool apply_background_filters = !filters.IsEmpty() &&
642 return scoped_ptr<ScopedResource>(); 759 !frame->current_render_pass->has_transparent_background;
643 DCHECK(!frame->current_texture); 760 DCHECK(!frame->current_texture);
644 761
645 // TODO(danakj): Do a single readback for both the surface and replica and 762 // TODO(danakj): Do a single readback for both the surface and replica and
646 // cache the filtered results (once filter textures are not reused). 763 // cache the filtered results (once filter textures are not reused).
647 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( 764 gfx::Rect window_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
648 contents_device_transform, SharedGeometryQuad().BoundingBox())); 765 contents_device_transform, SharedGeometryQuad().BoundingBox()));
649 766
650 int top, right, bottom, left; 767 int top, right, bottom, left;
651 filters.GetOutsets(&top, &right, &bottom, &left); 768 filters.GetOutsets(&top, &right, &bottom, &left);
652 window_rect.Inset(-left, -top, -right, -bottom); 769 window_rect.Inset(-left, -top, -right, -bottom);
653 770
654 window_rect.Intersect( 771 window_rect.Intersect(
655 MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect)); 772 MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
656 773
657 scoped_ptr<ScopedResource> device_background_texture = 774 scoped_ptr<ScopedResource> device_background_texture =
658 ScopedResource::create(resource_provider_); 775 ScopedResource::create(resource_provider_);
659 if (!device_background_texture->Allocate(window_rect.size(), 776 if (!device_background_texture->Allocate(window_rect.size(),
660 ResourceProvider::TextureUsageAny, 777 ResourceProvider::TextureUsageAny,
661 RGBA_8888)) { 778 RGBA_8888)) {
662 return scoped_ptr<ScopedResource>(); 779 return scoped_ptr<ScopedResource>();
663 } else { 780 } else {
664 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, 781 ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
665 device_background_texture->id()); 782 device_background_texture->id());
666 GetFramebufferTexture(lock.texture_id(), 783 GetFramebufferTextureSubImage(lock.texture_id(),
667 device_background_texture->format(), 784 gfx::Point(),
668 window_rect); 785 window_rect);
669 } 786 }
670 787
671 SkBitmap filtered_device_background = 788 int filtered_device_background_texture_id = 0;
672 ApplyFilters(this,
673 frame->offscreen_context_provider,
674 filters,
675 device_background_texture.get());
676 if (!filtered_device_background.getTexture())
677 return scoped_ptr<ScopedResource>();
678 789
679 GrTexture* texture = 790 SkBitmap filtered_device_background;
680 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); 791 if (apply_background_filters)
681 int filtered_device_background_texture_id = texture->getTextureHandle(); 792 filtered_device_background = ApplyFilters(this,
793 frame->offscreen_context_provider, filters,
794 device_background_texture.get());
795
796 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
797 if (filtered_device_background.getTexture()) {
798 GrTexture* texture =
799 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture());
800 filtered_device_background_texture_id = texture->getTextureHandle();
801 background_changed = true;
802 } else {
803 lock.reset(new ResourceProvider::ScopedReadLockGL(resource_provider_,
804 device_background_texture->id()));
805 filtered_device_background_texture_id = lock->texture_id();
806 background_changed = false;
807 }
682 808
683 scoped_ptr<ScopedResource> background_texture = 809 scoped_ptr<ScopedResource> background_texture =
684 ScopedResource::create(resource_provider_); 810 ScopedResource::create(resource_provider_);
685 if (!background_texture->Allocate(quad->rect.size(), 811 if (!background_texture->Allocate(quad->rect.size(),
686 ResourceProvider::TextureUsageFramebuffer, 812 ResourceProvider::TextureUsageFramebuffer,
687 RGBA_8888)) 813 RGBA_8888))
688 return scoped_ptr<ScopedResource>(); 814 return scoped_ptr<ScopedResource>();
689 815
690 const RenderPass* target_render_pass = frame->current_render_pass; 816 const RenderPass* target_render_pass = frame->current_render_pass;
691 bool using_background_texture = 817 bool using_background_texture =
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 gfx::Transform contents_device_transform = 868 gfx::Transform contents_device_transform =
743 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; 869 frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
744 contents_device_transform.FlattenTo2d(); 870 contents_device_transform.FlattenTo2d();
745 871
746 // Can only draw surface if device matrix is invertible. 872 // Can only draw surface if device matrix is invertible.
747 gfx::Transform contents_device_transform_inverse( 873 gfx::Transform contents_device_transform_inverse(
748 gfx::Transform::kSkipInitialization); 874 gfx::Transform::kSkipInitialization);
749 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) 875 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
750 return; 876 return;
751 877
878 bool applyBlendMode = quad->blend_mode != SkXfermode::kSrcOver_Mode;
879 bool backgroundChanged = false;
752 scoped_ptr<ScopedResource> background_texture; 880 scoped_ptr<ScopedResource> background_texture;
753 if (!quad->background_filters.IsEmpty()) { 881 if (!quad->background_filters.IsEmpty() || applyBlendMode) {
754 // The pixels from the filtered background should completely replace the 882 // The pixels from the filtered background should completely replace the
755 // current pixel values. 883 // current pixel values.
756 bool disable_blending = blend_enabled(); 884 bool disable_blending = blend_enabled();
757 if (disable_blending) 885 if (disable_blending)
758 SetBlendEnabled(false); 886 SetBlendEnabled(false);
759 887
760 background_texture = DrawBackgroundFilters( 888 background_texture = CreateBackgroundTextureWithFilters(
761 frame, 889 frame,
762 quad, 890 quad,
763 contents_device_transform, 891 contents_device_transform,
764 contents_device_transform_inverse); 892 contents_device_transform_inverse,
893 backgroundChanged);
765 894
766 if (disable_blending) 895 if (disable_blending)
767 SetBlendEnabled(true); 896 SetBlendEnabled(true);
768 } 897 }
769 898
770 // TODO(senorblanco): Cache this value so that we don't have to do it for both 899 // TODO(senorblanco): Cache this value so that we don't have to do it for both
771 // the surface and its replica. Apply filters to the contents texture. 900 // the surface and its replica. Apply filters to the contents texture.
772 SkBitmap filter_bitmap; 901 SkBitmap filter_bitmap;
773 SkScalar color_matrix[20]; 902 SkScalar color_matrix[20];
774 bool use_color_matrix = false; 903 bool use_color_matrix = false;
(...skipping 27 matching lines...) Expand all
802 color_matrix, optimized_filters.at(0).matrix(), sizeof(color_matrix)); 931 color_matrix, optimized_filters.at(0).matrix(), sizeof(color_matrix));
803 use_color_matrix = true; 932 use_color_matrix = true;
804 } else { 933 } else {
805 filter_bitmap = ApplyFilters(this, 934 filter_bitmap = ApplyFilters(this,
806 frame->offscreen_context_provider, 935 frame->offscreen_context_provider,
807 optimized_filters, 936 optimized_filters,
808 contents_texture); 937 contents_texture);
809 } 938 }
810 } 939 }
811 940
941 if (background_texture && applyBlendMode) {
942 filter_bitmap = ApplyBlendModeWithBackdrop(this,
943 frame->offscreen_context_provider, filter_bitmap,
944 contents_texture, background_texture.get(), quad->blend_mode);
945 }
946
812 // Draw the background texture if there is one. 947 // Draw the background texture if there is one.
813 if (background_texture) { 948 if (background_texture && backgroundChanged) {
814 DCHECK(background_texture->size() == quad->rect.size()); 949 DCHECK(background_texture->size() == quad->rect.size());
815 ResourceProvider::ScopedReadLockGL lock(resource_provider_, 950 ResourceProvider::ScopedReadLockGL lock(resource_provider_,
816 background_texture->id()); 951 background_texture->id());
817 952
818 // The background_texture is oriented the same as the frame buffer. The 953 // The background_texture is oriented the same as the frame buffer. The
819 // transform we are copying with has a vertical flip, so flip the contents 954 // transform we are copying with has a vertical flip, so flip the contents
820 // in the shader to maintain orientation 955 // in the shader to maintain orientation
821 bool flip_vertically = true; 956 bool flip_vertically = true;
822 957
823 CopyTextureToFramebuffer(frame, 958 CopyTextureToFramebuffer(frame,
(...skipping 1629 matching lines...) Expand 10 before | Expand all | Expand 10 after
2453 scoped_ptr<SkAutoLockPixels> lock, 2588 scoped_ptr<SkAutoLockPixels> lock,
2454 scoped_ptr<CopyOutputRequest> request, 2589 scoped_ptr<CopyOutputRequest> request,
2455 bool success) { 2590 bool success) {
2456 DCHECK(request->force_bitmap_result()); 2591 DCHECK(request->force_bitmap_result());
2457 2592
2458 lock.reset(); 2593 lock.reset();
2459 if (success) 2594 if (success)
2460 request->SendBitmapResult(bitmap.Pass()); 2595 request->SendBitmapResult(bitmap.Pass());
2461 } 2596 }
2462 2597
2598 void GLRenderer::GetFramebufferTextureSubImage(unsigned texture_id,
2599 gfx::Point offset,
2600 gfx::Rect window_rect) {
2601 DCHECK(texture_id);
2602 DCHECK_GE(window_rect.x(), 0);
2603 DCHECK_GE(window_rect.y(), 0);
2604 DCHECK_LE(window_rect.right(), current_surface_size_.width());
2605 DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
2606
2607 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2608 GLC(context_,
2609 context_->copyTexSubImage2D(GL_TEXTURE_2D,
shawnsingh 2013/09/25 05:33:53 Will this be certainly fast on all drivers/hardwar
rosca 2013/09/25 18:00:00 Are you referring to the copyTexSubImage2D functio
2610 0,
2611 offset.x(),
2612 offset.y(),
2613 window_rect.x(),
2614 window_rect.y(),
2615 window_rect.width(),
2616 window_rect.height()));
2617 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0));
2618 }
2619
2463 void GLRenderer::GetFramebufferTexture( 2620 void GLRenderer::GetFramebufferTexture(
2464 unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) { 2621 unsigned texture_id, ResourceFormat texture_format, gfx::Rect window_rect) {
2465 DCHECK(texture_id); 2622 DCHECK(texture_id);
2466 DCHECK_GE(window_rect.x(), 0); 2623 DCHECK_GE(window_rect.x(), 0);
2467 DCHECK_GE(window_rect.y(), 0); 2624 DCHECK_GE(window_rect.y(), 0);
2468 DCHECK_LE(window_rect.right(), current_surface_size_.width()); 2625 DCHECK_LE(window_rect.right(), current_surface_size_.width());
2469 DCHECK_LE(window_rect.bottom(), current_surface_size_.height()); 2626 DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
2470 2627
2471 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id)); 2628 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, texture_id));
2472 GLC(context_, 2629 GLC(context_,
(...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after
3132 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas 3289 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas
3133 // implementation. 3290 // implementation.
3134 return gr_context_ && context_->getContextAttributes().stencil; 3291 return gr_context_ && context_->getContextAttributes().stencil;
3135 } 3292 }
3136 3293
3137 bool GLRenderer::IsContextLost() { 3294 bool GLRenderer::IsContextLost() {
3138 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR); 3295 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR);
3139 } 3296 }
3140 3297
3141 } // namespace cc 3298 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698