/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "drmhwc"

#include "HwcDisplayConfigs.h"

#include <cmath>
#include <cstring>

#include "drm/DrmConnector.h"
#include "utils/log.h"

constexpr uint32_t kHeadlessModeDisplayWidthMm = 163;
constexpr uint32_t kHeadlessModeDisplayHeightMm = 122;
constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
constexpr uint32_t kSyncLen = 10;
constexpr uint32_t kBackPorch = 10;
constexpr uint32_t kFrontPorch = 10;
constexpr uint32_t kHzInKHz = 1000;

namespace android {

// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
uint32_t HwcDisplayConfigs::last_config_id = 1;

void HwcDisplayConfigs::GenFakeMode(uint16_t width, uint16_t height) {
  hwc_configs.clear();

  last_config_id++;
  preferred_config_id = active_config_id = last_config_id;
  auto headless_drm_mode_info = (drmModeModeInfo){
      .hdisplay = width,
      .vdisplay = height,
      .vrefresh = kHeadlessModeDisplayVRefresh,
      .name = "VIRTUAL-MODE",
  };

  if (width == 0 || height == 0) {
    strcpy(headless_drm_mode_info.name, "HEADLESS-MODE");
    headless_drm_mode_info.hdisplay = kHeadlessModeDisplayWidthPx;
    headless_drm_mode_info.vdisplay = kHeadlessModeDisplayHeightPx;
  }

  /* We need a valid mode to pass the kernel validation */

  headless_drm_mode_info.hsync_start = headless_drm_mode_info.hdisplay +
                                       kFrontPorch;
  headless_drm_mode_info.hsync_end = headless_drm_mode_info.hsync_start +
                                     kSyncLen;
  headless_drm_mode_info.htotal = headless_drm_mode_info.hsync_end + kBackPorch;

  headless_drm_mode_info.vsync_start = headless_drm_mode_info.vdisplay +
                                       kFrontPorch;
  headless_drm_mode_info.vsync_end = headless_drm_mode_info.vsync_start +
                                     kSyncLen;
  headless_drm_mode_info.vtotal = headless_drm_mode_info.vsync_end + kBackPorch;

  headless_drm_mode_info.clock = (headless_drm_mode_info.htotal *
                                  headless_drm_mode_info.vtotal *
                                  headless_drm_mode_info.vrefresh) /
                                 kHzInKHz;

  hwc_configs[active_config_id] = (HwcDisplayConfig){
      .id = active_config_id,
      .group_id = 1,
      .mode = DrmMode(&headless_drm_mode_info),
  };

  mm_width = kHeadlessModeDisplayWidthMm;
  mm_height = kHeadlessModeDisplayHeightMm;
}

// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
  /* In case UpdateModes will fail we will still have one mode for headless
   * mode
   */
  GenFakeMode(0, 0);
  /* Read real configs */
  auto ret = connector.UpdateModes();
  if (ret != 0) {
    ALOGE("Failed to update display modes %d", ret);
    return HWC2::Error::BadDisplay;
  }

  if (connector.GetModes().empty()) {
    ALOGE("No modes reported by KMS");
    return HWC2::Error::BadDisplay;
  }

  hwc_configs.clear();
  mm_width = connector.GetMmWidth();
  mm_height = connector.GetMmHeight();

  preferred_config_id = 0;
  uint32_t preferred_config_group_id = 0;

  auto first_config_id = last_config_id;
  uint32_t last_group_id = 1;

  /* Group modes */
  for (const auto &mode : connector.GetModes()) {
    /* Find group for the new mode or create new group */
    uint32_t group_found = 0;
    for (auto &hwc_config : hwc_configs) {
      if (mode.GetRawMode().hdisplay ==
              hwc_config.second.mode.GetRawMode().hdisplay &&
          mode.GetRawMode().vdisplay ==
              hwc_config.second.mode.GetRawMode().vdisplay) {
        group_found = hwc_config.second.group_id;
      }
    }
    if (group_found == 0) {
      group_found = last_group_id++;
    }

    bool disabled = false;
    if ((mode.GetRawMode().flags & DRM_MODE_FLAG_3D_MASK) != 0) {
      ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
            mode.GetName().c_str());
      disabled = true;
    }

    /* Add config */
    hwc_configs[last_config_id] = {
        .id = last_config_id,
        .group_id = group_found,
        .mode = mode,
        .disabled = disabled,
    };

    /* Chwck if the mode is preferred */
    if ((mode.GetRawMode().type & DRM_MODE_TYPE_PREFERRED) != 0 &&
        preferred_config_id == 0) {
      preferred_config_id = last_config_id;
      preferred_config_group_id = group_found;
    }

    last_config_id++;
  }

  /* We must have preferred mode. Set first mode as preferred
   * in case KMS haven't reported anything. */
  if (preferred_config_id == 0) {
    preferred_config_id = first_config_id;
    preferred_config_group_id = 1;
  }

  for (uint32_t group = 1; group < last_group_id; group++) {
    bool has_interlaced = false;
    bool has_progressive = false;
    for (auto &hwc_config : hwc_configs) {
      if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
        continue;
      }

      if (hwc_config.second.IsInterlaced()) {
        has_interlaced = true;
      } else {
        has_progressive = true;
      }
    }

    auto has_both = has_interlaced && has_progressive;
    if (!has_both) {
      continue;
    }

    bool group_contains_preferred_interlaced = false;
    if (group == preferred_config_group_id &&
        hwc_configs[preferred_config_id].IsInterlaced()) {
      group_contains_preferred_interlaced = true;
    }

    for (auto &hwc_config : hwc_configs) {
      if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
        continue;
      }

      auto disable = group_contains_preferred_interlaced
                         ? !hwc_config.second.IsInterlaced()
                         : hwc_config.second.IsInterlaced();

      if (disable) {
        ALOGI(
            "Group %i: Disabling display mode %s (This group should consist "
            "of %s modes)",
            group, hwc_config.second.mode.GetName().c_str(),
            group_contains_preferred_interlaced ? "interlaced" : "progressive");

        hwc_config.second.disabled = true;
      }
    }
  }

  /* Group should not contain 2 modes with FPS delta less than ~1HZ
   * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
   */
  constexpr float kMinFpsDelta = 1.0;  // FPS
  for (uint32_t m1 = first_config_id; m1 < last_config_id; m1++) {
    for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) {
      if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
          !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
          fabsf(hwc_configs[m1].mode.GetVRefresh() -
                hwc_configs[m2].mode.GetVRefresh()) < kMinFpsDelta) {
        ALOGI(
            "Group %i: Disabling display mode %s (Refresh rate value is "
            "too close to existing mode %s)",
            hwc_configs[m2].group_id, hwc_configs[m2].mode.GetName().c_str(),
            hwc_configs[m1].mode.GetName().c_str());

        hwc_configs[m2].disabled = true;
      }
    }
  }

  return HWC2::Error::None;
}

}  // namespace android
