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 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |