// Copyright 2023 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 "src/graphics/display/lib/framebuffer-display/framebuffer-display.h"

#include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
#include <fidl/fuchsia.hardware.sysmem/cpp/wire_test_base.h>
#include <fidl/fuchsia.sysmem2/cpp/wire.h>
#include <fidl/fuchsia.sysmem2/cpp/wire_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/wait.h>
#include <lib/driver/testing/cpp/scoped_global_logger.h>
#include <lib/fit/defer.h>
#include <lib/zx/object.h>
#include <lib/zx/result.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <zircon/rights.h>

#include <list>
#include <memory>

#include <bind/fuchsia/sysmem/heap/cpp/bind.h>
#include <fake-mmio-reg/fake-mmio-reg.h>
#include <gtest/gtest.h>

#include "src/graphics/display/lib/api-protocols/cpp/display-engine-events-fidl.h"
#include "src/graphics/display/lib/api-types/cpp/driver-buffer-collection-id.h"
#include "src/graphics/display/lib/api-types/cpp/image-buffer-usage.h"
#include "src/graphics/display/lib/api-types/cpp/image-metadata.h"
#include "src/graphics/display/lib/api-types/cpp/image-tiling-type.h"
#include "src/graphics/display/lib/api-types/cpp/pixel-format.h"
#include "src/lib/fsl/handles/object_info.h"
#include "src/lib/testing/predicates/status.h"

namespace framebuffer_display {

namespace {

// TODO(https://fxbug.dev/42072949): Consider creating and using a unified set of sysmem
// testing doubles instead of writing mocks for each display driver test.
class FakeBufferCollection : public fidl::testing::WireTestBase<fuchsia_sysmem2::BufferCollection> {
 public:
  explicit FakeBufferCollection(zx::unowned_vmo framebuffer_vmo)
      : framebuffer_vmo_(std::move(framebuffer_vmo)) {}

  void SetConstraints(::fuchsia_sysmem2::wire::BufferCollectionSetConstraintsRequest* request,
                      SetConstraintsCompleter::Sync& completer) override {}
  void CheckAllBuffersAllocated(CheckAllBuffersAllocatedCompleter::Sync& completer) override {
    completer.ReplySuccess();
  }
  void WaitForAllBuffersAllocated(WaitForAllBuffersAllocatedCompleter::Sync& completer) override {
    zx::vmo vmo;
    EXPECT_OK(framebuffer_vmo_->duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));

    fidl::Arena arena;
    auto response =
        fuchsia_sysmem2::wire::BufferCollectionWaitForAllBuffersAllocatedResponse::Builder(arena);
    auto collection_info = fuchsia_sysmem2::wire::BufferCollectionInfo::Builder(arena);
    auto single_buffer_settings = fuchsia_sysmem2::wire::SingleBufferSettings::Builder(arena);
    auto buffer_memory_settings = fuchsia_sysmem2::wire::BufferMemorySettings::Builder(arena);
    auto heap = fuchsia_sysmem2::wire::Heap::Builder(arena);
    heap.heap_type(arena, bind_fuchsia_sysmem_heap::HEAP_TYPE_FRAMEBUFFER);
    // no need to set heap.id - defaults to 0 server-side
    buffer_memory_settings.heap(heap.Build());
    single_buffer_settings.buffer_settings(buffer_memory_settings.Build());
    auto image_format_constraints = fuchsia_sysmem2::wire::ImageFormatConstraints::Builder(arena);
    image_format_constraints.pixel_format(fuchsia_images2::wire::PixelFormat::kB8G8R8A8);
    image_format_constraints.pixel_format_modifier(
        fuchsia_images2::wire::PixelFormatModifier::kLinear);
    single_buffer_settings.image_format_constraints(image_format_constraints.Build());
    collection_info.settings(single_buffer_settings.Build());
    auto vmo_buffer = fuchsia_sysmem2::wire::VmoBuffer::Builder(arena);
    vmo_buffer.vmo(std::move(vmo));
    vmo_buffer.vmo_usable_start(0);
    collection_info.buffers(std::array{vmo_buffer.Build()});
    response.buffer_collection_info(collection_info.Build());

    completer.ReplySuccess(response.Build());
  }

  void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {}

