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


#include "src/gpu/GrStencilSettings.h"

#include "src/gpu/GrProcessor.h"

constexpr const GrUserStencilSettings gUnused(
    GrUserStencilSettings::StaticInit<
        0x0000,
        GrUserStencilTest::kAlwaysIfInClip,
        0xffff,
        GrUserStencilOp::kKeep,
        GrUserStencilOp::kKeep,
        0x0000>()
);

static_assert(kAll_StencilFlags == (gUnused.fCWFlags[0] & gUnused.fCCWFlags[0]));

const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;

void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
                              int numStencilBits) {
    uint16_t cwFlags = user.fCWFlags[hasStencilClip];
    if (cwFlags & kSingleSided_StencilFlag) {
        SkASSERT(cwFlags == user.fCCWFlags[hasStencilClip]);
        fFlags = cwFlags;
        if (!this->isDisabled()) {
            fCWFace.reset(user.fCWFace, hasStencilClip, numStencilBits);
        }
        return;
    }

    uint16_t ccwFlags = user.fCCWFlags[hasStencilClip];
    fFlags = cwFlags & ccwFlags;
    if (this->isDisabled()) {
        return;
    }
    if (!(cwFlags & kDisabled_StencilFlag)) {
        fCWFace.reset(user.fCWFace, hasStencilClip, numStencilBits);
    } else {
        fCWFace.setDisabled();
    }
    if (!(ccwFlags & kDisabled_StencilFlag)) {
        fCCWFace.reset(user.fCCWFace, hasStencilClip, numStencilBits);
    } else {
        fCCWFace.setDisabled();
    }
}

void GrStencilSettings::reset(const GrStencilSettings& that) {
    fFlags = that.fFlags;
    if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
        return;
    }
    if (!this->isTwoSided()) {
        memcpy(&fCWFace, &that.fCWFace, sizeof(Face));
    } else {
        memcpy(&fCWFace, &that.fCWFace, 2 * sizeof(Face));
        static_assert(sizeof(Face) ==
                      offsetof(GrStencilSettings, fCCWFace) - offsetof(GrStencilSettings, fCWFace));
    }
}

bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
    if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
        // At least one is invalid and/or disabled.
        if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
            return false; // We never allow invalid stencils to be equal.
        }
        // They're only equal if both are disabled.
        return kDisabled_StencilFlag & (fFlags & that.fFlags);
    }
    if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
        return 0 == memcmp(&fCWFace, &that.fCWFace, sizeof(Face)); // Both are single sided.
    } else if (kSingleSided_StencilFlag & (fFlags | that.fFlags)) {
        return false;
    } else {
        return 0 == memcmp(&fCWFace, &that.fCWFace, 2 * sizeof(Face));
        static_assert(sizeof(Face) ==
                      offsetof(GrStencilSettings, fCCWFace) - offsetof(GrStencilSettings, fCWFace));
    }
    // memcmp relies on GrStencilSettings::Face being tightly packed.
    static_assert(0 == offsetof(Face, fRef));
    static_assert(2 == sizeof(Face::fRef));
    static_assert(2 == offsetof(Face, fTest));
    static_assert(2 == sizeof(Face::fTest));
    static_assert(4 == offsetof(Face, fTestMask));
    static_assert(2 == sizeof(Face::fTestMask));
    static_assert(6 == offsetof(Face, fPassOp));
    static_assert(1 == sizeof(Face::fPassOp));
    static_assert(7 == offsetof(Face, fFailOp));
    static_assert(1 == sizeof(Face::fFailOp));
    static_assert(8 == offsetof(Face, fWriteMask));
    static_assert(2 == sizeof(Face::fWriteMask));
    static_assert(10 == sizeof(Face));
}

