// Copyright 2022 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/drivers/intel-i915/pipe.h"

#include <lib/mmio-ptr/fake.h>
#include <lib/mmio/mmio.h>
#include <lib/sysmem-version/sysmem-version.h>

#include <memory>
#include <vector>

#include <fake-mmio-reg/fake-mmio-reg.h>
#include <gtest/gtest.h>

#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
#include "src/graphics/display/drivers/intel-i915/registers-pipe.h"
#include "src/graphics/display/lib/api-types-cpp/config-stamp.h"

namespace i915 {

class PipeTest : public ::testing::Test {
 public:
  PipeTest() = default;

  void SetUp() override { mmio_buffer_.emplace(reg_region_.GetMmioBuffer()); }

  void TearDown() override {}

 protected:
  constexpr static uint32_t kMinimumRegCount = 0xd0000 / sizeof(uint32_t);
  ddk_fake::FakeMmioRegRegion reg_region_{sizeof(uint32_t), kMinimumRegCount};
  std::optional<fdf::MmioBuffer> mmio_buffer_;
};

namespace {

class TestGttRegionImpl : public GttRegion {
 public:
  explicit TestGttRegionImpl(uint64_t handle) : handle_(handle) {}

  uint64_t bytes_per_row() const override { return 64; }
  uint64_t base() const override { return handle_ + 0xf0000000; }

 private:
  uint64_t handle_ = 0;
};

std::map<uint64_t, TestGttRegionImpl> region_map;

PixelFormatAndModifier GetPixelFormat(uint64_t image_handle) {
  return PixelFormatAndModifier(
      fuchsia_images2::PixelFormat::kB8G8R8A8,
      /*pixel_format_modifier_param=*/fuchsia_images2::PixelFormatModifier::kLinear);
}

const GttRegion& GetGttImageHandle(const image_metadata_t& image_metadata, uint64_t image_handle,
                                   uint32_t rotation) {
  auto it = region_map.find(image_handle);
  if (it != region_map.end()) {
    return it->second;
  }
  return region_map.try_emplace(image_handle, image_handle).first->second;
}

layer_t CreatePrimaryLayerConfig(uint64_t handle, uint32_t z_index = 1u) {
  uint32_t kWidth = 1024u;
  uint32_t kHeight = 768u;

  layer_t layer;
  layer.type = LAYER_TYPE_PRIMARY;
  layer.z_index = z_index;
  layer.cfg.primary = {
      .image_handle = handle,
      .image_metadata =
          {
              .width = kWidth,
              .height = kHeight,
              .tiling_type = IMAGE_TILING_TYPE_LINEAR,
          },
      .alpha_mode = ALPHA_DISABLE,
      .transform_mode = FRAME_TRANSFORM_IDENTITY,
      .src_frame = {0, 0, kWidth, kHeight},
      .dest_frame = {0, 0, kWidth, kHeight},
  };
  return layer;
}

}  // namespace

TEST_F(PipeTest, TiedTranscoderId) {
  PipeSkylake pipe_a(&mmio_buffer_.value(), PipeId::PIPE_A, {});
  EXPECT_EQ(TranscoderId::TRANSCODER_A, pipe_a.tied_transcoder_id());

  PipeSkylake pipe_b(&mmio_buffer_.value(), PipeId::PIPE_B, {});
  EXPECT_EQ(TranscoderId::TRANSCODER_B, pipe_b.tied_transcoder_id());

  PipeSkylake pipe_c(&mmio_buffer_.value(), PipeId::PIPE_C, {});
  EXPECT_EQ(TranscoderId::TRANSCODER_C, pipe_c.tied_transcoder_id());

  // TODO(https://fxbug.dev/42060657): Add a test for transcoder D, when we support it.
}

// Verifies that GetVsyncConfigStamp() could return the correct config stamp
// given different image handles from device registers.
TEST_F(PipeTest, GetVsyncConfigStamp) {
  PipeSkylake pipe(&*mmio_buffer_, PipeId::PIPE_A, {});

  uint64_t kImageHandle1 = 0x1111u;
  uint64_t kImageHandle2 = 0x2222u;
  uint64_t kImageHandle3 = 0x3333u;
  layer_t layer_1 = CreatePrimaryLayerConfig(kImageHandle1, 1u);
  layer_t layer_2 = CreatePrimaryLayerConfig(kImageHandle2, 1u);
  layer_t layer_3 = CreatePrimaryLayerConfig(kImageHandle3, 2u);

  // Applies configuration with only one layer (layer_1).
  const layer_t* test_layers_1[] = {&layer_1};
  display_config_t config = {
      .display_id = 1u,
      .mode = {},
      .cc_flags = 0u,
      .layer_list = test_layers_1,
      .layer_count = 1,
  };
  display::ConfigStamp stamp_1{1};
  pipe.ApplyConfiguration(&config, stamp_1, GetGttImageHandle, GetPixelFormat);

  // For images that are not registered with Pipe yet, GetVsyncConfigStamp()
  // should return nullopt.
  display::ConfigStamp vsync_config_stamp_not_found = pipe.GetVsyncConfigStamp({kImageHandle2});
  EXPECT_EQ(vsync_config_stamp_not_found, display::kInvalidConfigStamp);

  // Otherwise, for a valid image handle that has occurred in a past config,
  // GetVsyncConfigStamp() should return the latest config where it occurred.
  display::ConfigStamp vsync_config_stamp_1 = pipe.GetVsyncConfigStamp({kImageHandle1});
  EXPECT_NE(vsync_config_stamp_1, display::kInvalidConfigStamp);
  EXPECT_EQ(vsync_config_stamp_1, stamp_1);

  // Applies another configuration with two layers (layer_2 replacing layer_1,
  // and a new layer layer_3).
  const layer_t* test_layers_2[] = {&layer_2, &layer_3};
  display_config_t config_2 = {
      .display_id = 1u,
      .mode = {},
      .cc_flags = 0u,
      .layer_list = test_layers_2,
      .layer_count = 1,
  };
  display::ConfigStamp stamp_2{2};
  pipe.ApplyConfiguration(&config_2, stamp_2, GetGttImageHandle, GetPixelFormat);

  // It is possible that a layer update is slower than other layers, so on
  // Vsync time the device may have layers from different configurations. In
  // that case, the device should return the oldest configuration stamp, i.e.
  // stamp_1.
  display::ConfigStamp vsync_config_stamp_2 =
      pipe.GetVsyncConfigStamp({kImageHandle1, kImageHandle3});
  EXPECT_NE(vsync_config_stamp_2, display::kInvalidConfigStamp);
  EXPECT_EQ(vsync_config_stamp_2, stamp_1);

  // Now both layers are updated in another new Vsync. GetVsyncConfigStamp()
  // should return the updated stamp value.
  display::ConfigStamp vsync_config_stamp_3 =
      pipe.GetVsyncConfigStamp({kImageHandle2, kImageHandle3});
  EXPECT_NE(vsync_config_stamp_3, display::kInvalidConfigStamp);
  EXPECT_EQ(vsync_config_stamp_3, stamp_2);

  // Old image handle should be evicted from Pipe completely.
  display::ConfigStamp vsync_config_stamp_4 =
      pipe.GetVsyncConfigStamp({kImageHandle1, kImageHandle3});
  EXPECT_EQ(vsync_config_stamp_4, display::kInvalidConfigStamp);
}

}  // namespace i915
