tor-browser

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

WebGLTexelConversions.cpp (21172B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "WebGLTexelConversions.h"
      6 
      7 #include "GLBlitHelper.h"
      8 #include "WebGLContext.h"
      9 
     10 namespace mozilla {
     11 
     12 using namespace WebGLTexelConversions;
     13 
     14 namespace {
     15 
     16 /** @class WebGLImageConverter
     17 *
     18 * This class is just a helper to implement WebGLContext::ConvertImage below.
     19 *
     20 * Design comments:
     21 *
     22 * WebGLContext::ConvertImage has to handle hundreds of format conversion paths.
     23 * It is important to minimize executable code size here. Instead of passing
     24 * around a large number of function parameters hundreds of times, we create a
     25 * WebGLImageConverter object once, storing these parameters, and then we call
     26 * the run() method on it.
     27 */
     28 class WebGLImageConverter {
     29  const size_t mWidth, mHeight;
     30  const void* const mSrcStart;
     31  void* const mDstStart;
     32  const ptrdiff_t mSrcStride, mDstStride;
     33  bool mAlreadyRun;
     34  bool mSuccess;
     35 
     36  /*
     37   * Returns sizeof(texel)/sizeof(type). The point is that we will iterate over
     38   * texels with typed pointers and this value will tell us by how much we need
     39   * to increment these pointers to advance to the next texel.
     40   */
     41  template <WebGLTexelFormat Format>
     42  static size_t NumElementsPerTexelForFormat() {
     43    switch (Format) {
     44      case WebGLTexelFormat::A8:
     45      case WebGLTexelFormat::A16F:
     46      case WebGLTexelFormat::A32F:
     47      case WebGLTexelFormat::R8:
     48      case WebGLTexelFormat::R16F:
     49      case WebGLTexelFormat::R32F:
     50      case WebGLTexelFormat::RGB565:
     51      case WebGLTexelFormat::RGB11F11F10F:
     52      case WebGLTexelFormat::RGBA4444:
     53      case WebGLTexelFormat::RGBA5551:
     54        return 1;
     55      case WebGLTexelFormat::RA8:
     56      case WebGLTexelFormat::RA16F:
     57      case WebGLTexelFormat::RA32F:
     58      case WebGLTexelFormat::RG8:
     59      case WebGLTexelFormat::RG16F:
     60      case WebGLTexelFormat::RG32F:
     61        return 2;
     62      case WebGLTexelFormat::RGB8:
     63      case WebGLTexelFormat::RGB16F:
     64      case WebGLTexelFormat::RGB32F:
     65        return 3;
     66      case WebGLTexelFormat::RGBA8:
     67      case WebGLTexelFormat::RGBA16F:
     68      case WebGLTexelFormat::RGBA32F:
     69      case WebGLTexelFormat::BGRX8:
     70      case WebGLTexelFormat::BGRA8:
     71        return 4;
     72      default:
     73        MOZ_ASSERT(false, "Unknown texel format. Coding mistake?");
     74        return 0;
     75    }
     76  }
     77 
     78  /*
     79   * This is the completely format-specific templatized conversion function,
     80   * that will be instantiated hundreds of times for all different combinations.
     81   * It is important to avoid generating useless code here. In particular, many
     82   * instantiations of this function template will never be called, so we try
     83   * to return immediately in these cases to allow the compiler to avoid
     84   * generating useless code.
     85   */
     86  template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat,
     87            WebGLTexelPremultiplicationOp PremultiplicationOp,
     88            dom::PredefinedColorSpace SrcColorSpace,
     89            dom::PredefinedColorSpace DstColorSpace>
     90  void run() {
     91    // check for never-called cases. We early-return to allow the compiler
     92    // to avoid generating this code. It would be tempting to abort() instead,
     93    // as returning early does leave the destination surface with uninitialized
     94    // data, but that would not allow the compiler to avoid generating this
     95    // code. So instead, we return early, so Success() will return false, and
     96    // the caller must check that and abort in that case. See
     97    // WebGLContext::ConvertImage.
     98 
     99    bool sameColorSpace = (SrcColorSpace == DstColorSpace);
    100 
    101    if (SrcFormat == DstFormat &&
    102        PremultiplicationOp == WebGLTexelPremultiplicationOp::None &&
    103        sameColorSpace) {
    104      // Should have used a fast exit path earlier, rather than entering this
    105      // function. we explicitly return here to allow the compiler to avoid
    106      // generating this code
    107      return;
    108    }
    109 
    110    // Only textures uploaded from DOM elements or ImageData can allow DstFormat
    111    // != SrcFormat. DOM elements can only give BGRA8, BGRX8, A8, RGB565
    112    // formats. See DOMElementToImageSurface. ImageData is always RGBA8. So all
    113    // other SrcFormat will always satisfy DstFormat==SrcFormat, so we can avoid
    114    // compiling the code for all the unreachable paths.
    115    const bool CanSrcFormatComeFromDOMElementOrImageData =
    116        SrcFormat == WebGLTexelFormat::BGRA8 ||
    117        SrcFormat == WebGLTexelFormat::BGRX8 ||
    118        SrcFormat == WebGLTexelFormat::A8 ||
    119        SrcFormat == WebGLTexelFormat::RGB565 ||
    120        SrcFormat == WebGLTexelFormat::RGBA8;
    121    if (!CanSrcFormatComeFromDOMElementOrImageData && SrcFormat != DstFormat) {
    122      return;
    123    }
    124 
    125    // Likewise, only textures uploaded from DOM elements or ImageData can
    126    // possibly have to be unpremultiplied.
    127    if (!CanSrcFormatComeFromDOMElementOrImageData &&
    128        PremultiplicationOp == WebGLTexelPremultiplicationOp::Unpremultiply) {
    129      return;
    130    }
    131 
    132    // there is no point in premultiplication/unpremultiplication
    133    // in the following cases:
    134    //  - the source format has no alpha
    135    //  - the source format has no color
    136    //  - the destination format has no color
    137    if (!HasAlpha(SrcFormat) || !HasColor(SrcFormat) || !HasColor(DstFormat)) {
    138      if (PremultiplicationOp != WebGLTexelPremultiplicationOp::None) {
    139        return;
    140      }
    141    }
    142 
    143    // end of early return cases.
    144 
    145    MOZ_ASSERT(!mAlreadyRun, "converter should be run only once!");
    146    mAlreadyRun = true;
    147 
    148    // gather some compile-time meta-data about the formats at hand.
    149 
    150    using SrcType = typename DataTypeForFormat<SrcFormat>::Type;
    151    using DstType = typename DataTypeForFormat<DstFormat>::Type;
    152 
    153    const WebGLTexelFormat IntermediateSrcFormat =
    154        IntermediateFormat<SrcFormat>::Value;
    155    const WebGLTexelFormat IntermediateDstFormat =
    156        IntermediateFormat<DstFormat>::Value;
    157    using IntermediateSrcType =
    158        typename DataTypeForFormat<IntermediateSrcFormat>::Type;
    159    using IntermediateDstType =
    160        typename DataTypeForFormat<IntermediateDstFormat>::Type;
    161 
    162    const size_t NumElementsPerSrcTexel =
    163        NumElementsPerTexelForFormat<SrcFormat>();
    164    const size_t NumElementsPerDstTexel =
    165        NumElementsPerTexelForFormat<DstFormat>();
    166    const size_t MaxElementsPerTexel = 4;
    167    MOZ_ASSERT(NumElementsPerSrcTexel <= MaxElementsPerTexel,
    168               "unhandled format");
    169    MOZ_ASSERT(NumElementsPerDstTexel <= MaxElementsPerTexel,
    170               "unhandled format");
    171 
    172    // we assume that the strides are multiples of the sizeof of respective
    173    // types. this assumption will allow us to iterate over src and dst images
    174    // using typed pointers, e.g. uint8_t* or uint16_t* or float*, instead of
    175    // untyped pointers. So this assumption allows us to write cleaner and safer
    176    // code, but it might not be true forever and if it eventually becomes
    177    // wrong, we'll have to revert to always iterating using uint8_t* pointers
    178    // regardless of the types at hand.
    179    MOZ_ASSERT(
    180        mSrcStride % sizeof(SrcType) == 0 && mDstStride % sizeof(DstType) == 0,
    181        "Unsupported: texture stride is not a multiple of sizeof(type)");
    182    const ptrdiff_t srcStrideInElements =
    183        mSrcStride / static_cast<ptrdiff_t>(sizeof(SrcType));
    184    const ptrdiff_t dstStrideInElements =
    185        mDstStride / static_cast<ptrdiff_t>(sizeof(DstType));
    186    // Pop quiz: What's `ptrdiff_t(-16) / sizeof(int32_t)`?
    187    // Did you guess +4611686018427387900?
    188    MOZ_ASSERT(bool(srcStrideInElements < 0) == bool(mSrcStride < 0));
    189    MOZ_ASSERT(bool(dstStrideInElements < 0) == bool(mDstStride < 0));
    190 
    191    const SrcType* srcRowStart = static_cast<const SrcType*>(mSrcStart);
    192    DstType* dstRowStart = static_cast<DstType*>(mDstStart);
    193 
    194    static auto inColorSpace2 = gfx::ToColorSpace2(SrcColorSpace);
    195    static auto outColorSpace2 = gfx::ToColorSpace2(DstColorSpace);
    196 
    197    auto inColorProfile = gl::GLBlitHelper::ToColorProfileDesc(inColorSpace2);
    198    auto outColorProfile = gl::GLBlitHelper::ToColorProfileDesc(outColorSpace2);
    199 
    200    const auto conversion = color::ColorProfileConversionDesc::From({
    201        .src = *inColorProfile,
    202        .dst = *outColorProfile,
    203    });
    204 
    205    // the loop performing the texture format conversion
    206    for (size_t i = 0; i < mHeight; ++i) {
    207      const SrcType* srcRowEnd = srcRowStart + mWidth * NumElementsPerSrcTexel;
    208      const SrcType* srcPtr = srcRowStart;
    209      DstType* dstPtr = dstRowStart;
    210      while (srcPtr != srcRowEnd) {
    211        // convert a single texel. We proceed in 4 steps: unpack the source
    212        // texel so the corresponding interchange format (e.g. unpack RGB565 to
    213        // RGBA8), do colorSpace conversion if necessary, convert the resulting
    214        // data type to the destination type (e.g. convert from RGBA8 to
    215        // RGBA32F), and finally pack the destination texel (e.g. pack RGBA32F
    216        // to RGB32F).
    217        IntermediateSrcType unpackedSrc[MaxElementsPerTexel];
    218        IntermediateDstType unpackedDst[MaxElementsPerTexel];
    219 
    220        // unpack a src texel to corresponding intermediate src format.
    221        // for example, unpack RGB565 to RGBA8
    222        unpack<SrcFormat>(srcPtr, unpackedSrc);
    223 
    224        if (!sameColorSpace) {
    225          // do colorSpace conversion, which leaves alpha untouched
    226          float srcAsFloat[MaxElementsPerTexel];
    227          convertType(unpackedSrc, srcAsFloat);
    228          auto inTexelVec =
    229              color::vec3({srcAsFloat[0], srcAsFloat[1], srcAsFloat[2]});
    230          auto outTexelVec = conversion.DstFromSrc(inTexelVec);
    231          srcAsFloat[0] = outTexelVec[0];
    232          srcAsFloat[1] = outTexelVec[1];
    233          srcAsFloat[2] = outTexelVec[2];
    234          convertType(srcAsFloat, unpackedSrc);
    235        }
    236 
    237        // convert the data type to the destination type, if needed.
    238        // for example, convert RGBA8 to RGBA32F
    239        convertType(unpackedSrc, unpackedDst);
    240        // pack the destination texel.
    241        // for example, pack RGBA32F to RGB32F
    242        pack<DstFormat, PremultiplicationOp>(unpackedDst, dstPtr);
    243 
    244        srcPtr += NumElementsPerSrcTexel;
    245        dstPtr += NumElementsPerDstTexel;
    246      }
    247      srcRowStart += srcStrideInElements;
    248      dstRowStart += dstStrideInElements;
    249    }
    250 
    251    mSuccess = true;
    252  }
    253 
    254  template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat,
    255            WebGLTexelPremultiplicationOp PremultiplicationOp,
    256            dom::PredefinedColorSpace SrcColorSpace>
    257  void run(dom::PredefinedColorSpace dstColorSpace) {
    258 #define WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE(DstColorSpace)            \
    259  case DstColorSpace:                                                    \
    260    return run<SrcFormat, DstFormat, PremultiplicationOp, SrcColorSpace, \
    261               DstColorSpace>();
    262 
    263    switch (dstColorSpace) {
    264      WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE(dom::PredefinedColorSpace::Srgb)
    265      WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE(
    266          dom::PredefinedColorSpace::Display_p3)
    267      default:
    268        MOZ_ASSERT(false, "unhandled case. Coding mistake?");
    269    }
    270 
    271 #undef WEBGLIMAGECONVERTER_CASE_DSTCOLORSPACE
    272  }
    273 
    274  template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat,
    275            WebGLTexelPremultiplicationOp PremultiplicationOp>
    276  void run(dom::PredefinedColorSpace srcColorSpace,
    277           dom::PredefinedColorSpace dstColorSpace) {
    278 #define WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE(SrcColorSpace)             \
    279  case SrcColorSpace:                                                     \
    280    return run<SrcFormat, DstFormat, PremultiplicationOp, SrcColorSpace>( \
    281        dstColorSpace);
    282 
    283    switch (srcColorSpace) {
    284      WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE(dom::PredefinedColorSpace::Srgb)
    285      WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE(
    286          dom::PredefinedColorSpace::Display_p3)
    287      default:
    288        MOZ_ASSERT(false, "unhandled case. Coding mistake?");
    289    }
    290 
    291 #undef WEBGLIMAGECONVERTER_CASE_SRCCOLORSPACE
    292  }
    293 
    294  template <WebGLTexelFormat SrcFormat, WebGLTexelFormat DstFormat>
    295  void run(WebGLTexelPremultiplicationOp premultiplicationOp,
    296           dom::PredefinedColorSpace srcColorSpace,
    297           dom::PredefinedColorSpace dstColorSpace) {
    298 #define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \
    299  case PremultiplicationOp:                                               \
    300    return run<SrcFormat, DstFormat, PremultiplicationOp>(srcColorSpace,  \
    301                                                          dstColorSpace);
    302 
    303    switch (premultiplicationOp) {
    304      WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(
    305          WebGLTexelPremultiplicationOp::None)
    306      WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(
    307          WebGLTexelPremultiplicationOp::Premultiply)
    308      WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(
    309          WebGLTexelPremultiplicationOp::Unpremultiply)
    310      default:
    311        MOZ_ASSERT(false, "unhandled case. Coding mistake?");
    312    }
    313 
    314 #undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP
    315  }
    316 
    317  template <WebGLTexelFormat SrcFormat>
    318  void run(WebGLTexelFormat dstFormat,
    319           WebGLTexelPremultiplicationOp premultiplicationOp,
    320           dom::PredefinedColorSpace srcColorSpace,
    321           dom::PredefinedColorSpace dstColorSpace) {
    322 #define WEBGLIMAGECONVERTER_CASE_DSTFORMAT(DstFormat)                    \
    323  case DstFormat:                                                        \
    324    return run<SrcFormat, DstFormat>(premultiplicationOp, srcColorSpace, \
    325                                     dstColorSpace);
    326 
    327    switch (dstFormat) {
    328      // 1-channel formats
    329      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A8)
    330      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A16F)
    331      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::A32F)
    332      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R8)
    333      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R16F)
    334      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::R32F)
    335      // 2-channel formats
    336      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA8)
    337      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA16F)
    338      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RA32F)
    339      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG8)
    340      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG16F)
    341      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RG32F)
    342      // 3-channel formats
    343      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB8)
    344      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB565)
    345      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB11F11F10F)
    346      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB16F)
    347      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGB32F)
    348      // 4-channel formats
    349      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA8)
    350      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA5551)
    351      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA4444)
    352      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA16F)
    353      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBA32F)
    354      // DOM element source formats
    355      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::RGBX8)
    356      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::BGRX8)
    357      WEBGLIMAGECONVERTER_CASE_DSTFORMAT(WebGLTexelFormat::BGRA8)
    358 
    359      default:
    360        MOZ_ASSERT(false, "unhandled case. Coding mistake?");
    361    }
    362 
    363 #undef WEBGLIMAGECONVERTER_CASE_DSTFORMAT
    364  }
    365 
    366 public:
    367  void run(WebGLTexelFormat srcFormat, WebGLTexelFormat dstFormat,
    368           WebGLTexelPremultiplicationOp premultiplicationOp,
    369           dom::PredefinedColorSpace srcColorSpace,
    370           dom::PredefinedColorSpace dstColorSpace) {
    371 #define WEBGLIMAGECONVERTER_CASE_SRCFORMAT(SrcFormat)                    \
    372  case SrcFormat:                                                        \
    373    return run<SrcFormat>(dstFormat, premultiplicationOp, srcColorSpace, \
    374                          dstColorSpace);
    375 
    376    switch (srcFormat) {
    377      // 1-channel formats
    378      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A8)
    379      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A16F)
    380      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::A32F)
    381      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R8)
    382      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R16F)
    383      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::R32F)
    384      // 2-channel formats
    385      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA8)
    386      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA16F)
    387      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RA32F)
    388      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RG8)
    389      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RG16F)
    390      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RG32F)
    391      // 3-channel formats
    392      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB8)
    393      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB565)
    394      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB11F11F10F)
    395      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB16F)
    396      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGB32F)
    397      // 4-channel formats
    398      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA8)
    399      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA5551)
    400      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA4444)
    401      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA16F)
    402      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBA32F)
    403      // DOM element source formats
    404      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::RGBX8)
    405      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRX8)
    406      WEBGLIMAGECONVERTER_CASE_SRCFORMAT(WebGLTexelFormat::BGRA8)
    407 
    408      default:
    409        MOZ_ASSERT(false, "unhandled case. Coding mistake?");
    410    }
    411 
    412 #undef WEBGLIMAGECONVERTER_CASE_SRCFORMAT
    413  }
    414 
    415  WebGLImageConverter(size_t width, size_t height, const void* srcStart,
    416                      void* dstStart, ptrdiff_t srcStride, ptrdiff_t dstStride)
    417      : mWidth(width),
    418        mHeight(height),
    419        mSrcStart(srcStart),
    420        mDstStart(dstStart),
    421        mSrcStride(srcStride),
    422        mDstStride(dstStride),
    423        mAlreadyRun(false),
    424        mSuccess(false) {}
    425 
    426  bool Success() const { return mSuccess; }
    427 };
    428 
    429 }  // end anonymous namespace
    430 
    431 bool ConvertImage(size_t width, size_t height, const void* srcBegin,
    432                  size_t srcStride, gl::OriginPos srcOrigin,
    433                  WebGLTexelFormat srcFormat, bool srcPremultiplied,
    434                  void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin,
    435                  WebGLTexelFormat dstFormat, bool dstPremultiplied,
    436                  dom::PredefinedColorSpace srcColorSpace,
    437                  dom::PredefinedColorSpace dstColorSpace,
    438                  bool* const out_wasTrivial) {
    439  *out_wasTrivial = true;
    440 
    441  if (srcFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion ||
    442      dstFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion) {
    443    return false;
    444  }
    445 
    446  if (!width || !height) return true;
    447 
    448  const bool shouldYFlip = (srcOrigin != dstOrigin);
    449 
    450  const bool canSkipPremult =
    451      (!HasAlpha(srcFormat) || !HasColor(srcFormat) || !HasColor(dstFormat));
    452 
    453  WebGLTexelPremultiplicationOp premultOp;
    454  if (canSkipPremult) {
    455    premultOp = WebGLTexelPremultiplicationOp::None;
    456  } else if (!srcPremultiplied && dstPremultiplied) {
    457    premultOp = WebGLTexelPremultiplicationOp::Premultiply;
    458  } else if (srcPremultiplied && !dstPremultiplied) {
    459    premultOp = WebGLTexelPremultiplicationOp::Unpremultiply;
    460  } else {
    461    premultOp = WebGLTexelPremultiplicationOp::None;
    462  }
    463 
    464  const uint8_t* srcItr = (const uint8_t*)srcBegin;
    465  const uint8_t* const srcEnd = srcItr + srcStride * height;
    466  uint8_t* dstItr = (uint8_t*)dstBegin;
    467  ptrdiff_t dstItrStride = dstStride;
    468  if (shouldYFlip) {
    469    dstItr = dstItr + dstStride * (height - 1);
    470    dstItrStride = -dstItrStride;
    471  }
    472 
    473  bool sameColorSpace = (srcColorSpace == dstColorSpace);
    474 
    475  if (srcFormat == dstFormat &&
    476      premultOp == WebGLTexelPremultiplicationOp::None && sameColorSpace) {
    477    // Fast exit path: we just have to memcpy all the rows.
    478 
    479    const auto bytesPerPixel = TexelBytesForFormat(srcFormat);
    480    const size_t bytesPerRow = bytesPerPixel * width;
    481 
    482    while (srcItr != srcEnd) {
    483      memcpy(dstItr, srcItr, bytesPerRow);
    484      srcItr += srcStride;
    485      dstItr += dstItrStride;
    486    }
    487    return true;
    488  }
    489 
    490  *out_wasTrivial = false;
    491 
    492  WebGLImageConverter converter(width, height, srcItr, dstItr, srcStride,
    493                                dstItrStride);
    494  converter.run(srcFormat, dstFormat, premultOp, srcColorSpace, dstColorSpace);
    495  if (!converter.Success()) {
    496    // the dst image may be left uninitialized, so we better not try to
    497    // continue even in release builds. This should never happen anyway,
    498    // and would be a bug in our code.
    499    MOZ_CRASH("programming mistake in WebGL texture conversions");
    500  }
    501 
    502  return true;
    503 }
    504 
    505 }  // end namespace mozilla