// Copyright 2017 The Fuchsia 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 "vulkan_surface_pool.h"

#include <algorithm>
#include <string>

#include <trace/event.h>

#include "third_party/skia/include/gpu/GrContext.h"

namespace flutter_runner {

namespace {

std::string ToString(const SkISize& size) {
  return "{width: " + std::to_string(size.width()) +
         ", height: " + std::to_string(size.height()) + "}";
}

}  // namespace

VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider,
                                     sk_sp<GrContext> context,
                                     scenic::Session* scenic_session)
    : vulkan_provider_(vulkan_provider),
      context_(std::move(context)),
      scenic_session_(scenic_session) {}

VulkanSurfacePool::~VulkanSurfacePool() {}

std::unique_ptr<VulkanSurface>
VulkanSurfacePool::AcquireSurface(const SkISize& size) {
  auto surface = GetCachedOrCreateSurface(size);

  if (surface == nullptr) {
    FML_DLOG(ERROR) << "Could not acquire surface";
    return nullptr;
  }

  if (!surface->FlushSessionAcquireAndReleaseEvents()) {
    FML_DLOG(ERROR) << "Could not flush acquire/release events for buffer.";
    return nullptr;
  }

  return surface;
}

std::unique_ptr<VulkanSurface>
VulkanSurfacePool::GetCachedOrCreateSurface(const SkISize& size) {
  // First try to find a surface that exactly matches |size|.
  {
    auto exact_match_it =
        std::find_if(available_surfaces_.begin(), available_surfaces_.end(),
                     [&size](const auto& surface) {
                       return surface->IsValid() && surface->GetSize() == size;
                     });
    if (exact_match_it != available_surfaces_.end()) {
      auto acquired_surface = std::move(*exact_match_it);
      available_surfaces_.erase(exact_match_it);
      return acquired_surface;
    }
  }

  // Then, look for a surface that has enough |VkDeviceMemory| to hold a
  // |VkImage| of size |size|, but is currently holding a |VkImage| of a
  // different size.
  VulkanImage vulkan_image;
  if (!CreateVulkanImage(vulkan_provider_, size, &vulkan_image)) {
    FML_DLOG(ERROR) << "Failed to create a VkImage of size: " << ToString(size);
    return nullptr;
  }

  auto best_it = available_surfaces_.end();
  for (auto it = available_surfaces_.begin(); it != available_surfaces_.end();
       ++it) {
    const auto& surface = *it;
    if (!surface->IsValid() || surface->GetAllocationSize() <
                                   vulkan_image.vk_memory_requirements.size) {
      continue;
    }
    if (best_it == available_surfaces_.end() ||
        surface->GetAllocationSize() < (*best_it)->GetAllocationSize()) {
      best_it = it;
    }
  }

  // If no such surface exists, then create a new one.
  if (best_it == available_surfaces_.end()) {
    return CreateSurface(size);
  }

  auto acquired_surface = std::move(*best_it);
  available_surfaces_.erase(best_it);
  bool swap_succeeded =
      acquired_surface->BindToImage(context_, std::move(vulkan_image));
  if (!swap_succeeded) {
    FML_DLOG(ERROR) << "Failed to swap VulkanSurface to new VkImage of size: "
                    << ToString(size);
    return CreateSurface(size);
  }
  FML_DCHECK(acquired_surface->IsValid());
  trace_surfaces_reused_++;
  return acquired_surface;
}

