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

#include "tests/Test.h"

#include "include/core/SkCanvas.h"
#include "include/gpu/graphite/BackendTexture.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/Image.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Surface.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "tools/gpu/ManagedBackendTexture.h"
#include "tools/graphite/GraphiteTestContext.h"

using namespace skgpu;
using namespace skgpu::graphite;

DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ImageWrapTextureMipmapsTest,
                                               reporter,
                                               context,
                                               testContext,
                                               true,
                                               CtsEnforcement::kApiLevel_202404) {
    auto recorder = context->makeRecorder();
    if (!recorder) {
        ERRORF(reporter, "Could not make recorder");
        return;
    }

    skgpu::Protected isProtected = skgpu::Protected(context->priv().caps()->protectedSupport());

    auto info = SkImageInfo::Make({2, 1}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    SkAutoPixmapStorage basePM, topPM;
    basePM.alloc(info);
    basePM.erase(SK_ColorGREEN);
    topPM.alloc(info.makeDimensions({1, 1}));
    topPM.erase(SK_ColorBLUE);

    SkPixmap levelPMs[]{basePM, topPM};
    auto mbet = sk_gpu_test::ManagedGraphiteTexture::MakeMipmappedFromPixmaps(recorder.get(),
                                                                              levelPMs,
                                                                              Renderable::kNo,
                                                                              isProtected);

    if (!mbet) {
        ERRORF(reporter, "Could not make backend texture");
        return;
    }

    std::unique_ptr<Recording> recording = recorder->snap();

    auto recordingFinishProc = [](void* context, CallbackResult) {
        std::unique_ptr<Recording>(static_cast<Recording*>(context));
    };

    skgpu::graphite::InsertRecordingInfo recordingInfo;
    recordingInfo.fFinishedProc = recordingFinishProc;
    recordingInfo.fRecording = recording.get();
    recordingInfo.fFinishedContext = recording.release();
    if (!context->insertRecording(recordingInfo)) {
        ERRORF(reporter, "Could not insert recording");
        return;
    }

    static constexpr struct TestCase {
        SkImages::GenerateMipmapsFromBase genMipmaps;
        SkColor expectedColor;
    } kTestCases[]{{SkImages::GenerateMipmapsFromBase::kNo , 0xFFFF0000},
                   {SkImages::GenerateMipmapsFromBase::kYes, 0XFF00FF00}};

    for (const auto& testCase : kTestCases) {
        recorder = context->makeRecorder();
        if (!recorder) {
            ERRORF(reporter, "Could not make recorder");
            return;
        }

        auto image = SkImages::WrapTexture(recorder.get(),
                                           mbet->texture(),
                                           info.colorType(),
                                           info.alphaType(),
                                           info.refColorSpace(),
                                           Origin::kTopLeft,
                                           testCase.genMipmaps,
                                           sk_gpu_test::ManagedGraphiteTexture::ImageReleaseProc,
                                           mbet->releaseContext());
        if (!recorder) {
            ERRORF(reporter, "Could not make image");
            return;
        }

        // We determe the contents of the image's top level by doing a downsampling draw to a
        // surface and then reading the surface's contents.
        auto surface = SkSurfaces::RenderTarget(recorder.get(), info.makeDimensions({1, 1}));
        if (!recorder) {
            ERRORF(reporter, "Could not make surface");
            return;
        }

        auto shader = image->makeShader(
                SkTileMode::kRepeat,
                SkTileMode::kRepeat,
                SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNearest));

        surface->getCanvas()->scale(0.05f, 0.05f);
        SkPaint paint;
        paint.setShader(std::move(shader));
        surface->getCanvas()->drawPaint(paint);

        recording = recorder->snap();
        recordingInfo.fRecording = recording.get();
        recordingInfo.fFinishedContext = recording.release();
        if (!context->insertRecording(recordingInfo)) {
            ERRORF(reporter, "Could not insert recording");
            return;
        }

        struct ReadContext {
            bool called = false;
            bool success = false;
            uint32_t color;
        };
        auto readPixelsCallback = [](SkImage::ReadPixelsContext context,
                                     std::unique_ptr<const SkImage::AsyncReadResult> result) {
            auto& readContext = *static_cast<ReadContext*>(context);
            readContext.called = true;
            if (result) {
                readContext.success = true;
                readContext.color = *static_cast<const uint32_t*>(result->data(0));
            }
        };
        ReadContext readContext;
        context->asyncRescaleAndReadPixels(surface.get(),
                                           surface->imageInfo(),
                                           SkIRect::MakeSize(surface->imageInfo().dimensions()),
                                           SkImage::RescaleGamma::kSrc,
                                           SkImage::RescaleMode::kNearest,
                                           readPixelsCallback,
                                           &readContext);
        context->submit();
        while (!readContext.called) {
            testContext->tick();
            context->checkAsyncWorkCompletion();
        }

        if (!readContext.success) {
            ERRORF(reporter, "Read pixels failed");
            return;
        }

        REPORTER_ASSERT(reporter, readContext.color == testCase.expectedColor);
    }
}
