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

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

Powered by Google App Engine
This is Rietveld 408576698