| 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 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 628 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, | 746 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, |
| 629 device_background_texture->id()); | 747 device_background_texture->id()); |
| 630 GetFramebufferTexture(lock.texture_id(), | 748 GetFramebufferTexture(lock.texture_id(), |
| 631 device_background_texture->format(), | 749 device_background_texture->format(), |
| 632 window_rect); | 750 window_rect); |
| 633 } | 751 } |
| 634 | 752 |
| 635 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( | 753 skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( |
| 636 quad->background_filters, device_background_texture->size()); | 754 quad->background_filters, device_background_texture->size()); |
| 637 | 755 |
| 638 SkBitmap filtered_device_background = | 756 SkBitmap filtered_device_background; |
| 639 ApplyImageFilter(this, | 757 if (apply_background_filters) { |
| 640 frame->offscreen_context_provider, | 758 filtered_device_background = |
| 641 quad->rect.origin(), | 759 ApplyImageFilter(this, |
| 642 filter.get(), | 760 frame->offscreen_context_provider, |
| 643 device_background_texture.get()); | 761 quad->rect.origin(), |
| 644 if (!filtered_device_background.getTexture()) | 762 filter.get(), |
| 645 return scoped_ptr<ScopedResource>(); | 763 device_background_texture.get()); |
| 764 } |
| 765 *background_changed = (filtered_device_background.getTexture() != NULL); |
| 646 | 766 |
| 647 GrTexture* texture = | 767 int filtered_device_background_texture_id = 0; |
| 648 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); | 768 scoped_ptr<ResourceProvider::ScopedReadLockGL> lock; |
| 649 int filtered_device_background_texture_id = texture->getTextureHandle(); | 769 if (filtered_device_background.getTexture()) { |
| 770 GrTexture* texture = |
| 771 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); |
| 772 filtered_device_background_texture_id = texture->getTextureHandle(); |
| 773 } else { |
| 774 lock.reset(new ResourceProvider::ScopedReadLockGL( |
| 775 resource_provider_, device_background_texture->id())); |
| 776 filtered_device_background_texture_id = lock->texture_id(); |
| 777 } |
| 650 | 778 |
| 651 scoped_ptr<ScopedResource> background_texture = | 779 scoped_ptr<ScopedResource> background_texture = |
| 652 ScopedResource::create(resource_provider_); | 780 ScopedResource::create(resource_provider_); |
| 653 if (!background_texture->Allocate(quad->rect.size(), | 781 if (!background_texture->Allocate(quad->rect.size(), |
| 654 ResourceProvider::TextureUsageFramebuffer, | 782 ResourceProvider::TextureUsageFramebuffer, |
| 655 RGBA_8888)) | 783 RGBA_8888)) |
| 656 return scoped_ptr<ScopedResource>(); | 784 return scoped_ptr<ScopedResource>(); |
| 657 | 785 |
| 658 const RenderPass* target_render_pass = frame->current_render_pass; | 786 const RenderPass* target_render_pass = frame->current_render_pass; |
| 659 bool using_background_texture = | 787 bool using_background_texture = |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 gfx::Transform contents_device_transform = | 838 gfx::Transform contents_device_transform = |
| 711 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; | 839 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; |
| 712 contents_device_transform.FlattenTo2d(); | 840 contents_device_transform.FlattenTo2d(); |
| 713 | 841 |
| 714 // Can only draw surface if device matrix is invertible. | 842 // Can only draw surface if device matrix is invertible. |
| 715 gfx::Transform contents_device_transform_inverse( | 843 gfx::Transform contents_device_transform_inverse( |
| 716 gfx::Transform::kSkipInitialization); | 844 gfx::Transform::kSkipInitialization); |
| 717 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) | 845 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) |
| 718 return; | 846 return; |
| 719 | 847 |
| 848 bool need_background_texture = |
| 849 quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode || |
| 850 !quad->background_filters.IsEmpty(); |
| 851 bool background_changed = false; |
| 720 scoped_ptr<ScopedResource> background_texture; | 852 scoped_ptr<ScopedResource> background_texture; |
| 721 if (!quad->background_filters.IsEmpty()) { | 853 if (need_background_texture) { |
| 722 // The pixels from the filtered background should completely replace the | 854 // The pixels from the filtered background should completely replace the |
| 723 // current pixel values. | 855 // current pixel values. |
| 724 bool disable_blending = blend_enabled(); | 856 bool disable_blending = blend_enabled(); |
| 725 if (disable_blending) | 857 if (disable_blending) |
| 726 SetBlendEnabled(false); | 858 SetBlendEnabled(false); |
| 727 | 859 |
| 728 background_texture = DrawBackgroundFilters( | 860 background_texture = |
| 729 frame, | 861 GetBackgroundWithFilters(frame, |
| 730 quad, | 862 quad, |
| 731 contents_device_transform, | 863 contents_device_transform, |
| 732 contents_device_transform_inverse); | 864 contents_device_transform_inverse, |
| 865 &background_changed); |
| 733 | 866 |
| 734 if (disable_blending) | 867 if (disable_blending) |
| 735 SetBlendEnabled(true); | 868 SetBlendEnabled(true); |
| 736 } | 869 } |
| 737 | 870 |
| 738 // TODO(senorblanco): Cache this value so that we don't have to do it for both | 871 // TODO(senorblanco): Cache this value so that we don't have to do it for both |
| 739 // the surface and its replica. Apply filters to the contents texture. | 872 // the surface and its replica. Apply filters to the contents texture. |
| 740 SkBitmap filter_bitmap; | 873 SkBitmap filter_bitmap; |
| 741 SkScalar color_matrix[20]; | 874 SkScalar color_matrix[20]; |
| 742 bool use_color_matrix = false; | 875 bool use_color_matrix = false; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 761 } else { | 894 } else { |
| 762 filter_bitmap = ApplyImageFilter(this, | 895 filter_bitmap = ApplyImageFilter(this, |
| 763 frame->offscreen_context_provider, | 896 frame->offscreen_context_provider, |
| 764 quad->rect.origin(), | 897 quad->rect.origin(), |
| 765 filter.get(), | 898 filter.get(), |
| 766 contents_texture); | 899 contents_texture); |
| 767 } | 900 } |
| 768 } | 901 } |
| 769 } | 902 } |
| 770 | 903 |
| 771 // Draw the background texture if there is one. | 904 if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode && |
| 772 if (background_texture) { | 905 background_texture) { |
| 906 filter_bitmap = |
| 907 ApplyBlendModeWithBackdrop(this, |
| 908 frame->offscreen_context_provider, |
| 909 filter_bitmap, |
| 910 contents_texture, |
| 911 background_texture.get(), |
| 912 quad->shared_quad_state->blend_mode); |
| 913 } |
| 914 |
| 915 // Draw the background texture if it has some filters applied. |
| 916 if (background_texture && background_changed) { |
| 773 DCHECK(background_texture->size() == quad->rect.size()); | 917 DCHECK(background_texture->size() == quad->rect.size()); |
| 774 ResourceProvider::ScopedReadLockGL lock(resource_provider_, | 918 ResourceProvider::ScopedReadLockGL lock(resource_provider_, |
| 775 background_texture->id()); | 919 background_texture->id()); |
| 776 | 920 |
| 777 // The background_texture is oriented the same as the frame buffer. The | 921 // The background_texture is oriented the same as the frame buffer. The |
| 778 // transform we are copying with has a vertical flip, so flip the contents | 922 // transform we are copying with has a vertical flip, so flip the contents |
| 779 // in the shader to maintain orientation | 923 // in the shader to maintain orientation |
| 780 bool flip_vertically = true; | 924 bool flip_vertically = true; |
| 781 | 925 |
| 782 CopyTextureToFramebuffer(frame, | 926 CopyTextureToFramebuffer(frame, |
| (...skipping 2169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2952 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas | 3096 // The Skia GPU backend requires a stencil buffer. See ReinitializeGrCanvas |
| 2953 // implementation. | 3097 // implementation. |
| 2954 return gr_context_ && context_->getContextAttributes().stencil; | 3098 return gr_context_ && context_->getContextAttributes().stencil; |
| 2955 } | 3099 } |
| 2956 | 3100 |
| 2957 bool GLRenderer::IsContextLost() { | 3101 bool GLRenderer::IsContextLost() { |
| 2958 return output_surface_->context_provider()->IsContextLost(); | 3102 return output_surface_->context_provider()->IsContextLost(); |
| 2959 } | 3103 } |
| 2960 | 3104 |
| 2961 } // namespace cc | 3105 } // namespace cc |
| OLD | NEW |