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

#include "gm/gm.h"

#include "include/core/SkPath.h"
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/GrRecordingContext.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrDrawingManager.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrSurfaceDrawContext.h"
#include "src/gpu/ccpr/GrCCPathCache.h"
#include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
#include "tools/ToolUtils.h"

namespace skiagm {

#define ERR_MSG_ASSERT(COND) \
    do { \
        if (!(COND)) { \
            errorMsg->printf("preservefillrule.cpp(%i): assert(%s)", \
                             __LINE__, #COND); \
            return DrawResult::kFail; \
        } \
    } while (false)


/**
 * This test ensures that the ccpr path cache preserves fill rules properly, both in the case where
 * we copy paths into a8 literal coverage atlases, as well as in the case where we just reuse a
 * stashed fp16 coverage count atlas.
 */
class PreserveFillRuleGM : public GpuGM {
public:
    // fStarSize affects whether ccpr copies the paths to an a8 literal coverage atlas, or just
    // leaves them stashed in an fp16 coverage count atlas. The threshold for copying to a8 is
    // currently 256x256 total pixels copied. If this ever changes, there is code in onDraw that
    // will detect the unexpected behavior and draw a failure message.
    PreserveFillRuleGM(bool literalCoverageAtlas)
            : fLiteralCoverageAtlas(literalCoverageAtlas)
            , fStarSize((fLiteralCoverageAtlas) ? 200 : 20) {
    }

private:
    SkString onShortName() override {
        SkString name("preservefillrule");
        name += (fLiteralCoverageAtlas) ? "_big" : "_little";
        return name;
    }
    SkISize onISize() override { return SkISize::Make(fStarSize * 2, fStarSize * 2); }

    void modifyGrContextOptions(GrContextOptions* ctxOptions) override {
        ctxOptions->fGpuPathRenderers = GpuPathRenderers::kCoverageCounting;
        ctxOptions->fAllowPathMaskCaching = true;
    }

    DrawResult onDraw(GrRecordingContext* rContext, GrSurfaceDrawContext* rtc, SkCanvas* canvas,
                      SkString* errorMsg) override {
        using CoverageType = GrCCAtlas::CoverageType;

        if (rtc->numSamples() > 1) {
            errorMsg->set("ccpr is currently only used for coverage AA");
            return DrawResult::kSkip;
        }

        auto* ccpr = rContext->priv().drawingManager()->getCoverageCountingPathRenderer();
        if (!ccpr) {
            errorMsg->set("ccpr only");
            return DrawResult::kSkip;
        }

        auto pathCache = ccpr->testingOnly_getPathCache();
        if (!pathCache) {
            errorMsg->set("ccpr is not in caching mode. "
                          "Are you using viewer? Launch with \"--cachePathMasks true\".");
            return DrawResult::kFail;
        }

        auto dContext = GrAsDirectContext(rContext);
        if (!dContext) {
            *errorMsg = "Requires a direct context.";
            return skiagm::DrawResult::kSkip;
        }

        auto starRect = SkRect::MakeWH(fStarSize, fStarSize);
        SkPath star7_winding = ToolUtils::make_star(starRect, 7);
        star7_winding.setFillType(SkPathFillType::kWinding);

        SkPath star7_evenOdd = star7_winding;
        star7_evenOdd.transform(SkMatrix::Translate(0, fStarSize));
        star7_evenOdd.setFillType(SkPathFillType::kEvenOdd);

        SkPath star5_winding = ToolUtils::make_star(starRect, 5);
        star5_winding.transform(SkMatrix::Translate(fStarSize, 0));
        star5_winding.setFillType(SkPathFillType::kWinding);

        SkPath star5_evenOdd = star5_winding;
        star5_evenOdd.transform(SkMatrix::Translate(0, fStarSize));
        star5_evenOdd.setFillType(SkPathFillType::kEvenOdd);

        SkPaint paint;
        paint.setColor(SK_ColorGREEN);
        paint.setAntiAlias(true);

        for (int i = 0; i < 3; ++i) {
            canvas->clear(SK_ColorWHITE);
            canvas->drawPath(star7_winding, paint);
            canvas->drawPath(star7_evenOdd, paint);
            canvas->drawPath(star5_winding, paint);
            canvas->drawPath(star5_evenOdd, paint);
            dContext->priv().flushSurface(rtc->asSurfaceProxy());

            // Ensure the path cache is behaving in such a way that we are actually testing what we
            // think we are.
            int numCachedPaths = 0;
            for (GrCCPathCacheEntry* entry : pathCache->testingOnly_getLRU()) {
                if (0 == i) {
                    // We don't cache an atlas on the first hit.
                    ERR_MSG_ASSERT(!entry->cachedAtlas());
                } else {
                    // The stars should be cached in an atlas now.
                    ERR_MSG_ASSERT(entry->cachedAtlas());

                    CoverageType atlasCoverageType = entry->cachedAtlas()->coverageType();
                    if (i < 2) {
                        // We never copy to an a8 atlas before the second hit.
                        ERR_MSG_ASSERT(ccpr->coverageType() == atlasCoverageType);
                    } else if (fLiteralCoverageAtlas) {
                        // Verify fStarSize is large enough that the paths got copied to an a8
                        // atlas.
                        ERR_MSG_ASSERT(CoverageType::kA8_LiteralCoverage == atlasCoverageType);
                    } else {
                        // Verify fStarSize is small enough that the paths did *NOT* get copied to
                        // an a8 atlas.
                        ERR_MSG_ASSERT(ccpr->coverageType() == atlasCoverageType);
                    }
                }
                ++numCachedPaths;
            }

            if (dContext) {
                // Verify all 4 paths are tracked by the path cache.
                ERR_MSG_ASSERT(4 == numCachedPaths);
            }
        }

        return DrawResult::kOk;
    }

private:
    const bool fLiteralCoverageAtlas;
    const int fStarSize;
};

DEF_GM( return new PreserveFillRuleGM(true); )
DEF_GM( return new PreserveFillRuleGM(false); )

}  // namespace skiagm
