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

#include "gm.hpp"
#include "gmutils.hpp"
#include "common/testing_window.hpp"
#include "rive/renderer.hpp"
#include "rive/renderer/render_context.hpp"
#include "rive/renderer/render_context_impl.hpp"

#include "assets/nomoon.png.hpp"

using namespace rivegm;
using namespace rive;

// Renders the same scene twice, side by side: the LEFT cell through
// fully-featured ubershader pipelines and the RIGHT cell through specialized
// pipelines (via a render pass break between the two). The cells must match:
// a few LSB of rounding difference is expected on translucent content (the
// premultiplied and unmultiplied paint paths round differently), but any
// visible or structural divergence is an ubershader bug. The golden pins
// both halves, so a regression in either flavor diffs immediately.
//
// The scene is chosen to stress where the two pipeline flavors are most
// likely to diverge: ubershaders compile ENABLE_ADVANCED_BLEND, which flips
// the entire paint path to unmultiplied colors. So the scene leans on
// content whose premultiplied vs unmultiplied evaluation differs in rounding
// and codepath:
//   - translucent gradients fading to very low alpha (premultiply rounding),
//   - an image drawn at low opacity (the unmultiplied path round-trips image
//     texels through unmultiply/premultiply),
//   - an advanced blend (multiply) overlapping srcOver content (forces the
//     dst-read machinery alongside the plain path),
//   - thin strokes over the gradient (AA edge rounding).
//
// On backends that can't switch shader compilation mode at runtime, both
// cells render specialized and trivially match.
constexpr float CELL = 300.f;

static void draw_scene(Renderer* renderer, float ox)
{
  Factory* factory = TestingWindow::Get()->factory();
  constexpr float stops[2] = {0.f, 1.f};

  renderer->save();
  renderer->translate(ox, 0);

  // Opaque horizontal gradient base.
  AABB base = {20.f, 20.f, 280.f, 280.f};
  ColorInt baseColors[2] = {0xff2060c0, 0xffc06020};
  Paint basePaint;
  basePaint->shader(factory->makeLinearGradient(
      base.left(),
      0,
      base.right(),
      0,
      baseColors,
      stops,
      2));
  renderer->drawPath(PathBuilder::Rect(base), basePaint);

  // Translucent vertical gradient fading to near-zero alpha: the
  // premultiplied path rounds rgb*a per fragment, the unmultiplied path
  // premultiplies after coverage; low-alpha texels expose the difference.
  AABB overlay = {50.f, 50.f, 250.f, 250.f};
  ColorInt overlayColors[2] = {0xccff2020, 0x0dffff20};
  Paint overlayPaint;
  overlayPaint->shader(factory->makeLinearGradient(
      0,
      overlay.top(),
      0,
      overlay.bottom(),
      overlayColors,
      stops,
      2));
  renderer->drawPath(PathBuilder::Rect(overlay), overlayPaint);

  // Multiply square overlapping both gradients: advanced blend content in
  // the same scene as plain srcOver draws.
  Paint multiplyPaint;
  multiplyPaint->color(0xff90b0d0);
  multiplyPaint->blendMode(BlendMode::multiply);
  renderer->drawPath(
      PathBuilder::Rect({140.f, 80.f, 260.f, 200.f}),
      multiplyPaint);

  // Image at low opacity: in the unmultiplied path, image texels round-trip
  // through unmultiply_rgb and a later premultiply.
  auto img = LoadImage(assets::nomoon_png());
  if (img != nullptr)
  {
    renderer->save();
    renderer->translate(60.f, 120.f);
    float scale = 140.f / std::max(img->width(), img->height());
    renderer->scale(scale, scale);
    renderer->drawImage(
        img.get(),
        ImageSampler::LinearClamp(),
        BlendMode::srcOver,
        .35f);
    renderer->restore();
  }

  // Thin translucent strokes over everything: AA edge rounding.
  for (int i = 0; i < 3; ++i)
  {
    Paint strokePaint;
    strokePaint->style(RenderPaintStyle::stroke);
    strokePaint->thickness(1.5f);
    strokePaint->color(0x8020ff80);
    renderer->drawPath(
        PathBuilder::Circle(150.f, 150.f, 60.f + 25.f * i),
        strokePaint);
  }

  renderer->restore();
}

class uber_parity_GM : public rivegm::GM
{
public:
  uber_parity_GM() : GM(600, 300) {}
  ColorInt clearColor() const override { return 0xff404040; }

  void updateFrameOptions(TestingWindow::FrameOptions* options) const override
  {
    // Makes GM::run restore the process-wide mode after endFrame(); the
    // per-half modes below override it in between.
    options->shaderCompilationMode = rive::gpu::ShaderCompilationMode::
        onlyUbershaders;
  }

  void onDraw(rive::Renderer* renderer) override
  {
    gpu::RenderContext* renderContext = TestingWindow::Get()->renderContext();
    if (renderContext == nullptr)
    {
      // No runtime mode switching on this backend; both cells render
      // the same way and trivially match.
      draw_scene(renderer, 0);
      draw_scene(renderer, CELL);
      return;
    }

    gpu::RenderContext::FrameDescriptor
        frameDescriptor = renderContext->frameDescriptor();
    frameDescriptor.loadAction = gpu::LoadAction::preserveRenderTarget;

    for (int i = 0; i < 2; ++i)
    {
      // Flushes the previous half (and initially the clear) under the
      // mode that was live when its draws were recorded.
      TestingWindow::Get()->flushPLSContext();
      renderContext->impl()->testingOnly_setShaderCompilationMode(
          i == 0 ? gpu::ShaderCompilationMode::onlyUbershaders
                 : gpu::ShaderCompilationMode::alwaysSynchronous);
      renderContext->beginFrame(frameDescriptor);
      draw_scene(renderer, i * CELL);
    }
    // endFrame() flushes the right half under alwaysSynchronous, then
    // GM::run restores the process-wide mode.
  }
};
GMREGISTER(uber_parity, return new uber_parity_GM)
