gfx/skia/skia/src/core/SkSpriteBlitter_RGB16.cpp
author Wes Kocher <wkocher@mozilla.com>
Wed, 10 May 2017 10:01:18 -0700
changeset 407965 ce2218406119c36a551e3faea4e192186ee46cc5
parent 407937 af6f19870b2a00759ac1d83dedc3db57213abfee
child 408167 0ded74baeaf23d7985401fe9bbabdb3d9385ac22
permissions -rw-r--r--
Backed out 9 changesets (bug 1340627) for graphical glitches a=backout Backed out changeset 0b1371055c7f (bug 1340627) Backed out changeset f152be1fadb7 (bug 1340627) Backed out changeset c691e2ab6a0c (bug 1340627) Backed out changeset 3cb4bceb8d79 (bug 1340627) Backed out changeset 026aadd76d06 (bug 1340627) Backed out changeset fdbd5d281287 (bug 1340627) Backed out changeset 75fb0d9858a9 (bug 1340627) Backed out changeset 0d4ec7d38a00 (bug 1340627) Backed out changeset af6f19870b2a (bug 1340627) MozReview-Commit-ID: 9dHr7xMZezY

/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "SkSpriteBlitter.h"
#include "SkBlitRow.h"
#include "SkTemplates.h"
#include "SkUtils.h"
#include "SkColorPriv.h"

#define D16_S32A_Opaque_Pixel(dst, sc)                                        \
do {                                                                          \
    if (sc) {                                                                 \
        *dst = SkSrcOver32To16(sc, *dst);                                     \
    }                                                                         \
} while (0)

static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc,
                                               unsigned src_scale) {
    uint16_t dc = *dst;
    unsigned sa = SkGetPackedA32(sc);
    unsigned dr, dg, db;

    if (255 == sa) {
        dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale);
        dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale);
        db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale);
    } else {
#ifdef SK_SUPPORT_LEGACY_BROKEN_LERP
        unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale);
#else
        unsigned dst_scale = SkAlphaMulInv256(sa, src_scale);
#endif
        dr = (SkPacked32ToR16(sc) * src_scale + SkGetPackedR16(dc) * dst_scale) >> 8;
        dg = (SkPacked32ToG16(sc) * src_scale + SkGetPackedG16(dc) * dst_scale) >> 8;
        db = (SkPacked32ToB16(sc) * src_scale + SkGetPackedB16(dc) * dst_scale) >> 8;
    }
    *dst = SkPackRGB16(dr, dg, db);
}

#define D16_S32A_Blend_Pixel(dst, sc, src_scale) \
    do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0)


///////////////////////////////////////////////////////////////////////////////

class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
public:
    Sprite_D16_S16_Opaque(const SkPixmap& source) : SkSpriteBlitter(source) {}

    // overrides
    void blitRect(int x, int y, int width, int height) override {
        uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y);
        const uint16_t* SK_RESTRICT src = fSource.addr16(x - fLeft, y - fTop);
        size_t dstRB = fDst.rowBytes();
        size_t srcRB = fSource.rowBytes();

        while (--height >= 0) {
            memcpy(dst, src, width << 1);
            dst = (uint16_t*)((char*)dst + dstRB);
            src = (const uint16_t*)((const char*)src + srcRB);
        }
    }
};

#define D16_S16_Blend_Pixel(dst, sc, scale)     \
    do {                                        \
        uint16_t dc = *dst;                     \
        *dst = SkBlendRGB16(sc, dc, scale);     \
    } while (0)

#define SkSPRITE_CLASSNAME                  Sprite_D16_S16_Blend
#define SkSPRITE_ARGS                       , uint8_t alpha
#define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
#define SkSPRITE_INIT                       fSrcAlpha = alpha;
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   uint16_t
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr16
#define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha255To256(fSrcAlpha);
#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, src, scale)
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

///////////////////////////////////////////////////////////////////////////////

#define D16_S4444_Opaque(dst, sc)           \
    do {                                    \
        uint16_t dc = *dst;                 \
        *dst = SkSrcOver4444To16(sc, dc);   \
    } while (0)