static constexpr GrStencilTest gUserStencilTestToRaw[kGrUserStencilTestCount] = {
    // Tests that respect the clip.
    GrStencilTest::kAlways,  // kAlwaysIfInClip (This is only for when there is not a stencil clip).
    GrStencilTest::kEqual,   // kEqualIfInClip.
    GrStencilTest::kLess,    // kLessIfInClip.
    GrStencilTest::kLEqual,  // kLEqualIfInClip.

    // Tests that ignore the clip.
    GrStencilTest::kAlways,
    GrStencilTest::kNever,
    GrStencilTest::kGreater,
    GrStencilTest::kGEqual,
    GrStencilTest::kLess,
    GrStencilTest::kLEqual,
    GrStencilTest::kEqual,
    GrStencilTest::kNotEqual
};

static_assert(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
static_assert(1 == (int)GrUserStencilTest::kEqualIfInClip);
static_assert(2 == (int)GrUserStencilTest::kLessIfInClip);
static_assert(3 == (int)GrUserStencilTest::kLEqualIfInClip);
static_assert(4 == (int)GrUserStencilTest::kAlways);
static_assert(5 == (int)GrUserStencilTest::kNever);
static_assert(6 == (int)GrUserStencilTest::kGreater);
static_assert(7 == (int)GrUserStencilTest::kGEqual);
static_assert(8 == (int)GrUserStencilTest::kLess);
static_assert(9 == (int)GrUserStencilTest::kLEqual);
static_assert(10 == (int)GrUserStencilTest::kEqual);
static_assert(11 == (int)GrUserStencilTest::kNotEqual);

static constexpr GrStencilOp gUserStencilOpToRaw[kGrUserStencilOpCount] = {
    GrStencilOp::kKeep,

    // Ops that only modify user bits.
    GrStencilOp::kZero,
    GrStencilOp::kReplace,
    GrStencilOp::kInvert,
    GrStencilOp::kIncWrap,
    GrStencilOp::kDecWrap,
    GrStencilOp::kIncClamp,  // kIncMaybeClamp.
    GrStencilOp::kDecClamp,  // kDecMaybeClamp.

    // Ops that only modify the clip bit.
    GrStencilOp::kZero,      // kZeroClipBit.
    GrStencilOp::kReplace,   // kSetClipBit.
    GrStencilOp::kInvert,    // kInvertClipBit.

    // Ops that modify clip and user bits.
    GrStencilOp::kReplace,   // kSetClipAndReplaceUserBits.
    GrStencilOp::kZero       // kZeroClipAndUserBits.
};

static_assert(0 == (int)GrUserStencilOp::kKeep);
static_assert(1 == (int)GrUserStencilOp::kZero);
static_assert(2 == (int)GrUserStencilOp::kReplace);
static_assert(3 == (int)GrUserStencilOp::kInvert);
static_assert(4 == (int)GrUserStencilOp::kIncWrap);
static_assert(5 == (int)GrUserStencilOp::kDecWrap);
static_assert(6 == (int)GrUserStencilOp::kIncMaybeClamp);
static_assert(7 == (int)GrUserStencilOp::kDecMaybeClamp);
static_assert(8 == (int)GrUserStencilOp::kZeroClipBit);
static_assert(9 == (int)GrUserStencilOp::kSetClipBit);
static_assert(10 == (int)GrUserStencilOp::kInvertClipBit);
static_assert(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
static_assert(12 == (int)GrUserStencilOp::kZeroClipAndUserBits);

void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
                                    int numStencilBits) {
    SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
    SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
    SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
    SkASSERT(numStencilBits > 0 && numStencilBits <= 16);
    int clipBit = 1 << (numStencilBits - 1);
    int userMask = clipBit - 1;

    GrUserStencilOp maxOp = std::max(user.fPassOp, user.fFailOp);
    SkDEBUGCODE(GrUserStencilOp otherOp = std::min(user.fPassOp, user.fFailOp);)
    if (maxOp <= kLastUserOnlyStencilOp) {
        // Ops that only modify user bits.
        fWriteMask = user.fWriteMask & userMask;
        SkASSERT(otherOp <= kLastUserOnlyStencilOp);
    } else if (maxOp <= kLastClipOnlyStencilOp) {
        // Ops that only modify the clip bit.
        fWriteMask = clipBit;
        SkASSERT(GrUserStencilOp::kKeep == otherOp ||
                 (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
    } else {
        // Ops that modify both clip and user bits.
        fWriteMask = clipBit | (user.fWriteMask & userMask);
        SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
    }

    fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
    fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];

    if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
        // Ignore the clip.
        fTestMask = user.fTestMask & userMask;
        fTest = gUserStencilTestToRaw[(int)user.fTest];
    } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
        // Respect the clip.
        fTestMask = clipBit | (user.fTestMask & userMask);
        fTest = gUserStencilTestToRaw[(int)user.fTest];
    } else {
        // Test only for clip.
        fTestMask = clipBit;
        fTest = GrStencilTest::kEqual;
    }

    fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
}