void VulkanSurfacePool::SubmitSurface(
    std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
        p_surface) {
  TRACE_DURATION("flutter", "VulkanSurfacePool::SubmitSurface");

  // This cast is safe because |VulkanSurface| is the only implementation of
  // |SurfaceProducerSurface| for Flutter on Fuchsia.  Additionally, it is
  // required, because we need to access |VulkanSurface| specific information
  // of the surface (such as the amount of VkDeviceMemory it contains).
  auto vulkan_surface = std::unique_ptr<VulkanSurface>(
      static_cast<VulkanSurface*>(p_surface.release()));
  if (!vulkan_surface) {
    return;
  }


  const flutter::LayerRasterCacheKey& retained_key =
      vulkan_surface->GetRetainedKey();
  if (retained_key.id() != 0) {
    // Add the surface to |retained_surfaces_| if its retained key has a valid
    // layer id (|retained_key.id()|).
    //
    // We have to add the entry to |retained_surfaces_| map early when it's
    // still pending (|is_pending| = true). Otherwise (if we add the surface
    // later when |SignalRetainedReady| is called), Flutter would fail to find
    // the retained node before the painting is done (which could take multiple
    // frames). Flutter would then create a new |VulkanSurface| for the layer
    // upon the failed lookup. The new |VulkanSurface| would invalidate this
    // surface, and before the new |VulkanSurface| is done painting, another
    // newer |VulkanSurface| is likely to be created to replace the new
    // |VulkanSurface|. That would make the retained rendering much less useful
    // in improving the performance.
    auto insert_iterator = retained_surfaces_.insert(std::make_pair(
        retained_key,
        RetainedSurface({true, std::move(vulkan_surface)})
    ));
    if (insert_iterator.second) {
      insert_iterator.first->second.vk_surface->SignalWritesFinished(
          std::bind(&VulkanSurfacePool::SignalRetainedReady, this, retained_key));
    }
  } else {
    uintptr_t surface_key = reinterpret_cast<uintptr_t>(vulkan_surface.get());
    auto insert_iterator = pending_surfaces_.insert(std::make_pair(
        surface_key,               // key
        std::move(vulkan_surface)  // value
    ));
    if (insert_iterator.second) {
      insert_iterator.first->second->SignalWritesFinished(
          std::bind(&VulkanSurfacePool::RecyclePendingSurface,
                    this, surface_key));
    }
  }
}

std::unique_ptr<VulkanSurface> VulkanSurfacePool::CreateSurface(
    const SkISize& size) {
  TRACE_DURATION("flutter", "VulkanSurfacePool::CreateSurface", "width",
                 size.width(), "height", size.height());
  auto surface = std::make_unique<VulkanSurface>(vulkan_provider_, context_,
                                                 scenic_session_, size);
  if (!surface->IsValid()) {
    return nullptr;
  }
  trace_surfaces_created_++;
  return surface;
}

void VulkanSurfacePool::RecyclePendingSurface(uintptr_t surface_key) {
  // Before we do anything, we must clear the surface from the collection of
  // pending surfaces.
  auto found_in_pending = pending_surfaces_.find(surface_key);
  if (found_in_pending == pending_surfaces_.end()) {
    return;
  }

  // Grab a hold of the surface to recycle and clear the entry in the pending
  // surfaces collection.
  auto surface_to_recycle = std::move(found_in_pending->second);
  pending_surfaces_.erase(found_in_pending);

  RecycleSurface(std::move(surface_to_recycle));
}

void VulkanSurfacePool::RecycleSurface(std::unique_ptr<VulkanSurface> surface) {
  // The surface may have become invalid (for example it the fences could
  // not be reset).
  if (!surface->IsValid()) {
    return;
  }

  // Recycle the buffer by putting it in the list of available surfaces if we
  // have not reached the maximum amount of cached surfaces.
  if (available_surfaces_.size() < kMaxSurfaces) {
    available_surfaces_.push_back(std::move(surface));
  }
}

void VulkanSurfacePool::RecycleRetainedSurface(
    const flutter::LayerRasterCacheKey& key) {
  auto it = retained_surfaces_.find(key);
  if (it == retained_surfaces_.end()) {
    return;
  }

  // The surface should not be pending.
  FML_DCHECK(!it->second.is_pending);

  auto surface_to_recycle = std::move(it->second.vk_surface);
  retained_surfaces_.erase(it);
  RecycleSurface(std::move(surface_to_recycle));
}

void VulkanSurfacePool::SignalRetainedReady(flutter::LayerRasterCacheKey key) {
  retained_surfaces_[key].is_pending = false;
}