#define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Opaque
#define SkSPRITE_ARGS
#define SkSPRITE_FIELDS
#define SkSPRITE_INIT
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   SkPMColor16
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr16
#define SkSPRITE_PREAMBLE(srcBM, x, y)
#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Opaque(dst, src)
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

#define D16_S4444_Blend(dst, sc, scale16)           \
    do {                                            \
        uint16_t dc = *dst;                         \
        *dst = SkBlend4444To16(sc, dc, scale16);    \
    } while (0)


#define SkSPRITE_CLASSNAME                  Sprite_D16_S4444_Blend
#define SkSPRITE_ARGS                       , uint8_t alpha
#define SkSPRITE_FIELDS                     uint8_t  fSrcAlpha;
#define SkSPRITE_INIT                       fSrcAlpha = alpha;
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   uint16_t
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr16
#define SkSPRITE_PREAMBLE(srcBM, x, y)      int scale = SkAlpha15To16(fSrcAlpha);
#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S4444_Blend(dst, src, scale)
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

///////////////////////////////////////////////////////////////////////////////

#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Opaque
#define SkSPRITE_ARGS
#define SkSPRITE_FIELDS
#define SkSPRITE_INIT
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   uint8_t
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr8
#define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.ctable()->readColors()
#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Opaque_Pixel(dst, ctable[src])
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8A_Blend
#define SkSPRITE_ARGS                       , uint8_t alpha
#define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
#define SkSPRITE_INIT                       fSrcAlpha = alpha;
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   uint8_t
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr8
#define SkSPRITE_PREAMBLE(srcBM, x, y)      const SkPMColor* ctable = srcBM.ctable()->readColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

///////////////////////////////////////////////////////////////////////////////

static intptr_t asint(const void* ptr) {
    return reinterpret_cast<const char*>(ptr) - (const char*)0;
}

static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst,
                            const uint8_t* SK_RESTRICT src, int count,
                            const uint16_t* SK_RESTRICT ctable) {
    if (count <= 8) {
        do {
            *dst++ = ctable[*src++];
        } while (--count);
        return;
    }

    // eat src until we're on a 4byte boundary
    while (asint(src) & 3) {
        *dst++ = ctable[*src++];
        count -= 1;
    }

    int qcount = count >> 2;
    SkASSERT(qcount > 0);
    const uint32_t* qsrc = reinterpret_cast<const uint32_t*>(src);
    if (asint(dst) & 2) {
        do {
            uint32_t s4 = *qsrc++;
#ifdef SK_CPU_LENDIAN
            *dst++ = ctable[s4 & 0xFF];
            *dst++ = ctable[(s4 >> 8) & 0xFF];
            *dst++ = ctable[(s4 >> 16) & 0xFF];
            *dst++ = ctable[s4 >> 24];
#else   // BENDIAN
            *dst++ = ctable[s4 >> 24];
            *dst++ = ctable[(s4 >> 16) & 0xFF];
            *dst++ = ctable[(s4 >> 8) & 0xFF];
            *dst++ = ctable[s4 & 0xFF];
#endif
        } while (--qcount);
    } else {    // dst is on a 4byte boundary
        uint32_t* ddst = reinterpret_cast<uint32_t*>(dst);
        do {
            uint32_t s4 = *qsrc++;
#ifdef SK_CPU_LENDIAN
            *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
            *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
#else   // BENDIAN
            *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
            *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
#endif
        } while (--qcount);
        dst = reinterpret_cast<uint16_t*>(ddst);
    }
    src = reinterpret_cast<const uint8_t*>(qsrc);
    count &= 3;
    // catch any remaining (will be < 4)
    while (--count >= 0) {
        *dst++ = ctable[*src++];
    }
}

#define SkSPRITE_ROW_PROC(d, s, n, x, y)    blitrow_d16_si8(d, s, n, ctable)