 private:
  zx::unowned_vmo framebuffer_vmo_;
};

using BufferCollectionId = uint64_t;

class FakeSysmemBase {
 public:
  virtual BufferCollectionId AllocBufferCollectionId() = 0;
  virtual std::optional<std::pair<uint64_t, uint32_t>> GetFakeVmoInfo() = 0;
};

class MockAllocator : public fidl::testing::WireTestBase<fuchsia_sysmem2::Allocator> {
 public:
  explicit MockAllocator(FakeSysmemBase& parent, async_dispatcher_t* dispatcher,
                         zx::unowned_vmo framebuffer_vmo)
      : parent_(parent), dispatcher_(dispatcher), framebuffer_vmo_(std::move(framebuffer_vmo)) {
    ZX_ASSERT(dispatcher_);
  }

  void BindSharedCollection(BindSharedCollectionRequestView request,
                            BindSharedCollectionCompleter::Sync& completer) override {
    auto buffer_collection_id = parent_.AllocBufferCollectionId();
    active_buffer_collections_.emplace(
        buffer_collection_id,
        BufferCollection{
            .token_client = std::move(request->token()),
            .unowned_collection_server = request->buffer_collection_request(),
            .fake_buffer_collection = FakeBufferCollection(framebuffer_vmo_->borrow())});
    fidl::BindServer(
        dispatcher_, std::move(request->buffer_collection_request()),
        &active_buffer_collections_.at(buffer_collection_id).fake_buffer_collection,
        [this, buffer_collection_id](FakeBufferCollection*, fidl::UnbindInfo,
                                     fidl::ServerEnd<fuchsia_sysmem2::BufferCollection>) {
          inactive_buffer_collection_tokens_.push_back(
              std::move(active_buffer_collections_.at(buffer_collection_id).token_client));
          active_buffer_collections_.erase(buffer_collection_id);
        });
  }

  void GetVmoInfo(GetVmoInfoRequestView request, GetVmoInfoCompleter::Sync& completer) override {
    auto fake_vmo_info_result = parent_.GetFakeVmoInfo();
    // Call SetupFakeVmoInfo() in the test before GetVmoInfo() gets called.
    ZX_ASSERT(fake_vmo_info_result.has_value());
    fidl::Arena arena;
    auto response = fuchsia_sysmem2::wire::AllocatorGetVmoInfoResponse::Builder(arena);
    response.buffer_collection_id(fake_vmo_info_result->first);
    response.buffer_index(fake_vmo_info_result->second);

    completer.ReplySuccess(response.Build());
  }

  std::vector<std::pair<fidl::UnownedClientEnd<fuchsia_sysmem2::BufferCollectionToken>,
                        fidl::UnownedServerEnd<fuchsia_sysmem2::BufferCollection>>>
  GetBufferCollectionConnections() {
    if (active_buffer_collections_.empty()) {
      return {};
    }

    std::vector<std::pair<fidl::UnownedClientEnd<fuchsia_sysmem2::BufferCollectionToken>,
                          fidl::UnownedServerEnd<fuchsia_sysmem2::BufferCollection>>>
        result;
    for (const auto& kv : active_buffer_collections_) {
      result.emplace_back(kv.second.token_client, kv.second.unowned_collection_server);
    }
    return result;
  }

  void SetDebugClientInfo(SetDebugClientInfoRequestView request,
                          SetDebugClientInfoCompleter::Sync& completer) override {
    EXPECT_EQ(request->name().get().find("framebuffer-display"), 0u);
  }

  void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
    fdf::error("{} not implemented", name);
    EXPECT_TRUE(false);
  }

 private:
  struct BufferCollection {
    fidl::ClientEnd<fuchsia_sysmem2::BufferCollectionToken> token_client;
    fidl::UnownedServerEnd<fuchsia_sysmem2::BufferCollection> unowned_collection_server;
    FakeBufferCollection fake_buffer_collection;
  };

  FakeSysmemBase& parent_;
  std::unordered_map<BufferCollectionId, BufferCollection> active_buffer_collections_;
  std::vector<fidl::ClientEnd<fuchsia_sysmem2::BufferCollectionToken>>
      inactive_buffer_collection_tokens_;

  async_dispatcher_t* dispatcher_ = nullptr;
  zx::unowned_vmo framebuffer_vmo_;
};

