Bypass DecomposeIntoNoRepeatRects when possible. (bug 1396507 part 3, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Wed, 13 Sep 2017 09:30:26 -0400
changeset 430187 400e455a06dad4d88bf441bfe83087c798555348
parent 430186 44c703889755556f9db6f2c1aaa01e9f42eb583f
child 430188 393e901c47f67918b66b837a1a05509aa0216b78
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1396507
milestone57.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
Bypass DecomposeIntoNoRepeatRects when possible. (bug 1396507 part 3, r=mattwoodrow)
gfx/layers/d3d11/MLGDeviceD3D11.cpp
gfx/layers/mlgpu/MLGDevice.cpp
gfx/layers/mlgpu/MLGDeviceTypes.h
gfx/layers/mlgpu/PaintedLayerMLGPU.h
gfx/layers/mlgpu/RenderPassMLGPU.cpp
gfx/layers/mlgpu/RenderPassMLGPU.h
--- a/gfx/layers/d3d11/MLGDeviceD3D11.cpp
+++ b/gfx/layers/d3d11/MLGDeviceD3D11.cpp
@@ -1088,16 +1088,27 @@ MLGDeviceD3D11::InitSamplerStates()
     desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
     memset(desc.BorderColor, 0, sizeof(desc.BorderColor));
     HRESULT hr = mDevice->CreateSamplerState(&desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearClampToZero]));
     if (FAILED(hr)) {
       return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
                   "Could not create linear clamp to zero sampler (%x)", hr);
     }
   }
