/*
 * Copyright (C) 2020 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.
 */

#if PLATFORM_SDK_VERSION >= 30

#define LOG_TAG "hwc-bufferinfo-mappermetadata"

#include "BufferInfoMapperMetadata.h"

#include <drm/drm_fourcc.h>
#include <ui/GraphicBufferMapper.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

#include <cinttypes>

#include "utils/log.h"

namespace android {

BufferInfoGetter *BufferInfoMapperMetadata::CreateInstance() {
  if (GraphicBufferMapper::getInstance().getMapperVersion() <
      GraphicBufferMapper::GRALLOC_4)
    return nullptr;

  return new BufferInfoMapperMetadata();
}

/* The implementation below makes assumptions on the order and number of file
 * descriptors that Gralloc places in the native_handle_t and as such it very
 * likely needs to be adapted to match the particular Gralloc implementation
 * used in the system. For this reason it is been declared as a weak symbol,
 * so that it can be overridden.
 */
int __attribute__((weak))
BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) {
  int num_fds = handle->numFds;

  if (num_fds >= 1 && num_fds <= 2) {
    if (IsDrmFormatRgb(bo->format)) {
      bo->prime_fds[0] = handle->data[0];
    } else {
      bo->prime_fds[0] = bo->prime_fds[1] = bo->prime_fds[2] = handle->data[0];
    }
    if (bo->prime_fds[0] <= 0) {
      ALOGE("Encountered invalid fd %d", bo->prime_fds[0]);
      return android::BAD_VALUE;
    }

  } else if (num_fds >= 3) {
    bo->prime_fds[0] = handle->data[0];
    bo->prime_fds[1] = handle->data[1];
    bo->prime_fds[2] = handle->data[2];
    for (int i = 0; i < 3; i++) {
      if (bo->prime_fds[i] <= 0) {
        ALOGE("Encountered invalid fd %d", bo->prime_fds[i]);
        return android::BAD_VALUE;
      }
    }
  }
  return 0;
}

int BufferInfoMapperMetadata::ConvertBoInfo(buffer_handle_t handle,
                                            hwc_drm_bo_t *bo) {
  GraphicBufferMapper &mapper = GraphicBufferMapper::getInstance();
  if (!handle)
    return -EINVAL;

  uint64_t usage = 0;
  int err = mapper.getUsage(handle, &usage);
  if (err) {
    ALOGE("Failed to get usage err=%d", err);
    return err;
  }
  bo->usage = static_cast<uint32_t>(usage);

  ui::PixelFormat hal_format;
  err = mapper.getPixelFormatRequested(handle, &hal_format);
  if (err) {
    ALOGE("Failed to get HAL Pixel Format err=%d", err);
    return err;
  }
  bo->hal_format = static_cast<uint32_t>(hal_format);

  err = mapper.getPixelFormatFourCC(handle, &bo->format);
  if (err) {
    ALOGE("Failed to get FourCC format err=%d", err);
    return err;
  }

  err = mapper.getPixelFormatModifier(handle, &bo->modifiers[0]);
  if (err) {
    ALOGE("Failed to get DRM Modifier err=%d", err);
    return err;
  }

  uint64_t width = 0;
  err = mapper.getWidth(handle, &width);
  if (err) {
    ALOGE("Failed to get Width err=%d", err);
    return err;
  }
  bo->width = static_cast<uint32_t>(width);

  uint64_t height = 0;
  err = mapper.getHeight(handle, &height);
  if (err) {
    ALOGE("Failed to get Height err=%d", err);
    return err;
  }
  bo->height = static_cast<uint32_t>(height);

  std::vector<ui::PlaneLayout> layouts;
  err = mapper.getPlaneLayouts(handle, &layouts);
  if (err) {
    ALOGE("Failed to get Plane Layouts err=%d", err);
    return err;
  }

  for (uint32_t i = 0; i < layouts.size(); i++) {
    bo->modifiers[i] = bo->modifiers[0];
    bo->pitches[i] = layouts[i].strideInBytes;
    bo->offsets[i] = layouts[i].offsetInBytes;
  }

  return GetFds(handle, bo);
}

}  // namespace android

#endif