class FakeSysmem : public fidl::testing::WireTestBase<fuchsia_hardware_sysmem::Sysmem>,
                   public FakeSysmemBase {
 public:
  explicit FakeSysmem(async_dispatcher_t* dispatcher, zx::unowned_vmo framebuffer_vmo,
                      uint64_t first_buffer_collection_id)
      : dispatcher_(dispatcher),
        framebuffer_vmo_(std::move(framebuffer_vmo)),
        next_buffer_collection_id_(first_buffer_collection_id) {
    EXPECT_TRUE(dispatcher_);
  }

  fit::result<zx_status_t, fidl::WireSyncClient<fuchsia_sysmem2::Allocator>>
  MakeFakeSysmemAllocator() {
    auto [sysmem_client, sysmem_server] = fidl::Endpoints<fuchsia_sysmem2::Allocator>::Create();

    mock_allocators_.emplace_front(*this, dispatcher_, framebuffer_vmo_->borrow());
    auto it = mock_allocators_.begin();
    fidl::BindServer(dispatcher_, std::move(sysmem_server), &*it);

    return fit::ok(fidl::WireSyncClient(std::move(sysmem_client)));
  }

  std::list<MockAllocator>& mock_allocators() { return mock_allocators_; }

  // FIDL methods
  void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) final {
    completer.Close(ZX_ERR_NOT_SUPPORTED);
  }

  BufferCollectionId AllocBufferCollectionId() override { return next_buffer_collection_id_++; }

  std::optional<std::pair<uint64_t, uint32_t>> GetFakeVmoInfo() override { return fake_vmo_info_; }

  void SetupFakeVmoInfo(uint64_t buffer_collection_id, uint32_t buffer_index) {
    fake_vmo_info_.emplace(std::make_pair(buffer_collection_id, buffer_index));
  }

 private:
  friend class MockAllocator;
  std::list<MockAllocator> mock_allocators_;
  async_dispatcher_t* dispatcher_ = nullptr;
  zx::unowned_vmo framebuffer_vmo_ = {};
  BufferCollectionId next_buffer_collection_id_ = 0;
  std::optional<std::pair<uint64_t, uint32_t>> fake_vmo_info_;
};

class FakeMmio {
 public:
  FakeMmio() {
    mmio_ = std::make_unique<ddk_fake::FakeMmioRegRegion>(sizeof(uint32_t), kRegArrayLength);
  }

  fdf::MmioBuffer MmioBuffer() { return mmio_->GetMmioBuffer(); }

  ddk_fake::FakeMmioReg& FakeRegister(size_t address) { return (*mmio_)[address]; }

 private:
  static constexpr size_t kMmioBufferSize = 0x5000;
  static constexpr size_t kRegArrayLength = kMmioBufferSize / sizeof(uint32_t);
  std::unique_ptr<ddk_fake::FakeMmioRegRegion> mmio_;
};

class FramebufferDisplayTest : public ::testing::Test {
 protected:
  fdf_testing::ScopedGlobalLogger logger_;
  display::DisplayEngineEventsFidl engine_events_;
};

void ExpectHandlesArePaired(zx_handle_t lhs, zx_handle_t rhs) {
  auto [lhs_koid, lhs_related_koid] = fsl::GetKoids(lhs);
  auto [rhs_koid, rhs_related_koid] = fsl::GetKoids(rhs);

  EXPECT_NE(lhs_koid, ZX_KOID_INVALID);
  EXPECT_NE(lhs_related_koid, ZX_KOID_INVALID);
  EXPECT_NE(rhs_koid, ZX_KOID_INVALID);
  EXPECT_NE(rhs_related_koid, ZX_KOID_INVALID);

  EXPECT_EQ(lhs_koid, rhs_related_koid);
  EXPECT_EQ(rhs_koid, lhs_related_koid);
}

template <typename T>
void ExpectObjectsArePaired(zx::unowned<T> lhs, zx::unowned<T> rhs) {
  return ExpectHandlesArePaired(lhs->get(), rhs->get());
}

