// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "compositor_context.h"

#include <vector>

#include "flutter/flow/layers/layer_tree.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"

namespace flutter_runner {

class ScopedFrame final : public flutter::CompositorContext::ScopedFrame {
 public:
  ScopedFrame(CompositorContext& context,
              GrContext* gr_context,
              SkCanvas* canvas,
              flutter::ExternalViewEmbedder* view_embedder,
              const SkMatrix& root_surface_transformation,
              bool instrumentation_enabled,
              bool surface_supports_readback,
              fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger,
              SessionConnection& session_connection,
              VulkanSurfaceProducer& surface_producer,
              flutter::SceneUpdateContext& scene_update_context)
      : flutter::CompositorContext::ScopedFrame(context,
                                                surface_producer.gr_context(),
                                                canvas,
                                                view_embedder,
                                                root_surface_transformation,
                                                instrumentation_enabled,
                                                surface_supports_readback,
                                                raster_thread_merger),
        session_connection_(session_connection),
        surface_producer_(surface_producer),
        scene_update_context_(scene_update_context) {}

 private:
  SessionConnection& session_connection_;
  VulkanSurfaceProducer& surface_producer_;
  flutter::SceneUpdateContext& scene_update_context_;

  flutter::RasterStatus Raster(flutter::LayerTree& layer_tree,
                               bool ignore_raster_cache) override {
    std::vector<flutter::SceneUpdateContext::PaintTask> frame_paint_tasks;
    std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;

    {
      // Preroll the Flutter layer tree. This allows Flutter to perform
      // pre-paint optimizations.
      TRACE_EVENT0("flutter", "Preroll");
      layer_tree.Preroll(*this, ignore_raster_cache);
    }

    {
      // Traverse the Flutter layer tree so that the necessary session ops to
      // represent the frame are enqueued in the underlying session.
      TRACE_EVENT0("flutter", "UpdateScene");
      layer_tree.UpdateScene(scene_update_context_);
    }

    {
      // Flush all pending session ops: create surfaces and enqueue session
      // Image ops for the frame's paint tasks, then Present.
      TRACE_EVENT0("flutter", "SessionPresent");
      frame_paint_tasks = scene_update_context_.GetPaintTasks();
      for (auto& task : frame_paint_tasks) {
        SkISize physical_size =
            SkISize::Make(layer_tree.device_pixel_ratio() * task.scale_x *
                              task.paint_bounds.width(),
                          layer_tree.device_pixel_ratio() * task.scale_y *
                              task.paint_bounds.height());
        if (physical_size.width() == 0 || physical_size.height() == 0) {
          frame_surfaces.emplace_back(nullptr);
          continue;
        }

        std::unique_ptr<SurfaceProducerSurface> surface =
            surface_producer_.ProduceSurface(physical_size);
        if (!surface) {
          FML_LOG(ERROR)
              << "Could not acquire a surface from the surface producer "
                 "of size: "
              << physical_size.width() << "x" << physical_size.height();
        } else {
          task.material.SetTexture(*(surface->GetImage()));
        }

        frame_surfaces.emplace_back(std::move(surface));
      }

      session_connection_.Present();
    }

    {
      // Execute paint tasks in parallel with Scenic's side of the Present, then
      // signal fences.
      TRACE_EVENT0("flutter", "ExecutePaintTasks");
      size_t surface_index = 0;
      for (auto& task : frame_paint_tasks) {
        std::unique_ptr<SurfaceProducerSurface>& task_surface =
            frame_surfaces[surface_index++];
        if (!task_surface) {
          continue;
        }

        SkCanvas* canvas = task_surface->GetSkiaSurface()->getCanvas();
        flutter::Layer::PaintContext paint_context = {
            canvas,
            canvas,
            gr_context(),
            nullptr,
            context().raster_time(),
            context().ui_time(),
            context().texture_registry(),
            &context().raster_cache(),
            false,
            layer_tree.device_pixel_ratio()};
        canvas->restoreToCount(1);
        canvas->save();
        canvas->clear(task.background_color);
        canvas->scale(layer_tree.device_pixel_ratio() * task.scale_x,
                      layer_tree.device_pixel_ratio() * task.scale_y);
        canvas->translate(-task.paint_bounds.left(), -task.paint_bounds.top());
        for (flutter::Layer* layer : task.layers) {
          layer->Paint(paint_context);
        }
      }

      // Tell the surface producer that a present has occurred so it can perform
      // book-keeping on buffer caches.
      surface_producer_.OnSurfacesPresented(std::move(frame_surfaces));
    }

    return flutter::RasterStatus::kSuccess;
  }

  FML_DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
};

CompositorContext::CompositorContext(
    SessionConnection& session_connection,
    VulkanSurfaceProducer& surface_producer,
    flutter::SceneUpdateContext& scene_update_context)
    : session_connection_(session_connection),
      surface_producer_(surface_producer),
      scene_update_context_(scene_update_context) {}

CompositorContext::~CompositorContext() = default;

std::unique_ptr<flutter::CompositorContext::ScopedFrame>
CompositorContext::AcquireFrame(
    GrDirectContext* gr_context,
    SkCanvas* canvas,
    flutter::ExternalViewEmbedder* view_embedder,
    const SkMatrix& root_surface_transformation,
    bool instrumentation_enabled,
    bool surface_supports_readback,
    fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
  return std::make_unique<flutter_runner::ScopedFrame>(
      *this, gr_context, canvas, view_embedder, root_surface_transformation,
      instrumentation_enabled, surface_supports_readback, raster_thread_merger,
      session_connection_, surface_producer_, scene_update_context_);
}

}  // namespace flutter_runner
