OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |