/*
 * Copyright 2022 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/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkPixmap.h"
#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Recording.h"
#include "include/gpu/graphite/Surface.h"
#include "src/gpu/graphite/Surface_Graphite.h"

namespace skgpu::graphite {

// Tests that a drawing with MSAA will have contents retained between recordings.
// This is for testing MSAA load from resolve feature.
// TODO(b/296420752): enable in CTS after debugging failure at coordinates 32,30.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(MultisampleRetainTest, reporter, context,
                                   CtsEnforcement::kNever) {
    const SkImageInfo surfaceImageInfo = SkImageInfo::Make(
            33, 33, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);

    std::unique_ptr<Recorder> surfaceRecorder = context->makeRecorder();
    sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(surfaceRecorder.get(), surfaceImageInfo);

    // Clear entire surface to red
    SkCanvas* surfaceCanvas = surface->getCanvas();
    surfaceCanvas->clear(SkColors::kRed);
    std::unique_ptr<Recording> surfaceRecording = surfaceRecorder->snap();
    // Flush the clearing
    context->insertRecording({surfaceRecording.get()});

    // Draw a blue path. The old red background should be retained between recordings.
    SkPaint paint;
    paint.setStrokeWidth(3);
    paint.setColor(SkColors::kBlue);
    paint.setStyle(SkPaint::Style::kStroke_Style);

    constexpr int kPathPoints[][2] = {
        {9, 8},
        {9, 12},
        {14, 16},
        {10, 32},
    };

    SkPathBuilder builder;
    builder.moveTo(kPathPoints[0][0], kPathPoints[0][1]);
    for (size_t i = 0; i < std::size(kPathPoints); ++i) {
        builder.lineTo(kPathPoints[i][0], kPathPoints[i][1]);
    }
    SkPath path = builder.detach();

    surfaceCanvas->drawPath(path, paint);

    std::unique_ptr<Recording> surfaceRecording2 = surfaceRecorder->snap();
    // Play back recording.
    context->insertRecording({surfaceRecording2.get()});

    // Read pixels.
    SkBitmap bitmap;
    bitmap.allocPixels(surfaceImageInfo);
    if (!surface->readPixels(bitmap, 0, 0)) {
        ERRORF(reporter, "readPixels failed");
        return;
    }

    // Verify recording was replayed.
    REPORTER_ASSERT(reporter, bitmap.getColor4f(16, 0) == SkColors::kRed);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(0, 16) == SkColors::kRed);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(32, 30) == SkColors::kRed);

    // Verify points on the path have blue color. We don't verify last point because it is on the
    // edge of the path thus might have blurry color.
    for (size_t i = 0; i < std::size(kPathPoints) - 1; ++i) {
        REPORTER_ASSERT(reporter,
                        bitmap.getColor4f(kPathPoints[i][0], kPathPoints[i][1]) == SkColors::kBlue);
    }
}

// Tests that multisampled rendering with LoadOp::Clear in one pass and LoadOp::Load in another pass
// works. With the Vulkan backend in particular, without
// VK_EXT_multisampled_render_to_single_sampled, the render pass with LoadOp::Load has an extra
// "unresolve" pass at the start.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(MultisampleClearThenLoad,
                                   reporter,
                                   context,
                                   CtsEnforcement::kApiLevel_202604) {
    const SkImageInfo surfaceImageInfo = SkImageInfo::Make(
            33, 33, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType);

    std::unique_ptr<Recorder> surfaceRecorder = context->makeRecorder();
    sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(surfaceRecorder.get(), surfaceImageInfo);

    // Clear entire surface to red
    SkCanvas* surfaceCanvas = surface->getCanvas();
    surfaceCanvas->clear(SkColors::kRed);

    // Draw a blue path over it. This render pass will use LoadOp::Clear because of the clear above.
    SkPaint paint;
    paint.setStrokeWidth(3);
    paint.setColor(SkColors::kBlue);
    paint.setStyle(SkPaint::Style::kStroke_Style);
    paint.setAntiAlias(true);

    // Note: The path is not a line, since that's optimized not to take the multisampling path.
    SkPath path = SkPathBuilder()
                  .moveTo(0, 0)
                  .lineTo(15, 15)
                  .lineTo(33, 33)
                  .detach();

    surfaceCanvas->drawPath(path, paint);

    std::unique_ptr<Recording> surfaceRecording = surfaceRecorder->snap();
    // Play back recording. This breaks the render pass.
    context->insertRecording({surfaceRecording.get()});

    // Draw another path. Because the contents of the surface need to be retained, this render pass
    // will use LoadOp::Load.
    SkPath path2 = SkPathBuilder()
                   .moveTo(33, 0)
                   .lineTo(15, 15)
                   .lineTo(0, 33)
                   .detach();

    surfaceCanvas->drawPath(path2, paint);

    std::unique_ptr<Recording> surfaceRecording2 = surfaceRecorder->snap();
    // Play back recording. Break the render pass again.
    context->insertRecording({surfaceRecording2.get()});

    // Verify results
    SkBitmap bitmap;
    bitmap.allocPixels(surfaceImageInfo);
    if (!surface->readPixels(bitmap, 0, 0)) {
        ERRORF(reporter, "readPixels failed");
        return;
    }

    // Some points outside the paths
    REPORTER_ASSERT(reporter, bitmap.getColor4f(1, 16) == SkColors::kRed);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(16, 1) == SkColors::kRed);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(31, 16) == SkColors::kRed);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(16, 31) == SkColors::kRed);

    // Some points on the paths
    REPORTER_ASSERT(reporter, bitmap.getColor4f(1, 1) == SkColors::kBlue);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(31, 1) == SkColors::kBlue);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(1, 31) == SkColors::kBlue);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(31, 31) == SkColors::kBlue);
    REPORTER_ASSERT(reporter, bitmap.getColor4f(16, 16) == SkColors::kBlue);
}

}  // namespace skgpu::graphite
