Bug 1543621 - Move Y flip handling to AsyncImagePipelineManager::ApplyAsyncImageForPipeline() r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Tue, 23 Apr 2019 12:29:24 +0000
changeset 470480 b2a8685b55e1904694913e75c89151056a6d3508
parent 470479 faab5ee080b68acb0eff49bf0a9f3db10ad44a8d
child 470481 c126bc2983801e7e8b77e57e5c6c2d5998ce7d59
push id35906
push useraciure@mozilla.com
push dateTue, 23 Apr 2019 22:14:56 +0000
treeherdermozilla-central@0ce3633f8b80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1543621, 1507076
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1543621 - Move Y flip handling to AsyncImagePipelineManager::ApplyAsyncImageForPipeline() r=nical With webrender, current gecko does not handle SurfaceTexture.getTransformMatrix() yet. SurfaceTexture is used for video decoding and WebGL. On both usages, when getTransformMatrix() is not handled, it actually worked as bottom left origin. Then gecko need to ignore y flip. AsyncImagePipelineManager::ApplyAsyncImageForPipeline() is a good place to handle the situations, since it handles canvas and video frame rendering. Long term solution is going to be handled by Bug 1507076. Differential Revision: https://phabricator.services.mozilla.com/D28315
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/wr/AsyncImagePipelineManager.cpp
gfx/layers/wr/WebRenderTextureHost.cpp
gfx/layers/wr/WebRenderTextureHost.h
layout/generic/nsHTMLCanvasFrame.cpp
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -643,16 +643,20 @@ void TextureHost::SetReadLocked() {
 
 void TextureHost::ReadUnlock() {
   if (mReadLock && mReadLocked) {
     mReadLock->ReadUnlock();
     mReadLocked = false;
   }
 }
 
+bool TextureHost::NeedsYFlip() const {
+  return bool(mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT);
+}
+
 bool BufferTextureHost::EnsureWrappingTextureSource() {
   MOZ_ASSERT(!mHasIntermediateBuffer);
 
   if (mFirstSource && mFirstSource->IsOwnedBy(this)) {
     return true;
   }
   // We don't own it, apparently.
   if (mFirstSource) {
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -672,16 +672,18 @@ class TextureHost : public AtomicRefCoun
    * Some API's can use the cross-process IOSurface directly, such as OpenVR
    */
   virtual MacIOSurface* GetMacIOSurface() { return nullptr; }
 
   virtual bool IsDirectMap() { return false; }
 
   virtual bool SupportsWrNativeTexture() { return false; }
 
+  virtual bool NeedsYFlip() const;
+
  protected:
   virtual void ReadUnlock();
 
   void RecycleTexture(TextureFlags aFlags);
 
   virtual void MaybeNotifyUnlocked() {}
 
   virtual void UpdatedInternal(const nsIntRegion* Region) {}
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -256,16 +256,17 @@ Maybe<TextureHost::ResourceUpdateOp> Asy
   // an rgb image.
   auto numKeys = useExternalImage ? texture->NumSubTextures() : 1;
 
   // If we already had a texture and the format hasn't changed, better to reuse
   // the image keys than create new ones.
   bool canUpdate = !!previousTexture &&
                    previousTexture->GetSize() == texture->GetSize() &&
                    previousTexture->GetFormat() == texture->GetFormat() &&
+                   previousTexture->NeedsYFlip() == texture->NeedsYFlip() &&
                    aPipeline->mKeys.Length() == numKeys;
 
   // Check if WebRenderTextureHostWrapper could be reused.
   if (aPipeline->mWrTextureWrapper && (!useWrTextureWrapper || !canUpdate)) {
     aPipeline->mWrTextureWrapper = nullptr;
     canUpdate = false;
   }
 
@@ -405,25 +406,30 @@ void AsyncImagePipelineManager::ApplyAsy
     if (aPipeline->mCurrentTexture) {
       HoldExternalImage(aPipelineId, aEpoch, aPipeline->mCurrentTexture);
     }
     return;
   }
 
   aPipeline->mIsChanged = false;
 
+  gfx::Matrix4x4 scTransform = aPipeline->mScTransform;
+  if (aPipeline->mCurrentTexture && aPipeline->mCurrentTexture->NeedsYFlip()) {
+    scTransform.PreTranslate(0, aPipeline->mCurrentTexture->GetSize().height, 0)
+        .PreScale(1, -1, 1);
+  }
+
   wr::LayoutSize contentSize{aPipeline->mScBounds.Width(),
                              aPipeline->mScBounds.Height()};
   wr::DisplayListBuilder builder(aPipelineId, contentSize);
 
   float opacity = 1.0f;
   wr::StackingContextParams params;
   params.opacity = &opacity;
-  params.mTransformPtr =
-      aPipeline->mScTransform.IsIdentity() ? nullptr : &aPipeline->mScTransform;
+  params.mTransformPtr = scTransform.IsIdentity() ? nullptr : &scTransform;
   params.mix_blend_mode = aPipeline->mMixBlendMode;
 
   Maybe<wr::WrSpatialId> referenceFrameId = builder.PushStackingContext(
       params, wr::ToRoundedLayoutRect(aPipeline->mScBounds),
       // This is fine to do unconditionally because we only push images here.
       wr::RasterSpace::Screen());
 
   Maybe<wr::SpaceAndClipChainHelper> spaceAndClipChainHelper;
--- a/gfx/layers/wr/WebRenderTextureHost.cpp
+++ b/gfx/layers/wr/WebRenderTextureHost.cpp
@@ -164,10 +164,23 @@ void WebRenderTextureHost::PushDisplayIt
   mWrappedTextureHost->PushDisplayItems(aBuilder, aBounds, aClip, aFilter,
                                         aImageKeys);
 }
 
 bool WebRenderTextureHost::SupportsWrNativeTexture() {
   return mWrappedTextureHost->SupportsWrNativeTexture();
 }
 
+bool WebRenderTextureHost::NeedsYFlip() const {
+  bool yFlip = TextureHost::NeedsYFlip();
+  if (mWrappedTextureHost->AsSurfaceTextureHost()) {
+    MOZ_ASSERT(yFlip);
+    // With WebRender, SurfaceTextureHost always requests y-flip.
+    // But y-flip should not be handled, since
+    // SurfaceTexture.getTransformMatrix() is not handled yet.
+    // See Bug 1507076.
+    yFlip = false;
+  }
+  return yFlip;
+}
+
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/wr/WebRenderTextureHost.h
+++ b/gfx/layers/wr/WebRenderTextureHost.h
@@ -77,16 +77,18 @@ class WebRenderTextureHost : public Text
 
   void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
                         const wr::LayoutRect& aBounds,
                         const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
                         const Range<wr::ImageKey>& aImageKeys) override;
 
   bool SupportsWrNativeTexture() override;
 
