tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Compositor.cpp (9274B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/layers/Compositor.h"
      8 #include "mozilla/layers/CompositionRecorder.h"
      9 #include "base/message_loop.h"  // for MessageLoop
     10 #include "mozilla/gfx/Types.h"
     11 #include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
     12 #include "mozilla/layers/Diagnostics.h"
     13 #include "mozilla/layers/Effects.h"  // for Effect, EffectChain, etc
     14 #include "mozilla/layers/TextureClient.h"
     15 #include "mozilla/layers/TextureHost.h"
     16 #include "mozilla/layers/CompositorThread.h"
     17 #include "mozilla/mozalloc.h"  // for operator delete, etc
     18 #include "GeckoProfiler.h"
     19 #include "gfx2DGlue.h"
     20 #include "gfxUtils.h"
     21 #include "nsAppRunner.h"
     22 
     23 namespace mozilla::layers {
     24 
     25 class CompositorRecordedFrame final : public RecordedFrame {
     26 public:
     27  CompositorRecordedFrame(const TimeStamp& aTimeStamp,
     28                          RefPtr<AsyncReadbackBuffer>&& aBuffer)
     29      : RecordedFrame(aTimeStamp), mBuffer(aBuffer) {}
     30 
     31  virtual already_AddRefed<gfx::DataSourceSurface> GetSourceSurface() override {
     32    if (mSurface) {
     33      return do_AddRef(mSurface);
     34    }
     35 
     36    gfx::IntSize size = mBuffer->GetSize();
     37 
     38    mSurface = gfx::Factory::CreateDataSourceSurface(
     39        size, gfx::SurfaceFormat::B8G8R8A8,
     40        /* aZero = */ false);
     41 
     42    if (!mBuffer->MapAndCopyInto(mSurface, size)) {
     43      mSurface = nullptr;
     44      return nullptr;
     45    }
     46 
     47    return do_AddRef(mSurface);
     48  }
     49 
     50 private:
     51  RefPtr<AsyncReadbackBuffer> mBuffer;
     52  RefPtr<gfx::DataSourceSurface> mSurface;
     53 };
     54 
     55 Compositor::Compositor(widget::CompositorWidget* aWidget)
     56    : mWidget(aWidget),
     57      mIsDestroyed(false),
     58 #if defined(MOZ_WIDGET_ANDROID)
     59      // If the default color isn't white for Fennec, there is a black
     60      // flash before the first page of a tab is loaded.
     61      mClearColor(gfx::ToDeviceColor(gfx::sRGBColor::OpaqueWhite()))
     62 #else
     63      mClearColor(gfx::DeviceColor())
     64 #endif
     65 {
     66 }
     67 
     68 Compositor::~Compositor() {}
     69 
     70 void Compositor::Destroy() {
     71  mWidget = nullptr;
     72 
     73  TextureSourceProvider::Destroy();
     74  mIsDestroyed = true;
     75 }
     76 
     77 void Compositor::EndFrame() { mLastCompositionEndTime = TimeStamp::Now(); }
     78 
     79 nsTArray<TexturedVertex> TexturedTrianglesToVertexArray(
     80    const nsTArray<gfx::TexturedTriangle>& aTriangles) {
     81  const auto VertexFromPoints = [](const gfx::Point& p, const gfx::Point& t) {
     82    return TexturedVertex{{p.x, p.y}, {t.x, t.y}};
     83  };
     84 
     85  nsTArray<TexturedVertex> vertices;
     86 
     87  for (const gfx::TexturedTriangle& t : aTriangles) {
     88    vertices.AppendElement(VertexFromPoints(t.p1, t.textureCoords.p1));
     89    vertices.AppendElement(VertexFromPoints(t.p2, t.textureCoords.p2));
     90    vertices.AppendElement(VertexFromPoints(t.p3, t.textureCoords.p3));
     91  }
     92 
     93  return vertices;
     94 }
     95 
     96 static float WrapTexCoord(float v) {
     97  // This should return values in range [0, 1.0)
     98  return v - floorf(v);
     99 }
    100 
    101 static void SetRects(size_t n, decomposedRectArrayT* aLayerRects,
    102                     decomposedRectArrayT* aTextureRects, float x0, float y0,
    103                     float x1, float y1, float tx0, float ty0, float tx1,
    104                     float ty1, bool flip_y) {
    105  if (flip_y) {
    106    std::swap(ty0, ty1);
    107  }
    108  (*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0);
    109  (*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
    110 }
    111 
    112 #ifdef DEBUG
    113 static inline bool FuzzyEqual(float a, float b) {
    114  return fabs(a - b) < 0.0001f;
    115 }
    116 static inline bool FuzzyLTE(float a, float b) { return a <= b + 0.0001f; }
    117 #endif
    118 
    119 size_t DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
    120                                  const gfx::Rect& aTexCoordRect,
    121                                  decomposedRectArrayT* aLayerRects,
    122                                  decomposedRectArrayT* aTextureRects) {
    123  gfx::Rect texCoordRect = aTexCoordRect;
    124 
    125  // If the texture should be flipped, it will have negative height. Detect that
    126  // here and compensate for it. We will flip each rect as we emit it.
    127  bool flipped = false;
    128  if (texCoordRect.Height() < 0) {
    129    flipped = true;
    130    texCoordRect.MoveByY(texCoordRect.Height());
    131    texCoordRect.SetHeight(-texCoordRect.Height());
    132  }
    133 
    134  // Wrap the texture coordinates so they are within [0,1] and cap width/height
    135  // at 1. We rely on this below.
    136  texCoordRect = gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect.X()),
    137                                      WrapTexCoord(texCoordRect.Y())),
    138                           gfx::Size(std::min(texCoordRect.Width(), 1.0f),
    139                                     std::min(texCoordRect.Height(), 1.0f)));
    140 
    141  NS_ASSERTION(
    142      texCoordRect.X() >= 0.0f && texCoordRect.X() <= 1.0f &&
    143          texCoordRect.Y() >= 0.0f && texCoordRect.Y() <= 1.0f &&
    144          texCoordRect.Width() >= 0.0f && texCoordRect.Width() <= 1.0f &&
    145          texCoordRect.Height() >= 0.0f && texCoordRect.Height() <= 1.0f &&
    146          texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
    147          texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
    148      "We just wrapped the texture coordinates, didn't we?");
    149 
    150  // Get the top left and bottom right points of the rectangle. Note that
    151  // tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
    152  gfx::Point tl = texCoordRect.TopLeft();
    153  gfx::Point br = texCoordRect.BottomRight();
    154 
    155  NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f && tl.y >= 0.0f && tl.y <= 1.0f &&
    156                   br.x >= tl.x && br.x <= 2.0f && br.y >= tl.y &&
    157                   br.y <= 2.0f && FuzzyLTE(br.x - tl.x, 1.0f) &&
    158                   FuzzyLTE(br.y - tl.y, 1.0f),
    159               "Somehow generated invalid texture coordinates");
    160 
    161  // Then check if we wrap in either the x or y axis.
    162  bool xwrap = br.x > 1.0f;
    163  bool ywrap = br.y > 1.0f;
    164 
    165  // If xwrap is false, the texture will be sampled from tl.x .. br.x.
    166  // If xwrap is true, then it will be split into tl.x .. 1.0, and
    167  // 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
    168  // rectangle is also split appropriately, according to the calculated
    169  // xmid/ymid values.
    170  if (!xwrap && !ywrap) {
    171    SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), aRect.XMost(),
    172             aRect.YMost(), tl.x, tl.y, br.x, br.y, flipped);
    173    return 1;
    174  }
    175 
    176  // If we are dealing with wrapping br.x and br.y are greater than 1.0 so
    177  // wrap them here as well.
    178  br = gfx::Point(xwrap ? WrapTexCoord(br.x.value) : br.x.value,
    179                  ywrap ? WrapTexCoord(br.y.value) : br.y.value);
    180 
    181  // If we wrap around along the x axis, we will draw first from
    182  // tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
    183  // The same applies for the Y axis. The midpoints we calculate here are
    184  // only valid if we actually wrap around.
    185  GLfloat xmid =
    186      aRect.X() + (1.0f - tl.x) / texCoordRect.Width() * aRect.Width();
    187  GLfloat ymid =
    188      aRect.Y() + (1.0f - tl.y) / texCoordRect.Height() * aRect.Height();
    189 
    190  // Due to floating-point inaccuracy, we have to use XMost()-x and YMost()-y
    191  // to calculate width and height, respectively, to ensure that size will
    192  // remain consistent going from absolute to relative and back again.
    193  NS_ASSERTION(
    194      !xwrap || (xmid >= aRect.X() && xmid <= aRect.XMost() &&
    195                 FuzzyEqual((xmid - aRect.X()) + (aRect.XMost() - xmid),
    196                            aRect.XMost() - aRect.X())),
    197      "xmid should be within [x,XMost()] and the wrapped rect should have the "
    198      "same width");
    199  NS_ASSERTION(
    200      !ywrap || (ymid >= aRect.Y() && ymid <= aRect.YMost() &&
    201                 FuzzyEqual((ymid - aRect.Y()) + (aRect.YMost() - ymid),
    202                            aRect.YMost() - aRect.Y())),
    203      "ymid should be within [y,YMost()] and the wrapped rect should have the "
    204      "same height");
    205 
    206  if (!xwrap && ywrap) {
    207    SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), aRect.XMost(),
    208             ymid, tl.x, tl.y, br.x, 1.0f, flipped);
    209    SetRects(1, aLayerRects, aTextureRects, aRect.X(), ymid, aRect.XMost(),
    210             aRect.YMost(), tl.x, 0.0f, br.x, br.y, flipped);
    211    return 2;
    212  }
    213 
    214  if (xwrap && !ywrap) {
    215    SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), xmid,
    216             aRect.YMost(), tl.x, tl.y, 1.0f, br.y, flipped);
    217    SetRects(1, aLayerRects, aTextureRects, xmid, aRect.Y(), aRect.XMost(),
    218             aRect.YMost(), 0.0f, tl.y, br.x, br.y, flipped);
    219    return 2;
    220  }
    221 
    222  SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), xmid, ymid,
    223           tl.x, tl.y, 1.0f, 1.0f, flipped);
    224  SetRects(1, aLayerRects, aTextureRects, xmid, aRect.Y(), aRect.XMost(), ymid,
    225           0.0f, tl.y, br.x, 1.0f, flipped);
    226  SetRects(2, aLayerRects, aTextureRects, aRect.X(), ymid, xmid, aRect.YMost(),
    227           tl.x, 0.0f, 1.0f, br.y, flipped);
    228  SetRects(3, aLayerRects, aTextureRects, xmid, ymid, aRect.XMost(),
    229           aRect.YMost(), 0.0f, 0.0f, br.x, br.y, flipped);
    230  return 4;
    231 }
    232 
    233 bool Compositor::ShouldRecordFrames() const {
    234  return profiler_feature_active(ProfilerFeature::Screenshots) || mRecordFrames;
    235 }
    236 
    237 }  // namespace mozilla::layers