/*
 * 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/GrRenderTargetContext.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, GrRenderTargetContext* 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