+  {
+    CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
+    desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
+    desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
+    desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
+    HRESULT hr = mDevice->CreateSamplerState(&desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearRepeat]));
+    if (FAILED(hr)) {
+      return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
+                  "Could not create linear clamp to zero sampler (%x)", hr);
+    }
+  }
 
   {
     CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
     desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
     HRESULT hr = mDevice->CreateSamplerState(&desc, getter_AddRefs(mSamplerStates[SamplerMode::Point]));
     if (FAILED(hr)) {
       return Fail("FEATURE_FAILURE_POINT_SAMPLER",
                   "Could not create point sampler (%x)", hr);
--- a/gfx/layers/mlgpu/MLGDevice.cpp
+++ b/gfx/layers/mlgpu/MLGDevice.cpp
@@ -233,31 +233,16 @@ MLGDevice::SetPSTexturesYUV(uint32_t aSl
 }
 
 void
 MLGDevice::SetPSTexture(uint32_t aSlot, TextureSource* aSource)
 {
   SetPSTextures(aSlot, 1, &aSource);
 }
 
-static inline SamplerMode
-FilterToSamplerMode(gfx::SamplingFilter aFilter)
-{
-  switch (aFilter) {
-  case gfx::SamplingFilter::POINT:
-    return SamplerMode::Point;
-  case gfx::SamplingFilter::LINEAR:
-  case gfx::SamplingFilter::GOOD:
-    return SamplerMode::LinearClamp;
-  default:
-    MOZ_ASSERT_UNREACHABLE("Unknown sampler mode");
-    return SamplerMode::LinearClamp;
-  }
-}
-
 void
 MLGDevice::SetSamplerMode(uint32_t aIndex, gfx::SamplingFilter aFilter)
 {
   SetSamplerMode(aIndex, FilterToSamplerMode(aFilter));
 }
 
 bool
 MLGDevice::Fail(const nsCString& aFailureId, const nsCString* aMessage)
--- a/gfx/layers/mlgpu/MLGDeviceTypes.h
+++ b/gfx/layers/mlgpu/MLGDeviceTypes.h
@@ -2,16 +2,17 @@
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
 #define mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
 
 #include "mozilla/TypedEnumBits.h"
+#include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 namespace layers {
 
 enum class MLGUsage
 {
   // GPU read-only, CPU write once on creation and read/write never.
   Immutable,
@@ -42,16 +43,18 @@ enum class MLGBufferType : uint32_t
 };
 
 enum class SamplerMode
 {
   // Linear filter, clamped to border.
   LinearClamp = 0,
   // Linear filter, clamped to transparent pixels.
   LinearClampToZero,
+  // Linear filter, wrap edges.
+  LinearRepeat,
   // Point filter, clamped to border.
   Point,
   MaxModes
 };
 
 enum class MLGBlendState
 {
   Copy = 0,
@@ -99,12 +102,27 @@ enum class MLGRenderTargetFlags : uint32
   ZBuffer = (1 << 0)
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MLGRenderTargetFlags);
 
 // NVIDIA drivers crash when we supply too many rects to ClearView - it
 // seems to cause a stack overflow >= 20 rects. We cap to 12 for now.
 static const size_t kMaxClearViewRects = 12;
 
+static inline SamplerMode
+FilterToSamplerMode(gfx::SamplingFilter aFilter)
+{
+  switch (aFilter) {
+  case gfx::SamplingFilter::POINT:
+    return SamplerMode::Point;
+  case gfx::SamplingFilter::LINEAR:
+  case gfx::SamplingFilter::GOOD:
+    return SamplerMode::LinearClamp;
+  default:
+    MOZ_ASSERT_UNREACHABLE("Unknown sampler mode");
+    return SamplerMode::LinearClamp;
+  }
+}
+
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
--- a/gfx/layers/mlgpu/PaintedLayerMLGPU.h
+++ b/gfx/layers/mlgpu/PaintedLayerMLGPU.h
@@ -3,16 +3,17 @@
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_PAINTEDLAYERMLGPU_H
 #define MOZILLA_GFX_PAINTEDLAYERMLGPU_H
 
 #include "LayerManagerMLGPU.h"
 #include "mozilla/layers/ContentHost.h"
+#include "MLGDeviceTypes.h"
 #include "nsRegionFwd.h"
 #include <functional>
 
 namespace mozilla {
 namespace layers {
 
 class PaintedLayerMLGPU final
   : public PaintedLayer,
@@ -44,16 +45,24 @@ public:
   }
   TextureSource* GetTextureOnWhite() const {
     MOZ_ASSERT(HasComponentAlpha());
     return mTextureOnWhite;
   }
   ContentHostTexture* GetContentHost() const {
     return mHost;
   }
+  SamplerMode GetSamplerMode() {
+    // Note that when resamping, we must break the texture coordinates into
+    // no-repeat rects. When we have simple integer translations we can
+    // simply wrap around the edge of the buffer texture.
+    return MayResample()
+           ? SamplerMode::LinearClamp
+           : SamplerMode::LinearRepeat;
+  }
 
   // This can return a different region than GetShadowVisibleRegion or
   // GetLocalVisibleRegion, since we make sure to clamp it to the
   // texture size and account for resampling.
   nsIntRegion GetRenderRegion();
 
   MOZ_LAYER_DECL_NAME("PaintedLayerMLGPU", TYPE_PAINTED)
 
--- a/gfx/layers/mlgpu/RenderPassMLGPU.cpp
+++ b/gfx/layers/mlgpu/RenderPassMLGPU.cpp
@@ -446,31 +446,34 @@ TexturedRenderPass::TexturedRenderPass(F
  : BatchRenderPass(aBuilder, aItem),
    mTextureFlags(TextureFlags::NO_FLAGS)
 {
 }
 
 TexturedRenderPass::Info::Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer)
  : item(aItem),
    textureSize(aLayer->GetTexture()->GetSize()),
-   destOrigin(aLayer->GetContentHost()->GetOriginOffset())
+   destOrigin(aLayer->GetContentHost()->GetOriginOffset()),
+   decomposeIntoNoRepeatRects(aLayer->MayResample())
 {
 }
 
 TexturedRenderPass::Info::Info(const ItemInfo& aItem, TexturedLayerMLGPU* aLayer)
  : item(aItem),
    textureSize(aLayer->GetTexture()->GetSize()),
-   scale(aLayer->GetPictureScale())
+   scale(aLayer->GetPictureScale()),
+   decomposeIntoNoRepeatRects(false)
 {
 }
 
 TexturedRenderPass::Info::Info(const ItemInfo& aItem, ContainerLayerMLGPU* aLayer)
  : item(aItem),
    textureSize(aLayer->GetTargetSize()),
-   destOrigin(aLayer->GetTargetOffset())
+   destOrigin(aLayer->GetTargetOffset()),
+   decomposeIntoNoRepeatRects(false)
 {
 }
 
 bool
 TexturedRenderPass::AddItem(Txn& aTxn,
                             const Info& aInfo,
                             const Rect& aDrawRect)
 {
@@ -530,77 +533,86 @@ TexturedRenderPass::AddClippedItem(Txn& 
     aDrawRect.Height() * yScale);
 
   Rect textureCoords = TextureRectToCoords(textureRect, aInfo.textureSize);
   if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
     textureCoords.y = 1.0 - textureCoords.y;
     textureCoords.SetHeight(-textureCoords.Height());
   }
 
-  Rect layerRects[4];
-  Rect textureRects[4];
-  size_t numRects =
-    DecomposeIntoNoRepeatRects(aDrawRect, textureCoords, &layerRects, &textureRects);
-
-  for (size_t i = 0; i < numRects; i++) {
-    TexturedTraits traits(aInfo.item, layerRects[i], textureRects[i]);
+  if (!aInfo.decomposeIntoNoRepeatRects) {
+    // Fast, normal case, we can use the texture coordinates as-s and the caller
+    // will use a repeat sampler if needed.
+    TexturedTraits traits(aInfo.item, aDrawRect, textureCoords);
     if (!aTxn.Add(traits)) {
       return false;
     }
+  } else {
+    Rect layerRects[4];
+    Rect textureRects[4];
+    size_t numRects =
+      DecomposeIntoNoRepeatRects(aDrawRect, textureCoords, &layerRects, &textureRects);
+
+    for (size_t i = 0; i < numRects; i++) {
+      TexturedTraits traits(aInfo.item, layerRects[i], textureRects[i]);
+      if (!aTxn.Add(traits)) {
+        return false;
+      }
+    }
   }
   return true;
 }
 
 SingleTexturePass::SingleTexturePass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : TexturedRenderPass(aBuilder, aItem),
    mOpacity(1.0f)
 {
   SetDefaultGeometry(aItem);
 }
 
 bool
 SingleTexturePass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem)
 {
   RefPtr<TextureSource> texture;
 
-  gfx::SamplingFilter filter;
+  SamplerMode sampler;
   TextureFlags flags = TextureFlags::NO_FLAGS;
   if (PaintedLayerMLGPU* paintedLayer = aLayer->AsPaintedLayerMLGPU()) {
     if (paintedLayer->HasComponentAlpha()) {
       return false;
     }
     texture = paintedLayer->GetTexture();
-    filter = SamplingFilter::LINEAR;
+    sampler = paintedLayer->GetSamplerMode();
   } else if (TexturedLayerMLGPU* texLayer = aLayer->AsTexturedLayerMLGPU()) {
     texture = texLayer->GetTexture();
-    filter = texLayer->GetSamplingFilter();
+    sampler = FilterToSamplerMode(texLayer->GetSamplingFilter());
     TextureHost* host = texLayer->GetImageHost()->CurrentTextureHost();
     flags = host->GetFlags();
   } else {
     return false;
   }
 
   // We should not assign a texture-based layer to tiles if it has no texture.
   MOZ_ASSERT(texture);
 
   float opacity = aLayer->GetComputedOpacity();
   if (mTexture) {
     if (texture != mTexture) {
       return false;
     }
-    if (mFilter != filter) {
+    if (mSamplerMode != sampler) {
       return false;
     }
     if (mOpacity != opacity) {
       return false;
     }
     // Note: premultiplied, origin-bottom-left are already implied by the texture source.
   } else {
     mTexture = texture;
-    mFilter = filter;
+    mSamplerMode = sampler;
     mOpacity = opacity;
     mTextureFlags = flags;
   }
 
   Txn txn(this);
 
   if (PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU()) {
     Info info(aItem, layer);
@@ -633,17 +645,17 @@ SingleTexturePass::SetupPipeline()
 
   if (mGeometry == GeometryMode::UnitQuad) {
     mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
   } else {
     mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
   }
 
   mDevice->SetPSTexture(0, mTexture);
-  mDevice->SetSamplerMode(kDefaultSamplerSlot, mFilter);
+  mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
   switch (mTexture.get()->GetFormat()) {
     case SurfaceFormat::B8G8R8A8:
     case SurfaceFormat::R8G8B8A8:
       if (mGeometry == GeometryMode::UnitQuad)
         mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGBA);
       else
         mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGBA);
       break;
@@ -706,17 +718,17 @@ ComponentAlphaPass::SetupPipeline()
   if (mGeometry == GeometryMode::UnitQuad) {
     mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
     mDevice->SetPixelShader(PixelShaderID::ComponentAlphaQuad);
   } else {
     mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
     mDevice->SetPixelShader(PixelShaderID::ComponentAlphaVertex);
   }
 
-  mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp);
+  mDevice->SetSamplerMode(kDefaultSamplerSlot, mAssignedLayer->GetSamplerMode());
   mDevice->SetPSTextures(0, 2, textures);
 }
 
 VideoRenderPass::VideoRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : TexturedRenderPass(aBuilder, aItem),
    mOpacity(1.0f)
 {
   SetDefaultGeometry(aItem);
@@ -728,36 +740,36 @@ VideoRenderPass::AddToPass(LayerMLGPU* a
   ImageLayerMLGPU* layer = aLayer->AsImageLayerMLGPU();
   if (!layer) {
     return false;
   }
 
   RefPtr<TextureHost> host = layer->GetImageHost()->CurrentTextureHost();
   RefPtr<TextureSource> source = layer->GetTexture();
   float opacity = layer->GetComputedOpacity();
-  SamplingFilter filter = layer->GetSamplingFilter();
+  SamplerMode sampler = FilterToSamplerMode(layer->GetSamplingFilter());
 
   if (mHost) {
     if (mHost != host) {
       return false;
     }
     if (mTexture != source) {
       return false;
     }
     if (mOpacity != opacity) {
       return false;
     }
-    if (mFilter != filter) {
+    if (mSamplerMode != sampler) {
       return false;
     }
   } else {
     mHost = host;
     mTexture = source;
     mOpacity = opacity;
-    mFilter = filter;
+    mSamplerMode = sampler;
   }
   MOZ_ASSERT(!mTexture->AsBigImageIterator());
   MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED));
   MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT));
 
   Txn txn(this);
 
   Info info(aItem, layer);
@@ -814,17 +826,17 @@ VideoRenderPass::SetupPipeline()
       mDevice->SetPixelShader(PixelShaderID::TexturedVertexNV12);
     mDevice->SetPSTexturesNV12(0, mTexture);
     break;
   default:
     MOZ_ASSERT_UNREACHABLE("Unknown video format");
     break;
   }
 