void VulkanSurfacePool::AgeAndCollectOldBuffers() {
  TRACE_DURATION("flutter", "VulkanSurfacePool::AgeAndCollectOldBuffers");

  // Remove all surfaces that are no longer valid or are too old.
  available_surfaces_.erase(
      std::remove_if(available_surfaces_.begin(), available_surfaces_.end(),
                     [&](auto& surface) {
                       return !surface->IsValid() ||
                              surface->AdvanceAndGetAge() >= kMaxSurfaceAge;
                     }),
      available_surfaces_.end());

  // Look for a surface that has both a larger |VkDeviceMemory| allocation
  // than is necessary for its |VkImage|, and has a stable size history.
  auto surface_to_remove_it = std::find_if(
      available_surfaces_.begin(), available_surfaces_.end(),
      [](const auto& surface) {
        return surface->IsOversized() && surface->HasStableSizeHistory();
      });
  // If we found such a surface, then destroy it and cache a new one that only
  // uses a necessary amount of memory.
  if (surface_to_remove_it != available_surfaces_.end()) {
    auto size = (*surface_to_remove_it)->GetSize();
    available_surfaces_.erase(surface_to_remove_it);
    auto new_surface = CreateSurface(size);
    if (new_surface != nullptr) {
      available_surfaces_.push_back(std::move(new_surface));
    } else {
      FML_DLOG(ERROR) << "Failed to create a new shrunk surface";
    }
  }

  // Recycle retained surfaces that are not used and not pending in this frame.
  //
  // It's safe to recycle any retained surfaces that are not pending no matter
  // whether they're used or not. Hence if there's memory pressure, feel free to
  // recycle all retained surfaces that are not pending.
  std::vector<flutter::LayerRasterCacheKey> recycle_keys;
  for (auto&[key, retained_surface] : retained_surfaces_) {
    if (retained_surface.is_pending ||
      retained_surface.vk_surface->IsUsedInRetainedRendering()) {
      // Reset the flag for the next frame
      retained_surface.vk_surface->ResetIsUsedInRetainedRendering();
    } else {
      recycle_keys.push_back(key);
    }
  }
  for (auto& key : recycle_keys) {
    RecycleRetainedSurface(key);
  }

  TraceStats();
}

void VulkanSurfacePool::ShrinkToFit() {
  // Reset all oversized surfaces in |available_surfaces_| so that the old
  // surfaces and new surfaces don't exist at the same time at any point,
  // reducing our peak memory footprint.
  std::vector<SkISize> sizes_to_recreate;
  for (auto& surface : available_surfaces_) {
    if (surface->IsOversized()) {
      sizes_to_recreate.push_back(surface->GetSize());
      surface.reset();
    }
  }
  available_surfaces_.erase(std::remove(available_surfaces_.begin(),
                                        available_surfaces_.end(), nullptr),
                            available_surfaces_.end());
  for (const auto& size : sizes_to_recreate) {
    auto surface = CreateSurface(size);
    if (surface != nullptr) {
      available_surfaces_.push_back(std::move(surface));
    } else {
      FML_DLOG(ERROR) << "Failed to create resized surface";
    }
  }

  TraceStats();
}

void VulkanSurfacePool::TraceStats() {
  // Resources held in cached buffers.
  size_t cached_surfaces = 0;
  size_t cached_surfaces_bytes = 0;

  for (const auto& surface : available_surfaces_) {
    cached_surfaces++;
    cached_surfaces_bytes += surface->GetAllocationSize();
  }

  // Resources held by Skia.
  int skia_resources = 0;
  size_t skia_bytes = 0;
  context_->getResourceCacheUsage(&skia_resources, &skia_bytes);
  const size_t skia_cache_purgeable =
      context_->getResourceCachePurgeableBytes();

  TRACE_COUNTER("flutter", "SurfacePool", 0u,                     //
                "CachedCount", cached_surfaces,                   //
                "CachedBytes", cached_surfaces_bytes,             //
                "Created", trace_surfaces_created_,               //
                "Reused", trace_surfaces_reused_,                 //
                "PendingInCompositor", pending_surfaces_.size(),  //
                "Retained", retained_surfaces_.size(),            //
                "SkiaCacheResources", skia_resources,             //
                "SkiaCacheBytes", skia_bytes,                     //
                "SkiaCachePurgeable", skia_cache_purgeable        //
  );

  // Reset per present/frame stats.
  trace_surfaces_created_ = 0;
  trace_surfaces_reused_ = 0;
}

}  // namespace flutter_runner