TEST_F(FramebufferDisplayTest, ImportBufferCollection) {
  async::Loop env_loop(&kAsyncLoopConfigAttachToCurrentThread);
  FakeSysmem fake_sysmem(env_loop.dispatcher(), /*framebuffer_vmo=*/{}, 0);
  FakeMmio fake_mmio;

  auto [sysmem_hardware_client, sysmem_hardware_server] =
      fidl::Endpoints<fuchsia_hardware_sysmem::Sysmem>::Create();
  fidl::BindServer(env_loop.dispatcher(), std::move(sysmem_hardware_server), &fake_sysmem);

  auto sysmem_client_result = fake_sysmem.MakeFakeSysmemAllocator();
  ASSERT_TRUE(sysmem_client_result.is_ok());
  auto& sysmem_client = sysmem_client_result.value();

  constexpr int32_t kWidthPx = 800;
  constexpr int32_t kHeightPx = 600;
  constexpr int32_t kStridePx = 800;
  constexpr auto kPixelFormat = display::PixelFormat::kB8G8R8A8;
  constexpr DisplayProperties kDisplayProperties = {
      .width_px = kWidthPx,
      .height_px = kHeightPx,
      .row_stride_px = kStridePx,
      .pixel_format = kPixelFormat,
  };

  async::Loop display_loop(&kAsyncLoopConfigNeverAttachToThread);
  display_loop.StartThread("framebuffer-display-loop");
  FramebufferDisplay display(&engine_events_, std::move(sysmem_client),
                             fidl::WireSyncClient(std::move(sysmem_hardware_client)),
                             fake_mmio.MmioBuffer(), kDisplayProperties, display_loop.dispatcher());

  auto token1_endpoints = fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();
  auto token2_endpoints = fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();

  // Test ImportBufferCollection().
  const display::DriverBufferCollectionId kValidCollectionId(1);
  EXPECT_OK(display.ImportBufferCollection(kValidCollectionId, std::move(token1_endpoints.client)));

  // `collection_id` must be unused.
  EXPECT_STATUS(
      display.ImportBufferCollection(kValidCollectionId, std::move(token2_endpoints.client)),
      zx::error(ZX_ERR_ALREADY_EXISTS));

  env_loop.RunUntilIdle();

  EXPECT_EQ(fake_sysmem.mock_allocators().size(), 1u);
  auto& allocator = fake_sysmem.mock_allocators().front();

  // Verify that the current buffer collection token is used.
  {
    const std::vector buffer_collection_connections = allocator.GetBufferCollectionConnections();
    ASSERT_EQ(buffer_collection_connections.size(), 1u);

    const auto& buffer_collection_server = buffer_collection_connections[0].second;
    const auto& buffer_collection_client =
        display.GetBufferCollectionsForTesting().at(kValidCollectionId).client_end();
    ExpectObjectsArePaired(buffer_collection_server.handle(), buffer_collection_client.handle());

    const auto& buffer_collection_token_server = token1_endpoints.server;
    const auto& buffer_collection_token_client = buffer_collection_connections[0].first;
    ExpectObjectsArePaired(buffer_collection_token_server.handle(),
                           buffer_collection_token_client.handle());
  }

  // Test ReleaseBufferCollection().
  const display::DriverBufferCollectionId kInvalidCollectionId(2);
  EXPECT_STATUS(display.ReleaseBufferCollection(kInvalidCollectionId), zx::error(ZX_ERR_NOT_FOUND));
  EXPECT_OK(display.ReleaseBufferCollection(kValidCollectionId));

  env_loop.RunUntilIdle();

  // Verify that the current buffer collection token is released.
  {
    const std::vector buffer_collection_connections = allocator.GetBufferCollectionConnections();
    ASSERT_EQ(buffer_collection_connections.size(), 0u);
  }

  // Shutdown the loop before destroying the FakeSysmem and MockAllocator which
  // may still have pending callbacks.
  env_loop.Shutdown();
  display_loop.Shutdown();
}