void GrStencilSettings::Face::setDisabled() {
    memset(this, 0, sizeof(*this));
    static_assert(0 == (int)GrStencilTest::kAlways);
    static_assert(0 == (int)GrStencilOp::kKeep);
}

static constexpr GrUserStencilSettings gZeroStencilClipBit(
    GrUserStencilSettings::StaticInit<
        0x0000,
        GrUserStencilTest::kAlways,
        0xffff,
        GrUserStencilOp::kZeroClipBit,
        GrUserStencilOp::kZeroClipBit,
        0x0000>()
);
static constexpr GrUserStencilSettings gSetStencilClipBit(
    GrUserStencilSettings::StaticInit<
        0x0000,
        GrUserStencilTest::kAlways,
        0xffff,
        GrUserStencilOp::kSetClipBit,
        GrUserStencilOp::kSetClipBit,
        0x0000>()
);

const GrUserStencilSettings* GrStencilSettings::SetClipBitSettings(bool setToInside) {
    return setToInside ? &gSetStencilClipBit : &gZeroStencilClipBit;
}

void GrStencilSettings::genKey(GrProcessorKeyBuilder* b, bool includeRefs) const {
    b->add32(fFlags);
    if (this->isDisabled()) {
        return;
    }
    if (!this->isTwoSided()) {
        constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
        static_assert(0 == sizeof(Face) % sizeof(uint16_t));
        uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
        if (includeRefs) {
            memcpy(key, &fCWFace, sizeof(Face));
        } else {
            Face tempFace = fCWFace;
            tempFace.fRef = 0;
            memcpy(key, &tempFace, sizeof(Face));
        }
        key[kCount16] = 0;
        static_assert(1 == kCount16 % 2);
    } else {
        constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
        static_assert(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
        uint32_t* key = b->add32n(kCount32);
        if (includeRefs) {
            memcpy(key, &fCWFace, 2 * sizeof(Face));
            static_assert(
                    sizeof(Face) ==
                    offsetof(GrStencilSettings, fCCWFace) - offsetof(GrStencilSettings, fCWFace));
        } else {
            Face tempFaces[2];
            tempFaces[0] = fCWFace;
            tempFaces[0].fRef = 0;
            tempFaces[1] = fCCWFace;
            tempFaces[1].fRef = 0;
            memcpy(key, &tempFaces, 2 * sizeof(Face));
        }
    }
    // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
    static_assert(0 == offsetof(Face, fRef));
    static_assert(2 == sizeof(Face::fRef));
    static_assert(2 == offsetof(Face, fTest));
    static_assert(2 == sizeof(Face::fTest));
    static_assert(4 == offsetof(Face, fTestMask));
    static_assert(2 == sizeof(Face::fTestMask));
    static_assert(6 == offsetof(Face, fPassOp));
    static_assert(1 == sizeof(Face::fPassOp));
    static_assert(7 == offsetof(Face, fFailOp));
    static_assert(1 == sizeof(Face::fFailOp));
    static_assert(8 == offsetof(Face, fWriteMask));
    static_assert(2 == sizeof(Face::fWriteMask));
    static_assert(10 == sizeof(Face));
}
