
#include "hifb.hpp"

HI_S32 g_hFrameBuffer;
HIFB_BUFFER_S g_stCanvasBuf;
void* g_BackBuffer;

static struct fb_bitfield s_r16 = {10, 5, 0};
static struct fb_bitfield s_g16 = {5, 5, 0};
static struct fb_bitfield s_b16 = {0, 5, 0};
static struct fb_bitfield s_a16 = {15, 1, 0};

HI_BOOL HiInitDisplay() {
  HI_S32 s32Ret = HI_SUCCESS;
  HI_U32 u32PicWidth = SCREEN_WIDTH;
  HI_U32 u32PicHeight = SCREEN_HEIGHT;
  SIZE_S stSize;

  VO_LAYER VoLayer = 0;
  VO_PUB_ATTR_S stPubAttr;
  VO_VIDEO_LAYER_ATTR_S stLayerAttr;
  HI_U32 u32VoFrmRate;

  HI_BOOL bShow = HI_TRUE;
  HIFB_LAYER_INFO_S stLayerInfo = {};
  HIFB_POINT_S stPoint = {};
  struct fb_var_screeninfo stVarInfo;
  HIFB_COLORKEY_S stColorKey;
  VB_CONF_S stVbConf;
  HI_U32 u32BlkSize;

  /******************************************
   step  1: init variable
  ******************************************/
  memset(&stVbConf, 0, sizeof(VB_CONF_S));

  u32BlkSize = CEILING_2_POWER(u32PicWidth, SAMPLE_SYS_ALIGN_WIDTH) *
               CEILING_2_POWER(u32PicHeight, SAMPLE_SYS_ALIGN_WIDTH) * 2;

  stVbConf.u32MaxPoolCnt = 128;
  stVbConf.astCommPool[0].u32BlkSize = u32BlkSize;
  stVbConf.astCommPool[0].u32BlkCnt = 6;

  /******************************************
   step 2: mpp system init.
  ******************************************/
  s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
  if (HI_SUCCESS != s32Ret) {
    SAMPLE_PRT("system init failed with %d!\n", s32Ret);
    return HI_FALSE;
  }

  /******************************************
   step 3:  start vo hd0.
  *****************************************/
  s32Ret = HI_MPI_VO_UnBindGraphicLayer(GRAPHICS_LAYER_HC0, SAMPLE_VO_DEV_DHD0);
  if (HI_SUCCESS != s32Ret) {
    SAMPLE_PRT("UnBindGraphicLayer failed with %d!\n", s32Ret);
    return HI_FALSE;
  }

  s32Ret = HI_MPI_VO_BindGraphicLayer(GRAPHICS_LAYER_HC0, SAMPLE_VO_DEV_DHD0);
  if (HI_SUCCESS != s32Ret) {
    SAMPLE_PRT("BindGraphicLayer failed with %d!\n", s32Ret);
    return HI_FALSE;
  }

  stPubAttr.enIntfSync = VO_OUTPUT_640x480_60;
  stPubAttr.enIntfType = VO_INTF_HDMI;
  stPubAttr.u32BgColor = 0x000000;

  stLayerAttr.bClusterMode = HI_FALSE;
  stLayerAttr.bDoubleFrame = HI_FALSE;
  stLayerAttr.enPixFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;

  u32VoFrmRate = 60;
  stSize.u32Width = SCREEN_WIDTH;
  stSize.u32Height = SCREEN_HEIGHT;

  memcpy(&stLayerAttr.stImageSize, &stSize, sizeof(stSize));

  stLayerAttr.u32DispFrmRt = 60;
  stLayerAttr.stDispRect.s32X = 0;
  stLayerAttr.stDispRect.s32Y = 0;
  stLayerAttr.stDispRect.u32Width = stSize.u32Width;
  stLayerAttr.stDispRect.u32Height = stSize.u32Height;

  s32Ret = SAMPLE_COMM_VO_StartDev(SAMPLE_VO_DEV_DHD0, &stPubAttr);
  if (HI_SUCCESS != s32Ret) {
    SAMPLE_PRT("start vo dev failed with %d!\n", s32Ret);
    return HI_FALSE;
  }

  s32Ret = SAMPLE_COMM_VO_StartLayer(VoLayer, &stLayerAttr);
  if (HI_SUCCESS != s32Ret) {
    SAMPLE_PRT("start vo layer failed with %d!\n", s32Ret);
    return HI_FALSE;
  }

  if (stPubAttr.enIntfType & VO_INTF_HDMI) {
    s32Ret = SAMPLE_COMM_VO_HdmiStart(stPubAttr.enIntfSync);
    if (HI_SUCCESS != s32Ret) {
      SAMPLE_PRT("start HDMI failed with %d!\n", s32Ret);
      return HI_FALSE;
    }
  }

  if ((g_hFrameBuffer = open("/dev/fb0", O_RDWR, NULL)) < 0) {
    SAMPLE_PRT("failed to open /dev/fb0...\n");
    return HI_FALSE;
  }

  /*all layer surport colorkey*/
  stColorKey.bKeyEnable = HI_TRUE;
  stColorKey.u32Key = 0x0;
  if (ioctl(g_hFrameBuffer, FBIOPUT_COLORKEY_HIFB, &stColorKey) < 0) {
    SAMPLE_PRT("FBIOPUT_COLORKEY_HIFB!\n");
    return HI_FALSE;
  }

  s32Ret = ioctl(g_hFrameBuffer, FBIOGET_VSCREENINFO, &stVarInfo);
  if (s32Ret < 0) {
    SAMPLE_PRT("GET_VSCREENINFO failed!\n");
    return HI_FALSE;
  }

  if (ioctl(g_hFrameBuffer, FBIOPUT_SCREEN_ORIGIN_HIFB, &stPoint) < 0) {
    SAMPLE_PRT("set screen original show position failed!\n");
    return HI_FALSE;
  }

  stVarInfo.transp = s_a16;
  stVarInfo.red = s_r16;
  stVarInfo.green = s_g16;
  stVarInfo.blue = s_b16;
  stVarInfo.bits_per_pixel = 16;
  stVarInfo.activate = FB_ACTIVATE_NOW;
  stVarInfo.xres = stVarInfo.xres_virtual = SCREEN_WIDTH;
  stVarInfo.yres = stVarInfo.yres_virtual = SCREEN_HEIGHT;

  if (ioctl(g_hFrameBuffer, FBIOPUT_VSCREENINFO, &stVarInfo) < 0) {
    SAMPLE_PRT("PUT_VSCREENINFO failed!\n");
    return HI_FALSE;
  }

  stLayerInfo.BufMode = HIFB_LAYER_BUF_ONE;
  stLayerInfo.u32Mask = HIFB_LAYERMASK_BUFMODE;

  if (ioctl(g_hFrameBuffer, FBIOPUT_LAYER_INFO, &stLayerInfo) < 0) {
    SAMPLE_PRT("PUT_LAYER_INFO failed!\n");
    return HI_FALSE;
  }

  if (ioctl(g_hFrameBuffer, FBIOPUT_SHOW_HIFB, &bShow) < 0) {
    SAMPLE_PRT("FBIOPUT_SHOW_HIFB failed!\n");
    return HI_FALSE;
  }

  /* allocate mmz memory for back buffer... */
  if (HI_FAILURE == HI_MPI_SYS_MmzAlloc(&g_stCanvasBuf.stCanvas.u32PhyAddr,
                                        &g_BackBuffer, NULL, NULL,
                                        SCREEN_WIDTH * SCREEN_HEIGHT * 2)) {
    SAMPLE_PRT("allocate memory (640*480*2 bytes) failed\n");
    return HI_FALSE;
  }

  /* when we call RefreshScreen we will re-draw the entire screen... */
  g_stCanvasBuf.UpdateRect.x = 0;
  g_stCanvasBuf.UpdateRect.y = 0;
  g_stCanvasBuf.UpdateRect.w = SCREEN_WIDTH;
  g_stCanvasBuf.UpdateRect.h = SCREEN_HEIGHT;

  /* meta data about the back buffer... */
  g_stCanvasBuf.stCanvas.u32Height = SCREEN_HEIGHT;
  g_stCanvasBuf.stCanvas.u32Width = SCREEN_WIDTH;
  g_stCanvasBuf.stCanvas.u32Pitch = SCREEN_WIDTH * 2;
  g_stCanvasBuf.stCanvas.enFmt = HIFB_FMT_ARGB1555;

  memset(g_BackBuffer, 0x00,
         g_stCanvasBuf.stCanvas.u32Pitch * g_stCanvasBuf.stCanvas.u32Height);

  /* finally open TDE so we can do hardware accelerated color conversions... */
  s32Ret = HI_TDE2_Open();
  if (s32Ret < 0) {
    SAMPLE_PRT("HI_TDE2_Open failed :%d!\n", s32Ret);
    return HI_FALSE;
  }

  return HI_TRUE;
}

void RefreshScreen() {
  ioctl(g_hFrameBuffer, FBIO_REFRESH, &g_stCanvasBuf);
}