+  bool NeedsYFlip() const override;
+
  protected:
   void CreateRenderTextureHost(const SurfaceDescriptor& aDesc,
                                TextureHost* aTexture);
 
   RefPtr<TextureHost> mWrappedTextureHost;
   wr::ExternalImageId mExternalImageId;
 };
 
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -170,20 +170,16 @@ class nsDisplayCanvas final : public nsD
         aBuilder.PushIFrame(r, !BackfaceIsHidden(), data->GetPipelineId().ref(),
                             /*ignoreMissingPipelines*/ false);
 
         gfx::Matrix4x4 scTransform;
         gfxRect destGFXRect = mFrame->PresContext()->AppUnitsToGfxUnits(dest);
         scTransform.PreScale(destGFXRect.Width() / canvasSizeInPx.width,
                              destGFXRect.Height() / canvasSizeInPx.height,
                              1.0f);
-        if (data->NeedsYFlip()) {
-          scTransform = scTransform.PreTranslate(0, data->GetSize().height, 0)
-                            .PreScale(1, -1, 1);
-        }
 
         MaybeIntSize scaleToSize;
         LayoutDeviceRect scBounds(LayoutDevicePoint(0, 0), bounds.Size());
         wr::ImageRendering filter = wr::ToImageRendering(
             nsLayoutUtils::GetSamplingFilterForFrame(mFrame));
         wr::MixBlendMode mixBlendMode = wr::MixBlendMode::Normal;
         aManager->WrBridge()->AddWebRenderParentCommand(
             OpUpdateAsyncImagePipeline(data->GetPipelineId().value(), scBounds,