C++程序  |  203行  |  6.06 KB

/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <tuple>

#include "Benchmark.h"
#include "Resources.h"
#include "SkCpu.h"
#include "SkImage.h"
#include "SkImage_Base.h"
#include "SkNx.h"
#include "SkOpts.h"
#include "SkPM4fPriv.h"
#include "SkString.h"

#define INNER_LOOPS 10

static inline void brute_srcover_srgb_srgb_1(uint32_t* dst, uint32_t src) {
    auto d = Sk4f_fromS32(*dst),
         s = Sk4f_fromS32( src);
    *dst = Sk4f_toS32(s + d * (1.0f - s[3]));
}

static inline void srcover_srgb_srgb_1(uint32_t* dst, uint32_t src) {
    if (src >= 0xFF000000) {
        *dst = src;
        return;
    }
    brute_srcover_srgb_srgb_1(dst, src);
}

static void brute_force_srcover_srgb_srgb(
    uint32_t* dst, const uint32_t* const src, int ndst, const int nsrc) {
    while (ndst > 0) {
        int n = SkTMin(ndst, nsrc);

        for (int i = 0; i < n; i++) {
            brute_srcover_srgb_srgb_1(dst++, src[i]);
        }
        ndst -= n;
    }
}

static void trivial_srcover_srgb_srgb(
    uint32_t* dst, const uint32_t* const src, int ndst, const int nsrc) {
    while (ndst > 0) {
        int n = SkTMin(ndst, nsrc);

        for (int i = 0; i < n; i++) {
            srcover_srgb_srgb_1(dst++, src[i]);
        }
        ndst -= n;
    }
}

static void best_non_simd_srcover_srgb_srgb(
    uint32_t* dst, const uint32_t* const src, int ndst, const int nsrc) {
    uint64_t* ddst = reinterpret_cast<uint64_t*>(dst);

    auto srcover_srgb_srgb_2 = [](uint32_t* dst, const uint32_t* src) {
        srcover_srgb_srgb_1(dst++, *src++);
        srcover_srgb_srgb_1(dst, *src);
    };

    while (ndst >0) {
        int count = SkTMin(ndst, nsrc);
        ndst -= count;
        const uint64_t* dsrc = reinterpret_cast<const uint64_t*>(src);
        const uint64_t* end = dsrc + (count >> 1);
        do {
            if ((~*dsrc & 0xFF000000FF000000) == 0) {
                do {
                    *ddst++ = *dsrc++;
                } while (dsrc < end && (~*dsrc & 0xFF000000FF000000) == 0);
            } else if ((*dsrc & 0xFF000000FF000000) == 0) {
                do {
                    dsrc++;
                    ddst++;
                } while (dsrc < end && (*dsrc & 0xFF000000FF000000) == 0);
            } else {
                srcover_srgb_srgb_2(reinterpret_cast<uint32_t*>(ddst++),
                                    reinterpret_cast<const uint32_t*>(dsrc++));
            }
        } while (dsrc < end);

        if ((count & 1) != 0) {
            uint32_t s1;
            memcpy(&s1, dsrc, 4);
            srcover_srgb_srgb_1(reinterpret_cast<uint32_t*>(ddst), s1);
        }
    }
}

class SrcOverVSkOptsBruteForce {
public:
    static SkString Name() { return SkString{"VSkOptsBruteForce"}; }
    static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
        brute_force_srcover_srgb_srgb(dst, src, count, count);
    }
};

class SrcOverVSkOptsTrivial {
public:
    static SkString Name() { return SkString{"VSkOptsTrivial"}; }
    static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
        trivial_srcover_srgb_srgb(dst, src, count, count);
    }
};

class SrcOverVSkOptsNonSimdCore {
public:
    static SkString Name() { return SkString{"VSkOptsNonSimdCore"}; }
    static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
        best_non_simd_srcover_srgb_srgb(dst, src, count, count);
    }
};

class SrcOverVSkOptsDefault {
public:
    static SkString Name() { return SkString{"VSkOptsDefault"}; }
    static void BlendN(uint32_t* dst, const uint32_t* src, int count) {
        SkOpts::srcover_srgb_srgb(dst, src, count, count);
    }
};

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

template <typename Blender>
class LinearSrcOverBench : public Benchmark {
public:
    LinearSrcOverBench(const char* fileName) : fFileName(fileName) {
        fName = "LinearSrcOver_";
        fName.append(fileName);
        fName.append(Blender::Name());
    }

protected:
    bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
    const char* onGetName() override { return fName.c_str(); }

    void onPreDraw(SkCanvas*) override {
        if (!fPixmap.addr()) {
            sk_sp<SkImage> image = GetResourceAsImage(fFileName.c_str());
            SkBitmap bm;
            SkColorSpace* legacyColorSpace = nullptr;
            if (!as_IB(image)->getROPixels(&bm, legacyColorSpace)) {
                SkFAIL("Could not read resource");
            }
            bm.peekPixels(&fPixmap);
            fCount = fPixmap.rowBytesAsPixels();
            fDst.reset(fCount);
            sk_bzero(fDst.get(), fPixmap.rowBytes());
        }
    }

    void onDraw(int loops, SkCanvas*) override {
        SkASSERT(fPixmap.colorType() == kN32_SkColorType);

        const int width = fPixmap.rowBytesAsPixels();

        for (int i = 0; i < loops * INNER_LOOPS; ++i) {
            const uint32_t* src = fPixmap.addr32();
            for (int y = 0; y < fPixmap.height(); y++) {
                Blender::BlendN(fDst.get(), src, width);
                src += width;
            }
        }
    }

    void onPostDraw(SkCanvas*) override {
        // Make sure the compiler does not optimize away the operation.
        volatile uint32_t v = 0;
        for (int i = 0; i < fCount; i++) {
            v ^= fDst[i];
        }
    }

private:
    int fCount;
    SkAutoTArray<uint32_t> fDst;
    SkString fFileName;
    SkString fName;
    SkPixmap fPixmap;

    typedef Benchmark INHERITED;
};

#define BENCHES(fileName)                                                            \
    DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsBruteForce>(fileName); )  \
    DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsTrivial>(fileName); )     \
    DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsNonSimdCore>(fileName); ) \
    DEF_BENCH( return new LinearSrcOverBench<SrcOverVSkOptsDefault>(fileName); )

BENCHES("yellow_rose.png")
BENCHES("baby_tux.png")
BENCHES("plane.png")
BENCHES("mandrill_512.png")
BENCHES("iconstrip.png")