// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "screen-capture-utils/crtc.h"

#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include <vector>

#include <base/check.h>
#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/logging.h>
#include <base/notreached.h>
#include <base/stl_util.h>

namespace screenshot {

namespace {

constexpr const char kDrmDeviceDir[] = "/dev/dri";
constexpr const char kDrmDeviceGlob[] = "card?";

float FixedPoint1616ToFloat(uint32_t n) {
  float result = (n & 0xFFFF0000) >> 16;
  result += (n & 0xFFFF) / 65536.0f;
  return result;
}

bool PopulatePlaneConfiguration(int fd,
                                uint32_t plane_id,
                                PlaneConfiguration* conf) {
  // TODO(andrescj): Handle rotation.
  std::map<std::string, uint64_t> interesting_props{
      {"CRTC_X", 0}, {"CRTC_Y", 0}, {"CRTC_W", 0}, {"CRTC_H", 0},
      {"SRC_X", 0},  {"SRC_Y", 0},  {"SRC_W", 0},  {"SRC_H", 0}};

  ScopedDrmObjectPropertiesPtr props(
      drmModeObjectGetProperties(fd, plane_id, DRM_MODE_OBJECT_PLANE));
  if (!props) {
    return false;
  }

  int found = 0;
  for (int i = 0; i < props->count_props; i++) {
    ScopedDrmPropertyPtr prop(drmModeGetProperty(fd, props->props[i]));
    if (!prop) {
      continue;
    }

    if (interesting_props.find(prop->name) != interesting_props.end()) {
      interesting_props[prop->name] = props->prop_values[i];
      found++;
    }
  }

  if (found != interesting_props.size()) {
    return false;
  }

  conf->x = static_cast<int32_t>(interesting_props["CRTC_X"]);
  conf->y = static_cast<int32_t>(interesting_props["CRTC_Y"]);
  conf->w = static_cast<uint32_t>(interesting_props["CRTC_W"]);
  conf->h = static_cast<uint32_t>(interesting_props["CRTC_H"]);
  conf->crop_x = FixedPoint1616ToFloat(interesting_props["SRC_X"]);
  conf->crop_y = FixedPoint1616ToFloat(interesting_props["SRC_Y"]);
  conf->crop_w = FixedPoint1616ToFloat(interesting_props["SRC_W"]);
  conf->crop_h = FixedPoint1616ToFloat(interesting_props["SRC_H"]);
  return true;
}

std::vector<std::unique_ptr<Crtc>> GetConnectedCrtcs() {
  std::vector<std::unique_ptr<Crtc>> crtcs;

  std::vector<base::FilePath> paths;
  {
    base::FileEnumerator lister(base::FilePath(kDrmDeviceDir), false,
                                base::FileEnumerator::FILES, kDrmDeviceGlob);
    for (base::FilePath name = lister.Next(); !name.empty();
         name = lister.Next()) {
      paths.emplace_back(name);
    }
  }
  std::sort(paths.begin(), paths.end());

  for (base::FilePath path : paths) {
    base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ |
                              base::File::FLAG_WRITE);
    if (!file.IsValid())
      continue;

    // Set CAP_ATOMIC so we can query all planes and plane properties.
    // TODO(b/290543296): Revisit if we still need this check after Hana EOL.
    bool atomic_modeset =
        drmSetClientCap(file.GetPlatformFile(), DRM_CLIENT_CAP_ATOMIC, 1) == 0;

    ScopedDrmModeResPtr resources(drmModeGetResources(file.GetPlatformFile()));
    if (!resources)
      continue;

    for (int index_connector = 0; index_connector < resources->count_connectors;
         ++index_connector) {
      ScopedDrmModeConnectorPtr connector(drmModeGetConnector(
          file.GetPlatformFile(), resources->connectors[index_connector]));
      if (!connector || connector->encoder_id == 0)
        continue;

      ScopedDrmModeEncoderPtr encoder(
          drmModeGetEncoder(file.GetPlatformFile(), connector->encoder_id));
      if (!encoder || encoder->crtc_id == 0)
        continue;

      ScopedDrmModeCrtcPtr crtc(
          drmModeGetCrtc(file.GetPlatformFile(), encoder->crtc_id));
      if (!crtc || !crtc->mode_valid || crtc->buffer_id == 0)
        continue;

      ScopedDrmModeFB2Ptr fb2(
          drmModeGetFB2(file.GetPlatformFile(), crtc->buffer_id),
          file.GetPlatformFile());

      if (!fb2) {
        LOG(ERROR) << "getfb2 failed";
        continue;
      }

      std::unique_ptr<Crtc> res_crtc;

      // Keep around a file for next display if needed.
      base::File file_dup = file.Duplicate();
      if (!file_dup.IsValid())
        continue;

      // Multiplane is only supported when atomic_modeset is available. Obtain
      // the |plane_res_| for later use.
      if (atomic_modeset) {
        ScopedDrmPlaneResPtr plane_res(
            drmModeGetPlaneResources(file.GetPlatformFile()));
        CHECK(plane_res) << " Failed to get plane resources";
        res_crtc = std::make_unique<Crtc>(std::move(file), std::move(connector),
                                          std::move(encoder), std::move(crtc),
                                          std::move(fb2), std::move(plane_res));
      } else {
        res_crtc = std::make_unique<Crtc>(std::move(file), std::move(connector),
                                          std::move(encoder), std::move(crtc),
                                          std::move(fb2), nullptr);
      }

      file = std::move(file_dup);
      crtcs.emplace_back(std::move(res_crtc));
    }
  }