-  mDevice->SetSamplerMode(kDefaultSamplerSlot, mFilter);
+  mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
   mDevice->SetPSConstantBuffer(1, ps1);
 }
 
 RenderViewPass::RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
  : TexturedRenderPass(aBuilder, aItem),
    mParentView(nullptr)
 {
   mAssignedLayer = aItem.layer->AsContainerLayerMLGPU();
--- a/gfx/layers/mlgpu/RenderPassMLGPU.h
+++ b/gfx/layers/mlgpu/RenderPassMLGPU.h
@@ -296,16 +296,17 @@ protected:
     Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer);
     Info(const ItemInfo& aItem, TexturedLayerMLGPU* aLayer);
     Info(const ItemInfo& aItem, ContainerLayerMLGPU* aLayer);
 
     const ItemInfo& item;
     gfx::IntSize textureSize;
     gfx::Point destOrigin;
     Maybe<gfx::Size> scale;
+    bool decomposeIntoNoRepeatRects;
   };
 
   // Add a set of draw rects based on a visible region. The texture size and
   // scaling factor are used to compute uv-coordinates.
   //
   // The origin is the offset from the draw rect to the layer bounds. You can
   // also think of it as the translation from layer space into texture space,
   // pre-scaling. For example, ImageLayers use the texture bounds as their
@@ -395,17 +396,17 @@ private:
   void SetupPipeline() override;
   float GetOpacity() const override {
     return mOpacity;
   }
   Maybe<MLGBlendState> GetBlendState() const override;
 
 private:
   RefPtr<TextureSource> mTexture;
-  gfx::SamplingFilter mFilter;
+  SamplerMode mSamplerMode;
   float mOpacity;
 };
 
 class ComponentAlphaPass final : public TexturedRenderPass
 {
 public:
   explicit ComponentAlphaPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
 
@@ -441,17 +442,17 @@ private:
   void SetupPipeline() override;
   float GetOpacity() const override {
     return mOpacity;
   }
 
 private:
   RefPtr<TextureHost> mHost;
   RefPtr<TextureSource> mTexture;
-  gfx::SamplingFilter mFilter;
+  SamplerMode mSamplerMode;
   float mOpacity;
 };
 
 class RenderViewPass final : public TexturedRenderPass
 {
 public:
   RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem);