/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Not a Contribution.
 *
 * Copyright 2015 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.
 */

#include "EGLImageBuffer.h"
#include <cutils/native_handle.h>
#include <gralloc_priv.h>
#include <ui/GraphicBuffer.h>
#include <map>
#include "EGLImageWrapper.h"
#include "glengine.h"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0

//-----------------------------------------------------------------------------
EGLImageKHR create_eglImage(android::sp<android::GraphicBuffer> graphicBuffer)
//-----------------------------------------------------------------------------
{
  bool isProtected = (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
  EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
                    isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
                    isProtected ? EGL_TRUE : EGL_NONE, EGL_NONE};

  EGLImageKHR eglImage = eglCreateImageKHR(
      eglGetCurrentDisplay(), (EGLContext)EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
      (EGLClientBuffer)(graphicBuffer->getNativeBuffer()), attrs);

  return eglImage;
}

//-----------------------------------------------------------------------------
EGLImageBuffer::EGLImageBuffer(android::sp<android::GraphicBuffer> graphicBuffer)
//-----------------------------------------------------------------------------
{
  // this->graphicBuffer = graphicBuffer;
  this->eglImageID = create_eglImage(graphicBuffer);
  this->width = graphicBuffer->getWidth();
  this->height = graphicBuffer->getHeight();

  textureID = 0;
  renderbufferID = 0;
  framebufferID = 0;
}

//-----------------------------------------------------------------------------
EGLImageBuffer::~EGLImageBuffer()
//-----------------------------------------------------------------------------
{
  if (textureID != 0) {
    GL(glDeleteTextures(1, &textureID));
    textureID = 0;
  }

  if (renderbufferID != 0) {
    GL(glDeleteRenderbuffers(1, &renderbufferID));
    renderbufferID = 0;
  }

  if (framebufferID != 0) {
    GL(glDeleteFramebuffers(1, &framebufferID));
    framebufferID = 0;
  }

  // Delete the eglImage
  if (eglImageID != 0)
  {
      eglDestroyImageKHR(eglGetCurrentDisplay(), eglImageID);
      eglImageID = 0;
  }
}

//-----------------------------------------------------------------------------
int EGLImageBuffer::getWidth()
//-----------------------------------------------------------------------------
{
  return width;
}

//-----------------------------------------------------------------------------
int EGLImageBuffer::getHeight()
//-----------------------------------------------------------------------------
{
  return height;
}

//-----------------------------------------------------------------------------
unsigned int EGLImageBuffer::getTexture()
//-----------------------------------------------------------------------------
{
  if (textureID == 0) {
    bindAsTexture();
  }

  return textureID;
}

//-----------------------------------------------------------------------------
unsigned int EGLImageBuffer::getFramebuffer()
//-----------------------------------------------------------------------------
{
  if (framebufferID == 0) {
    bindAsFramebuffer();
  }

  return framebufferID;
}

//-----------------------------------------------------------------------------
void EGLImageBuffer::bindAsTexture()
//-----------------------------------------------------------------------------
{
  if (textureID == 0) {
    GL(glGenTextures(1, &textureID));
    int target = 0x8D65;
    GL(glBindTexture(target, textureID));
    GL(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
    GL(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
    GL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
    GL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));

    GL(glEGLImageTargetTexture2DOES(0x8D65, eglImageID));
  }

  GL(glBindTexture(0x8D65, textureID));
}

//-----------------------------------------------------------------------------
void EGLImageBuffer::bindAsFramebuffer()
//-----------------------------------------------------------------------------
{
  if (renderbufferID == 0) {
    GL(glGenFramebuffers(1, &framebufferID));
    GL(glGenRenderbuffers(1, &renderbufferID));

    GL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID));
    GL(glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, eglImageID));

    GL(glBindFramebuffer(GL_FRAMEBUFFER, framebufferID));
    GL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
                                 renderbufferID));
    GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (result != GL_FRAMEBUFFER_COMPLETE) {
      ALOGI("%s Framebuffer Invalid***************", __FUNCTION__);
    }
  }

  GL(glBindFramebuffer(GL_FRAMEBUFFER, framebufferID));
}