  return crtcs;
}

}  // namespace

Crtc::Crtc(base::File file,
           ScopedDrmModeConnectorPtr connector,
           ScopedDrmModeEncoderPtr encoder,
           ScopedDrmModeCrtcPtr crtc,
           ScopedDrmModeFB2Ptr fb2,
           ScopedDrmPlaneResPtr plane_res)
    : file_(std::move(file)),
      connector_(std::move(connector)),
      encoder_(std::move(encoder)),
      crtc_(std::move(crtc)),
      fb2_(std::move(fb2)),
      plane_res_(std::move(plane_res)) {}

bool Crtc::IsInternalDisplay() const {
  switch (connector_->connector_type) {
    case DRM_MODE_CONNECTOR_eDP:
    case DRM_MODE_CONNECTOR_LVDS:
    case DRM_MODE_CONNECTOR_DSI:
    case DRM_MODE_CONNECTOR_VIRTUAL:
      return true;
    default:
      return false;
  }
}

std::unique_ptr<Crtc> CrtcFinder::Find() const {
  auto crtcs = GetConnectedCrtcs();
  for (auto& crtc : crtcs) {
    if (MatchesSpec(crtc.get()))
      return std::move(crtc);
  }
  return nullptr;
}

bool CrtcFinder::MatchesSpec(const Crtc* crtc) const {
  switch (spec_) {
    case Spec::kAnyDisplay:
      return true;
    case Spec::kInternalDisplay:
      return crtc->IsInternalDisplay();
    case Spec::kExternalDisplay:
      return !crtc->IsInternalDisplay();
    case Spec::kById:
      return crtc->crtc()->crtc_id == crtc_id_;
  }
  NOTREACHED() << "Invalid spec";
  return false;
}

std::vector<Crtc::PlaneInfo> Crtc::GetConnectedPlanes() const {
  CHECK(fb2())
      << "This code path is supported only if drmModeGetFB2() succeeded "
         "for the CRTC.";
  std::vector<Crtc::PlaneInfo> planes;
  if (!plane_res_.get()) {
    // Return the empty list if we decided not to query the plane resources or
    // if doing so failed.
    return planes;
  }
  for (uint32_t i = 0; i < plane_res_->count_planes; i++) {
    ScopedDrmPlanePtr plane(
        drmModeGetPlane(file_.GetPlatformFile(), plane_res_->planes[i]));
    if (plane->crtc_id != crtc_->crtc_id) {
      continue;
    }

    PlaneConfiguration conf{};
    bool res = PopulatePlaneConfiguration(file_.GetPlatformFile(),
                                          plane->plane_id, &conf);
    if (!res) {
      LOG(WARNING) << "Failed to query plane position, skipping.\n";
      continue;
    }
    ScopedDrmModeFB2Ptr fb_info(
        drmModeGetFB2(file_.GetPlatformFile(), plane->fb_id),
        file_.GetPlatformFile());
    if (!fb_info) {
      LOG(WARNING) << "Failed to query plane fb info, skipping.\n";
      continue;
    }
    planes.emplace_back(std::make_pair(std::move(fb_info), conf));
  }
  return planes;
}

}  // namespace screenshot