TEST_F(FramebufferDisplayTest, ImportKernelFramebufferImage) {
  constexpr int32_t kWidthPx = 800;
  constexpr int32_t kHeightPx = 600;
  constexpr int32_t kStridePx = 800;
  constexpr display::PixelFormat kPixelFormat = display::PixelFormat::kB8G8R8A8;
  constexpr size_t kBytesPerPixel = 4;
  const display::DriverBufferCollectionId kBufferCollectionId(1);
  constexpr size_t kImageBytes = uint64_t{kStridePx} * kHeightPx * kBytesPerPixel;

  // `framebuffer_vmo` must outlive `fake_sysmem`.
  zx::vmo framebuffer_vmo;
  EXPECT_OK(zx::vmo::create(/*size=*/kImageBytes, /*options=*/0, &framebuffer_vmo));

  async::Loop env_loop(&kAsyncLoopConfigNeverAttachToThread);
  FakeSysmem fake_sysmem(env_loop.dispatcher(), framebuffer_vmo.borrow(),
                         kBufferCollectionId.value());
  FakeMmio fake_mmio;

  env_loop.StartThread("env-loop");

  auto [sysmem_hardware_client, sysmem_hardware_server] =
      fidl::Endpoints<fuchsia_hardware_sysmem::Sysmem>::Create();
  fidl::BindServer(env_loop.dispatcher(), std::move(sysmem_hardware_server), &fake_sysmem);

  auto sysmem_client_result = fake_sysmem.MakeFakeSysmemAllocator();
  ASSERT_TRUE(sysmem_client_result.is_ok());
  auto& sysmem_client = sysmem_client_result.value();

  constexpr DisplayProperties kDisplayProperties = {
      .width_px = kWidthPx,
      .height_px = kHeightPx,
      .row_stride_px = kStridePx,
      .pixel_format = kPixelFormat,
  };

  async::Loop display_loop(&kAsyncLoopConfigNeverAttachToThread);
  display_loop.StartThread("framebuffer-display-loop");
  FramebufferDisplay display(&engine_events_, std::move(sysmem_client),
                             fidl::WireSyncClient(std::move(sysmem_hardware_client)),
                             fake_mmio.MmioBuffer(), kDisplayProperties, display_loop.dispatcher());
  auto token_endpoints = fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();

  // Import BufferCollection.
  EXPECT_OK(display.ImportBufferCollection(kBufferCollectionId, std::move(token_endpoints.client)));

  // Set Buffer collection constraints.
  static constexpr display::ImageBufferUsage kDisplayUsage({
      .tiling_type = display::ImageTilingType::kLinear,
  });
  EXPECT_OK(display.SetBufferCollectionConstraints(kDisplayUsage, kBufferCollectionId));

  auto [heap_client, heap_server] = fidl::Endpoints<fuchsia_hardware_sysmem::Heap>::Create();
  auto bind_ref = fidl::BindServer(env_loop.dispatcher(), std::move(heap_server), &display);
  fidl::WireSyncClient heap{std::move(heap_client)};

  fidl::Arena arena;
  // At least for now we use empty settings, because currently FramebufferDisplay doesn't pay
  // attention to any settings, so this way if that changes, this test will fail intentionally so
  // that this test can be updated to have settings that achieve this test's goals.
  auto settings = fuchsia_sysmem2::wire::SingleBufferSettings::Builder(arena);
  fidl::WireResult<fuchsia_hardware_sysmem::Heap::AllocateVmo> fidl_transport_result =
      heap->AllocateVmo(0, settings.Build(), kBufferCollectionId.value(), 0);
  ASSERT_TRUE(fidl_transport_result.ok()) << fidl_transport_result.FormatDescription();
  fit::result<zx_status_t, fuchsia_hardware_sysmem::wire::HeapAllocateVmoResponse*>&
      fidl_domain_result = fidl_transport_result.value();
  EXPECT_OK(fidl_domain_result);

  bind_ref.Unbind();

  fake_sysmem.SetupFakeVmoInfo(kBufferCollectionId.value(), 0);

  // Invalid import: bad collection id
  static constexpr display::ImageMetadata kDisplayImageMetadata(
      {.width = kWidthPx, .height = kHeightPx, .tiling_type = display::ImageTilingType::kLinear});
  static constexpr uint32_t kIndex = 0;
  display::DriverBufferCollectionId kInvalidCollectionId(100);
  EXPECT_STATUS(display.ImportImage(kDisplayImageMetadata, kInvalidCollectionId, kIndex),
                zx::error(ZX_ERR_NOT_FOUND));

  // Invalid import: bad index
  uint32_t kInvalidIndex = 100;
  EXPECT_STATUS(display.ImportImage(kDisplayImageMetadata, kBufferCollectionId, kInvalidIndex),
                zx::error(ZX_ERR_OUT_OF_RANGE));

  // Invalid import: bad width
  static constexpr display::ImageMetadata kImageMetadataWithIncorrectWidth({
      .width = kWidthPx * 2,
      .height = kHeightPx,
      .tiling_type = display::ImageTilingType::kLinear,
  });
  EXPECT_STATUS(display.ImportImage(kImageMetadataWithIncorrectWidth, kBufferCollectionId, kIndex),
                zx::error(ZX_ERR_INVALID_ARGS));

  // Invalid import: bad height
  static constexpr display::ImageMetadata kImageMetadataWithIncorrectHeight({
      .width = kWidthPx,
      .height = kHeightPx * 2,
      .tiling_type = display::ImageTilingType::kLinear,
  });
  EXPECT_STATUS(display.ImportImage(kImageMetadataWithIncorrectHeight, kBufferCollectionId, kIndex),
                zx::error(ZX_ERR_INVALID_ARGS));

  // Valid import
  zx::result<display::DriverImageId> valid_import_result =
      display.ImportImage(kDisplayImageMetadata, kBufferCollectionId, kIndex);
  ASSERT_OK(valid_import_result);
  EXPECT_NE(display::kInvalidDriverImageId, valid_import_result.value());

  // Release buffer collection.
  EXPECT_OK(display.ReleaseBufferCollection(kBufferCollectionId));

  env_loop.RunUntilIdle();

  // Shutdown the loop before destroying the FakeSysmem and MockAllocator which
  // may still have pending callbacks.
  env_loop.Shutdown();
  display_loop.Shutdown();
}

}  // namespace

}  // namespace framebuffer_display
