/*
 * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.
    * Neither the name of The Linux Foundation nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <vector>
#include <string>

#include "gl_common.h"

#define __CLASS__ "GLCommon"

namespace sdm {

GLuint GLCommon::LoadProgram(int vertex_entries, const char **vertex, int fragment_entries,
                           const char **fragment) {
  GLuint prog_id = glCreateProgram();

  int vert_id = glCreateShader(GL_VERTEX_SHADER);
  int frag_id = glCreateShader(GL_FRAGMENT_SHADER);

  GL(glShaderSource(vert_id, vertex_entries, vertex, 0));
  GL(glCompileShader(vert_id));
  DumpShaderLog(vert_id);

  GL(glShaderSource(frag_id, fragment_entries, fragment, 0));
  GL(glCompileShader(frag_id));
  DumpShaderLog(frag_id);

  GL(glAttachShader(prog_id, vert_id));
  GL(glAttachShader(prog_id, frag_id));

  GL(glLinkProgram(prog_id));

  GL(glDetachShader(prog_id, vert_id));
  GL(glDetachShader(prog_id, frag_id));

  GL(glDeleteShader(vert_id));
  GL(glDeleteShader(frag_id));

  return prog_id;
}

void GLCommon::DumpShaderLog(int shader) {
  int success = 0;
  GLchar infoLog[512];
  GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success));
  if (!success) {
    glGetShaderInfoLog(shader, 512, NULL, infoLog);
    DLOGI("Shader Failed to compile: %s\n", infoLog);
  }
}

void GLCommon::MakeCurrent(const GLContext* ctx) {
  DTRACE_SCOPED();
  EGL(eglMakeCurrent(ctx->egl_display, ctx->egl_surface, ctx->egl_surface, ctx->egl_context));
}

void GLCommon::SetProgram(uint32_t id) {
  DTRACE_SCOPED();
  GL(glUseProgram(id));
}

void GLCommon::DeleteProgram(uint32_t id) {
  DTRACE_SCOPED();
  GL(glDeleteProgram(id));
}

void GLCommon::SetSourceBuffer(const native_handle_t *src_hnd) {
  DTRACE_SCOPED();
  EGLImageBuffer *src_buffer = image_wrapper_.wrap(reinterpret_cast<const void *>(src_hnd));

  GL(glActiveTexture(GL_TEXTURE0));
  if (src_buffer) {
    GL(glBindTexture(GL_TEXTURE_2D, src_buffer->getTexture(GL_TEXTURE_2D)));
  }
}

void GLCommon::SetDestinationBuffer(const native_handle_t *dst_hnd) {
  DTRACE_SCOPED();
  EGLImageBuffer *dst_buffer = image_wrapper_.wrap(reinterpret_cast<const void *>(dst_hnd));

  if (dst_buffer) {
    GL(glBindFramebuffer(GL_FRAMEBUFFER, dst_buffer->getFramebuffer()));
  }
}

int GLCommon::WaitOnInputFence(const std::vector<shared_ptr<Fence>> &in_fences) {
  DTRACE_SCOPED();

  shared_ptr<Fence> in_fence = Fence::Merge(in_fences, true /* ignore signaled*/);
  if (in_fence == nullptr) {
   return 0;
  }

  int fd = Fence::Dup(in_fence);
  EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd, EGL_NONE};
  EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID,
                                     attribs);

  if (sync == EGL_NO_SYNC_KHR) {
    DLOGE("Failed to create sync from source fd: %s", Fence::GetStr(in_fence).c_str());
    close(fd);
    return -1;
  }

  EGL(eglWaitSyncKHR(eglGetCurrentDisplay(), sync, 0));
  EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));

  return 0;
}

int GLCommon::CreateOutputFence(shared_ptr<Fence> *out_fence) {
  DTRACE_SCOPED();
  EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);

  // Swap buffer.
  GL(glFlush());

  if (sync == EGL_NO_SYNC_KHR) {
    DLOGE("Failed to create egl sync fence");
    return -1;
  }

  int status = 0;
  int fd = eglDupNativeFenceFDANDROID(eglGetCurrentDisplay(), sync);
  if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
    status = -1;
    DLOGE("Failed to dup sync");
  } else {
    *out_fence = Fence::Create(fd, "gl_out_fence");
  }
  EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));

  return status;
}

void GLCommon::DestroyContext(GLContext* ctx) {
  DTRACE_SCOPED();

  // Clear egl image buffers.
  image_wrapper_.Deinit();

  EGL(DeleteProgram(ctx->program_id));
  EGL(eglMakeCurrent(ctx->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
  EGL(eglDestroySurface(ctx->egl_display, ctx->egl_surface));
  EGL(eglDestroyContext(ctx->egl_display, ctx->egl_context));
  EGL(eglTerminate(ctx->egl_display));
}

void GLCommon::ClearCache() {
  // Clear cached handles.
  image_wrapper_.Deinit();
  image_wrapper_.Init();
}

void GLCommon::SetRealTimePriority() {
  // same as composer thread
  struct sched_param param = {0};
  param.sched_priority = 2;
  if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
    DLOGE("Couldn't set SCHED_FIFO: %d", errno);
  }
}

void GLCommon::SetViewport(const GLRect &dst_rect) {
  DTRACE_SCOPED();
  float width = dst_rect.right - dst_rect.left;
  float height = dst_rect.bottom - dst_rect.top;
  GL(glViewport(dst_rect.left, dst_rect.top, width, height));
}

}  // namespace sdm