#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Opaque
#define SkSPRITE_ARGS
#define SkSPRITE_FIELDS
#define SkSPRITE_INIT
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   uint8_t
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr8
#define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.ctable()->read16BitCache()
#define SkSPRITE_BLIT_PIXEL(dst, src)       *dst = ctable[src]
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

#define SkSPRITE_CLASSNAME                  Sprite_D16_SIndex8_Blend
#define SkSPRITE_ARGS                       , uint8_t alpha
#define SkSPRITE_FIELDS                     uint8_t fSrcAlpha;
#define SkSPRITE_INIT                       fSrcAlpha = alpha;
#define SkSPRITE_DST_TYPE                   uint16_t
#define SkSPRITE_SRC_TYPE                   uint8_t
#define SkSPRITE_DST_GETADDR                writable_addr16
#define SkSPRITE_SRC_GETADDR                addr8
#define SkSPRITE_PREAMBLE(srcBM, x, y)      const uint16_t* ctable = srcBM.ctable()->read16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
#define SkSPRITE_BLIT_PIXEL(dst, src)       D16_S16_Blend_Pixel(dst, ctable[src], src_scale)
#define SkSPRITE_NEXT_ROW
#define SkSPRITE_POSTAMBLE(srcBM)
#include "SkSpriteBlitterTemplate.h"

///////////////////////////////////////////////////////////////////////////////

class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
public:
    Sprite_D16_S32_BlitRowProc(const SkPixmap& source) : SkSpriteBlitter(source) {}

    void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
        this->INHERITED::setup(dst, left, top, paint);

        unsigned flags = 0;

        if (paint.getAlpha() < 0xFF) {
            flags |= SkBlitRow::kGlobalAlpha_Flag;
        }
        if (!fSource.isOpaque()) {
            flags |= SkBlitRow::kSrcPixelAlpha_Flag;
        }
        if (paint.isDither()) {
            flags |= SkBlitRow::kDither_Flag;
        }
        fProc = SkBlitRow::Factory16(flags);
    }

    void blitRect(int x, int y, int width, int height) override {
        uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y);
        const SkPMColor* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
        size_t dstRB = fDst.rowBytes();
        size_t srcRB = fSource.rowBytes();
        SkBlitRow::Proc16 proc = fProc;
        U8CPU alpha = fPaint->getAlpha();

        while (--height >= 0) {
            proc(dst, src, width, alpha, x, y);
            y += 1;
            dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
            src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
        }
    }

private:
    SkBlitRow::Proc16 fProc;

    typedef SkSpriteBlitter INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkPixmap& source, const SkPaint& paint,
                                            SkTBlitterAllocator* allocator) {

    SkASSERT(allocator != nullptr);

    if (paint.getMaskFilter() != nullptr) { // may add cases for this
        return nullptr;
    }
    if (!paint.isSrcOver()) { // may add cases for this
        return nullptr;
    }
    if (paint.getColorFilter() != nullptr) { // may add cases for this
        return nullptr;
    }

    const SkAlphaType at = source.alphaType();

    SkSpriteBlitter* blitter = nullptr;
    unsigned alpha = paint.getAlpha();

    switch (source.colorType()) {
        case kN32_SkColorType: {
            if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
                break;
            }
            blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source);
            break;
        }
        case kARGB_4444_SkColorType:
            if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
                break;
            }
            if (255 == alpha) {
                blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source);
            } else {
                blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4);
            }
            break;
        case kRGB_565_SkColorType:
            if (255 == alpha) {
                blitter = allocator->createT<Sprite_D16_S16_Opaque>(source);
            } else {
                blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha);
            }
            break;
        case kIndex_8_SkColorType:
            if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
                break;
            }
            if (paint.isDither()) {
                // we don't support dither yet in these special cases
                break;
            }
            if (source.isOpaque()) {
                if (255 == alpha) {
                    blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source);
                } else {
                    blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha);
                }
            } else {
                if (255 == alpha) {
                    blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source);
                } else {
                    blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha);
                }
            }
            break;
        default:
            break;
    }
    return blitter;
}