gpu_tonemapper: Include gpu tonemapper

GPU tonemapper library which is used by HWC to tone
map the layers from one Gamut to another based on the
3D LUT.

Change-Id: Iccaa38e40989e832fd3891a24eca494aba696d9a
Crs-fixed: 1094964
diff --git a/Android.mk b/Android.mk
index 60a48f5..6eef2fc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,7 +3,7 @@
 
 ifneq ($(TARGET_IS_HEADLESS), true)
     display-hals += libcopybit liblight libmemtrack hdmi_cec \
-                    $(sdm-libs)/hwc $(sdm-libs)/hwc2
+                    $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper
 endif
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
diff --git a/common.mk b/common.mk
index d44a664..6476dfd 100644
--- a/common.mk
+++ b/common.mk
@@ -17,6 +17,7 @@
 
 common_includes := $(display_top)/libqdutils
 common_includes += $(display_top)/libqservice
+common_includes += $(display_top)/gpu_tonemapper
 ifneq ($(TARGET_IS_HEADLESS), true)
     common_includes += $(display_top)/libcopybit
 endif
diff --git a/gpu_tonemapper/Android.mk b/gpu_tonemapper/Android.mk
new file mode 100644
index 0000000..9ae3840
--- /dev/null
+++ b/gpu_tonemapper/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_COPY_HEADERS_TO     := $(common_header_export_path)
+LOCAL_COPY_HEADERS        := TonemapFactory.h Tonemapper.h
+LOCAL_SHARED_LIBRARIES    := libEGL libGLESv2 libui libutils liblog
+include $(BUILD_COPY_HEADERS)
+
+LOCAL_MODULE              := libgpu_tonemapper
+LOCAL_MODULE_TAGS         := optional
+LOCAL_C_INCLUDES          := $(TARGET_OUT_HEADERS)/qcom/display/
+
+LOCAL_CFLAGS              := -Wno-missing-field-initializers -Wall \
+                             -Wno-unused-parameter -std=c++11 -DLOG_TAG=\"GPU_TONEMAPPER\"
+
+LOCAL_SRC_FILES           := TonemapFactory.cpp \
+                             glengine.cpp \
+                             EGLImageBuffer.cpp \
+                             EGLImageWrapper.cpp \
+                             Tonemapper.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/gpu_tonemapper/EGLImageBuffer.cpp b/gpu_tonemapper/EGLImageBuffer.cpp
new file mode 100644
index 0000000..e64e16f
--- /dev/null
+++ b/gpu_tonemapper/EGLImageBuffer.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, 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;
+  }
+}
+
+//-----------------------------------------------------------------------------
+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));
+}
diff --git a/gpu_tonemapper/EGLImageBuffer.h b/gpu_tonemapper/EGLImageBuffer.h
new file mode 100644
index 0000000..23af573
--- /dev/null
+++ b/gpu_tonemapper/EGLImageBuffer.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __EGLIMAGE_BUFFER_H__
+#define __EGLIMAGE_BUFFER_H__
+
+#include <cutils/native_handle.h>
+#include <gralloc_priv.h>
+#include <ui/GraphicBuffer.h>
+#include "engine.h"
+
+class EGLImageBuffer {
+  // android::sp<android::GraphicBuffer> graphicBuffer;
+  void *eglImageID;
+  int width;
+  int height;
+  uint textureID;
+  uint renderbufferID;
+  uint framebufferID;
+
+ public:
+  int getWidth();
+  int getHeight();
+  EGLImageBuffer(android::sp<android::GraphicBuffer>);
+  unsigned int getTexture();
+  unsigned int getFramebuffer();
+  void bindAsTexture();
+  void bindAsFramebuffer();
+  ~EGLImageBuffer();
+  static EGLImageBuffer *from(const private_handle_t *src);
+  static void clear();
+};
+
+#endif  //__EGLIMAGE_BUFFER_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/EGLImageWrapper.cpp b/gpu_tonemapper/EGLImageWrapper.cpp
new file mode 100644
index 0000000..eb0a2ca
--- /dev/null
+++ b/gpu_tonemapper/EGLImageWrapper.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, 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 "EGLImageWrapper.h"
+#include <cutils/native_handle.h>
+#include <gralloc_priv.h>
+#include <ui/GraphicBuffer.h>
+
+std::map<int, EGLImageBuffer *> EGLImageWrapper::eglImageBufferMap;
+
+//-----------------------------------------------------------------------------
+EGLImageBuffer *EGLImageWrapper::wrap(const void *pvt_handle)
+//-----------------------------------------------------------------------------
+{
+  const private_handle_t *src = static_cast<const private_handle_t *>(pvt_handle);
+
+  EGLImageBuffer *result = 0;
+  std::map<int, EGLImageBuffer *>::iterator it = eglImageBufferMap.find(src->fd);
+  if (it == eglImageBufferMap.end()) {
+    native_handle_t *native_handle = const_cast<private_handle_t *>(src);
+
+    int flags = android::GraphicBuffer::USAGE_HW_TEXTURE |
+                android::GraphicBuffer::USAGE_SW_READ_NEVER |
+                android::GraphicBuffer::USAGE_SW_WRITE_NEVER;
+    if (src->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
+      flags |= android::GraphicBuffer::USAGE_PROTECTED;
+    }
+
+    android::sp<android::GraphicBuffer> graphicBuffer =
+        new android::GraphicBuffer(src->width, src->height, src->format, flags,
+                                   src->width /*src->stride*/, native_handle, false);
+
+    result = new EGLImageBuffer(graphicBuffer);
+
+    eglImageBufferMap[src->fd] = result;
+  } else {
+    result = it->second;
+  }
+
+  return result;
+}
+
+//-----------------------------------------------------------------------------
+void EGLImageWrapper::destroy()
+//-----------------------------------------------------------------------------
+{
+  std::map<int, EGLImageBuffer *>::iterator it = eglImageBufferMap.begin();
+  for (; it != eglImageBufferMap.end(); it++) {
+    delete it->second;
+  }
+  eglImageBufferMap.clear();
+}
\ No newline at end of file
diff --git a/gpu_tonemapper/EGLImageWrapper.h b/gpu_tonemapper/EGLImageWrapper.h
new file mode 100644
index 0000000..d7fc84b
--- /dev/null
+++ b/gpu_tonemapper/EGLImageWrapper.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __TONEMAPPER_EGLIMAGEWRAPPER_H__
+#define __TONEMAPPER_EGLIMAGEWRAPPER_H__
+
+#include <map>
+#include "EGLImageBuffer.h"
+
+class EGLImageWrapper {
+  static std::map<int, EGLImageBuffer *> eglImageBufferMap;
+
+ public:
+  static EGLImageBuffer *wrap(const void *pvt_handle);
+  static void destroy();
+};
+
+#endif  //__TONEMAPPER_EGLIMAGEWRAPPER_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/TonemapFactory.cpp b/gpu_tonemapper/TonemapFactory.cpp
new file mode 100644
index 0000000..81e9f7f
--- /dev/null
+++ b/gpu_tonemapper/TonemapFactory.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, 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 "TonemapFactory.h"
+#include <utils/Log.h>
+#include "EGLImageWrapper.h"
+#include "Tonemapper.h"
+#include "engine.h"
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------------
+Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize,
+                                          void *lutXform, int lutXformSize)
+//----------------------------------------------------------------------------------------------------------------------------------------------------------
+{
+  // initializes the engine - does nothing if already initialized
+  engine_initialize();
+
+  // build the tonemapper
+  Tonemapper *tonemapper = Tonemapper::build(type, colorMap, colorMapSize, lutXform, lutXformSize);
+
+  return tonemapper;
+}
+
+//------------------------------------------
+void TonemapperFactory_Destroy()
+//------------------------------------------
+{
+  // clear EGLImage mappings
+  EGLImageWrapper::destroy();
+  // shutdown the engine
+  engine_shutdown();
+}
diff --git a/gpu_tonemapper/TonemapFactory.h b/gpu_tonemapper/TonemapFactory.h
new file mode 100644
index 0000000..1004170
--- /dev/null
+++ b/gpu_tonemapper/TonemapFactory.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __TONEMAPPER_TONEMAPPERFACTORY_H__
+#define __TONEMAPPER_TONEMAPPERFACTORY_H__
+
+#include "Tonemapper.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// returns an instance of Tonemapper
+Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize,
+                                          void *lutXform, int lutXformSize);
+
+// destroy tonemap session
+void TonemapperFactory_Destroy();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  //__TONEMAPPER_TONEMAPPERFACTORY_H__
diff --git a/gpu_tonemapper/Tonemapper.cpp b/gpu_tonemapper/Tonemapper.cpp
new file mode 100644
index 0000000..957c133
--- /dev/null
+++ b/gpu_tonemapper/Tonemapper.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, 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 <utils/Log.h>
+
+#include "EGLImageWrapper.h"
+#include "Tonemapper.h"
+#include "engine.h"
+#include "forward_tonemap.inl"
+#include "fullscreen_vertex_shader.inl"
+#include "rgba_inverse_tonemap.inl"
+
+//-----------------------------------------------------------------------------
+Tonemapper::Tonemapper()
+//-----------------------------------------------------------------------------
+{
+  tonemapTexture = 0;
+  lutXformTexture = 0;
+  programID = 0;
+}
+
+//-----------------------------------------------------------------------------
+Tonemapper::~Tonemapper()
+//-----------------------------------------------------------------------------
+{
+  engine_deleteInputBuffer(tonemapTexture);
+  engine_deleteInputBuffer(lutXformTexture);
+  engine_deleteProgram(programID);
+}
+
+//-----------------------------------------------------------------------------
+Tonemapper *Tonemapper::build(int type, void *colorMap, int colorMapSize, void *lutXform,
+                              int lutXformSize)
+//-----------------------------------------------------------------------------
+{
+  if (colorMapSize <= 0) {
+      ALOGE("Invalid Color Map size = %d", colorMapSize);
+      return NULL;
+  }
+  engine_bind();
+
+  // build new tonemapper
+  Tonemapper *tonemapper = new Tonemapper();
+  // load the 3d lut
+  tonemapper->tonemapTexture = engine_load3DTexture(colorMap, colorMapSize, 0);
+  // load the non-uniform xform
+  tonemapper->lutXformTexture = engine_load1DTexture(lutXform, lutXformSize, 0);
+  bool bUseXform = (tonemapper->lutXformTexture != 0) && (lutXformSize != 0);
+
+  // create the program
+  const char *fragmentShaders[3];
+  int fragmentShaderCount = 0;
+  const char *version = "#version 300 es\n";
+  const char *define = "#define USE_NONUNIFORM_SAMPLING\n";
+
+  fragmentShaders[fragmentShaderCount++] = version;
+
+  // non-uniform sampling
+  if (bUseXform) {
+    fragmentShaders[fragmentShaderCount++] = define;
+  }
+
+  if (type == TONEMAP_INVERSE) {  // inverse tonemapping
+    fragmentShaders[fragmentShaderCount++] = rgba_inverse_tonemap_shader;
+  } else {  // forward tonemapping
+    fragmentShaders[fragmentShaderCount++] = forward_tonemap_shader;
+  }
+
+  tonemapper->programID =
+      engine_loadProgram(1, &fullscreen_vertex_shader, fragmentShaderCount, fragmentShaders);
+
+  return tonemapper;
+}
+
+//-----------------------------------------------------------------------------
+int Tonemapper::blit(const void *dst, const void *src, int srcFenceFd)
+//-----------------------------------------------------------------------------
+{
+  // make current
+  engine_bind();
+
+  // create eglimages if required
+  EGLImageBuffer *dst_buffer = EGLImageWrapper::wrap(dst);
+  EGLImageBuffer *src_buffer = EGLImageWrapper::wrap(src);
+
+  // bind the program
+  engine_setProgram(programID);
+
+  // set destination
+  engine_setDestination(dst_buffer->getFramebuffer(), 0, 0, dst_buffer->getWidth(),
+                        dst_buffer->getHeight());
+  // set source
+  engine_setExternalInputBuffer(0, src_buffer->getTexture());
+  // set 3d lut
+  engine_set3DInputBuffer(1, tonemapTexture);
+  // set non-uniform xform
+  engine_set2DInputBuffer(2, lutXformTexture);
+
+  // perform
+  int fenceFD = engine_blit(srcFenceFd);
+
+  return fenceFD;
+}
diff --git a/gpu_tonemapper/Tonemapper.h b/gpu_tonemapper/Tonemapper.h
new file mode 100644
index 0000000..9c41670
--- /dev/null
+++ b/gpu_tonemapper/Tonemapper.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __TONEMAPPER_TONEMAP_H__
+#define __TONEMAPPER_TONEMAP_H__
+
+#define TONEMAP_FORWARD 0
+#define TONEMAP_INVERSE 1
+
+class Tonemapper {
+ private:
+  unsigned int tonemapTexture;
+  unsigned int lutXformTexture;
+  unsigned int programID;
+  Tonemapper();
+
+ public:
+  ~Tonemapper();
+  static Tonemapper *build(int type, void *colorMap, int colorMapSize, void *lutXform,
+                           int lutXformSize);
+  int blit(const void *dst, const void *src, int srcFenceFd);
+};
+
+#endif  //__TONEMAPPER_TONEMAP_H__
diff --git a/gpu_tonemapper/engine.h b/gpu_tonemapper/engine.h
new file mode 100644
index 0000000..5635ee3
--- /dev/null
+++ b/gpu_tonemapper/engine.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __TONEMAPPER_ENGINE_H__
+#define __TONEMAPPER_ENGINE_H__
+
+bool engine_initialize();
+void engine_bind();
+void engine_shutdown();
+
+unsigned int engine_loadProgram(int, const char **, int, const char **);
+void engine_setProgram(int);
+void engine_deleteProgram(unsigned int);
+
+unsigned int engine_load3DTexture(void *data, int sz, int format);
+unsigned int engine_load1DTexture(void *xform, int xformSize, int format);
+void engine_deleteInputBuffer(unsigned int);
+
+void engine_set2DInputBuffer(int binding, unsigned int textureID);
+void engine_set3DInputBuffer(int binding, unsigned int textureID);
+void engine_setExternalInputBuffer(int binding, unsigned int textureID);
+void engine_setDestination(int id, int x, int y, int w, int h);
+
+int engine_blit(int);
+
+#endif  //__TONEMAPPER_ENGINE_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/forward_tonemap.inl b/gpu_tonemapper/forward_tonemap.inl
new file mode 100644
index 0000000..a008949
--- /dev/null
+++ b/gpu_tonemapper/forward_tonemap.inl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+const char* forward_tonemap_shader = ""
+    "#extension GL_OES_EGL_image_external_essl3 : require                       \n"
+    "precision highp float;                                                     \n"
+    "precision highp sampler2D;                                                 \n"
+    "layout(binding = 0) uniform samplerExternalOES externalTexture;            \n"
+    "layout(binding = 1) uniform sampler3D tonemapper;                          \n"
+    "layout(binding = 2) uniform sampler2D xform;                               \n"
+    "in vec2 uv;                                                                \n"
+    "out vec4 fs_color;                                                         \n"
+    "void main()                                                                \n"
+    "{                                                                          \n"
+    "vec4 rgb = texture(externalTexture, uv);                                   \n"
+    "#if defined(USE_NONUNIFORM_SAMPLING)                                       \n"
+    "float r = texture(xform, vec2(r, 0.0f)).r;                                 \n"
+    "float g = texture(xform, vec2(g, 0.0f)).g;                                 \n"
+    "float b = texture(xform, vec2(b, 0.0f)).b;                                 \n"
+    "#else                                                                      \n"
+    "float r = rgb.r;                                                           \n"
+    "float g = rgb.g;                                                           \n"
+    "float b = rgb.b;                                                           \n"
+    "#endif                                                                     \n"
+    "fs_color.rgb = texture(tonemapper, vec3(r, g, b)).rgb;                     \n"
+    "}                                                                          \n";
diff --git a/gpu_tonemapper/fullscreen_vertex_shader.inl b/gpu_tonemapper/fullscreen_vertex_shader.inl
new file mode 100644
index 0000000..9a70c2b
--- /dev/null
+++ b/gpu_tonemapper/fullscreen_vertex_shader.inl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+const char* fullscreen_vertex_shader = "                                      "
+"#version 300 es                                                            \n"
+"precision highp float;                                                     \n"
+"layout(location = 0) in vec2 iUV;                                          \n"
+"out vec2 uv;                                                               \n"
+"void main()                                                                \n"
+"{                                                                          \n"
+"    vec2 positions[3];                                                     \n"
+"    positions[0] = vec2(-1.0f, 3.0f);                                      \n"
+"    positions[1] = vec2(-1.0f, -1.0f);                                     \n"
+"    positions[2] = vec2(3.0f, -1.0f);                                      \n"
+"    vec2 uvs[3];                                                           \n"
+"    uvs[0] = vec2(0.0f, -1.0f);                                            \n"
+"    uvs[1] = vec2(0.0f, 1.0f);                                             \n"
+"    uvs[2] = vec2(2.0f, 1.0f);                                             \n"
+"    gl_Position = vec4(positions[gl_VertexID], -1.0f, 1.0f);               \n"
+"    uv = uvs[gl_VertexID];                                                 \n"
+"}                                                                          \n";
diff --git a/gpu_tonemapper/glengine.cpp b/gpu_tonemapper/glengine.cpp
new file mode 100644
index 0000000..e5c8e68
--- /dev/null
+++ b/gpu_tonemapper/glengine.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2016, 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 "glengine.h"
+#include <utils/Log.h>
+#include "engine.h"
+
+void checkGlError(const char *, int);
+void checkEglError(const char *, int);
+
+static EGLDisplay eglDisplay;
+static EGLContext eglContext;
+static EGLSurface eglSurface;
+
+static bool isEngineInitialized = false;
+
+//-----------------------------------------------------------------------------
+// Make Current
+void engine_bind()
+//-----------------------------------------------------------------------------
+{
+  EGL(eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext));
+}
+
+//-----------------------------------------------------------------------------
+// initialize GL
+//
+bool engine_initialize()
+//-----------------------------------------------------------------------------
+{
+  if (isEngineInitialized)
+    return true;
+
+  EGLBoolean result = false;
+
+  // display
+  eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  EGL(eglBindAPI(EGL_OPENGL_ES_API));
+
+  // initialize
+  EGL(eglInitialize(eglDisplay, 0, 0));
+
+  // config
+  EGLConfig eglConfig;
+  EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+                                  EGL_RED_SIZE,     8,
+                                  EGL_GREEN_SIZE,   8,
+                                  EGL_BLUE_SIZE,    8,
+                                  EGL_ALPHA_SIZE,   8,
+                                  EGL_NONE};
+  int numConfig = 0;
+  EGL(eglChooseConfig(eglDisplay, eglConfigAttribList, &eglConfig, 1, &numConfig));
+
+  // context
+  EGLint eglContextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+  eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, eglContextAttribList);
+
+  // surface
+  EGLint eglSurfaceAttribList[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
+  eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, eglSurfaceAttribList);
+
+  result = (EGL_TRUE == eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext));
+
+  isEngineInitialized = result;
+
+  ALOGI("In %s result = %d context = %p", __FUNCTION__, result, (void *)eglContext);
+
+  return result;
+}
+
+//-----------------------------------------------------------------------------
+// Shutdown.
+void engine_shutdown()
+//-----------------------------------------------------------------------------
+{
+  EGL(eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+  EGL(eglDestroySurface(eglDisplay, eglSurface));
+  EGL(eglDestroyContext(eglDisplay, eglContext));
+  EGL(eglTerminate(eglDisplay));
+  eglDisplay = EGL_NO_DISPLAY;
+  eglContext = EGL_NO_CONTEXT;
+  eglSurface = EGL_NO_SURFACE;
+  isEngineInitialized = false;
+}
+
+//-----------------------------------------------------------------------------
+void engine_deleteInputBuffer(unsigned int id)
+//-----------------------------------------------------------------------------
+{
+  if (id != 0) {
+    GL(glDeleteTextures(1, &id));
+  }
+}
+
+//-----------------------------------------------------------------------------
+void engine_deleteProgram(unsigned int id)
+//-----------------------------------------------------------------------------
+{
+  if (id != 0) {
+    GL(glDeleteProgram(id));
+  }
+}
+
+//-----------------------------------------------------------------------------
+unsigned int engine_load3DTexture(void *colorMapData, int sz, int format)
+//-----------------------------------------------------------------------------
+{
+  GLuint texture = 0;
+  GL(glGenTextures(1, &texture));
+  GL(glBindTexture(GL_TEXTURE_3D, texture));
+  GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+  GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+  GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
+  GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+  GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+
+  GL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB10_A2, sz, sz, sz, 0, GL_RGBA,
+                  GL_UNSIGNED_INT_2_10_10_10_REV, colorMapData));
+
+  return texture;
+}
+//-----------------------------------------------------------------------------
+unsigned int engine_load1DTexture(void *data, int sz, int format)
+//-----------------------------------------------------------------------------
+{
+  GLuint texture = 0;
+  if ((data != 0) && (sz != 0)) {
+    GL(glGenTextures(1, &texture));
+    GL(glBindTexture(GL_TEXTURE_2D, texture));
+    GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+    GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+    GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+    GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+
+    GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, sz, 1, 0, GL_RGBA,
+                    GL_UNSIGNED_INT_2_10_10_10_REV, data));
+  }
+  return texture;
+}
+
+//-----------------------------------------------------------------------------
+void dumpShaderLog(int shader)
+//-----------------------------------------------------------------------------
+{
+  int success;
+  GLchar infoLog[512];
+  GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success));
+  if (!success) {
+    glGetShaderInfoLog(shader, 512, NULL, infoLog);
+    ALOGI("Shader Failed to compile: %s\n", infoLog);
+  }
+}
+
+//-----------------------------------------------------------------------------
+GLuint engine_loadProgram(int vertexEntries, const char **vertex, int fragmentEntries,
+                          const char **fragment)
+//-----------------------------------------------------------------------------
+{
+  GLuint progId = glCreateProgram();
+
+  int vertId = glCreateShader(GL_VERTEX_SHADER);
+  int fragId = glCreateShader(GL_FRAGMENT_SHADER);
+
+  GL(glShaderSource(vertId, vertexEntries, vertex, 0));
+  GL(glCompileShader(vertId));
+  dumpShaderLog(vertId);
+
+  GL(glShaderSource(fragId, fragmentEntries, fragment, 0));
+  GL(glCompileShader(fragId));
+  dumpShaderLog(fragId);
+
+  GL(glAttachShader(progId, vertId));
+  GL(glAttachShader(progId, fragId));
+
+  GL(glLinkProgram(progId));
+
+  GL(glDetachShader(progId, vertId));
+  GL(glDetachShader(progId, fragId));
+
+  GL(glDeleteShader(vertId));
+  GL(glDeleteShader(fragId));
+
+  return progId;
+}
+
+//-----------------------------------------------------------------------------
+void WaitOnNativeFence(int fd)
+//-----------------------------------------------------------------------------
+{
+  if (fd != -1) {
+    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd, EGL_NONE};
+
+    EGLSyncKHR sync = eglCreateSyncKHR(eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+
+    if (sync == EGL_NO_SYNC_KHR) {
+      ALOGE("%s - Failed to Create sync from source fd", __FUNCTION__);
+    } else {
+      // the gpu will wait for this sync - not this cpu thread.
+      EGL(eglWaitSyncKHR(eglDisplay, sync, 0));
+      EGL(eglDestroySyncKHR(eglDisplay, sync));
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+int CreateNativeFence()
+//-----------------------------------------------------------------------------
+{
+  int fd = -1;
+
+  EGLSyncKHR sync = eglCreateSyncKHR(eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+  GL(glFlush());
+  if (sync == EGL_NO_SYNC_KHR) {
+    ALOGE("%s - Failed to Create Native Fence sync", __FUNCTION__);
+  } else {
+    fd = eglDupNativeFenceFDANDROID(eglDisplay, sync);
+    if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+      ALOGE("%s - Failed to dup sync", __FUNCTION__);
+    }
+    EGL(eglDestroySyncKHR(eglDisplay, sync));
+  }
+
+  return fd;
+}
+
+//-----------------------------------------------------------------------------
+void engine_setDestination(int id, int x, int y, int w, int h)
+//-----------------------------------------------------------------------------
+{
+  GL(glBindFramebuffer(GL_FRAMEBUFFER, id));
+  GL(glViewport(x, y, w, h));
+}
+
+//-----------------------------------------------------------------------------
+void engine_setProgram(int id)
+//-----------------------------------------------------------------------------
+{
+  GL(glUseProgram(id));
+}
+
+//-----------------------------------------------------------------------------
+void engine_set2DInputBuffer(int binding, unsigned int id)
+//-----------------------------------------------------------------------------
+{
+  GL(glActiveTexture(GL_TEXTURE0 + binding));
+  GL(glBindTexture(GL_TEXTURE_2D, id));
+}
+
+//-----------------------------------------------------------------------------
+void engine_set3DInputBuffer(int binding, unsigned int id)
+//-----------------------------------------------------------------------------
+{
+  GL(glActiveTexture(GL_TEXTURE0 + binding));
+  GL(glBindTexture(GL_TEXTURE_3D, id));
+}
+
+//-----------------------------------------------------------------------------
+void engine_setExternalInputBuffer(int binding, unsigned int id)
+//-----------------------------------------------------------------------------
+{
+  GL(glActiveTexture(GL_TEXTURE0 + binding));
+  GL(glBindTexture(0x8D65, id));
+}
+
+//-----------------------------------------------------------------------------
+int engine_blit(int srcFenceFd)
+//-----------------------------------------------------------------------------
+{
+  int fd = -1;
+  WaitOnNativeFence(srcFenceFd);
+  float fullscreen_vertices[]{0.0f, 2.0f, 0.0f, 0.0f, 2.0f, 0.0f};
+  GL(glEnableVertexAttribArray(0));
+  GL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, fullscreen_vertices));
+  GL(glDrawArrays(GL_TRIANGLES, 0, 3));
+  fd = CreateNativeFence();
+  GL(glFlush());
+  return fd;
+}
+
+//-----------------------------------------------------------------------------
+void checkGlError(const char *file, int line)
+//-----------------------------------------------------------------------------
+{
+  for (GLint error = glGetError(); error; error = glGetError()) {
+    char *pError;
+    switch (error) {
+      case GL_NO_ERROR:
+        pError = (char *)"GL_NO_ERROR";
+        break;
+      case GL_INVALID_ENUM:
+        pError = (char *)"GL_INVALID_ENUM";
+        break;
+      case GL_INVALID_VALUE:
+        pError = (char *)"GL_INVALID_VALUE";
+        break;
+      case GL_INVALID_OPERATION:
+        pError = (char *)"GL_INVALID_OPERATION";
+        break;
+      case GL_OUT_OF_MEMORY:
+        pError = (char *)"GL_OUT_OF_MEMORY";
+        break;
+      case GL_INVALID_FRAMEBUFFER_OPERATION:
+        pError = (char *)"GL_INVALID_FRAMEBUFFER_OPERATION";
+        break;
+
+      default:
+        ALOGE("glError (0x%x) %s:%d\n", error, file, line);
+        return;
+    }
+
+    ALOGE("glError (%s) %s:%d\n", pError, file, line);
+    return;
+  }
+  return;
+}
+
+//-----------------------------------------------------------------------------
+void checkEglError(const char *file, int line)
+//-----------------------------------------------------------------------------
+{
+  for (int i = 0; i < 5; i++) {
+    const EGLint error = eglGetError();
+    if (error == EGL_SUCCESS) {
+      break;
+    }
+
+    char *pError;
+    switch (error) {
+      case EGL_SUCCESS:
+        pError = (char *)"EGL_SUCCESS";
+        break;
+      case EGL_NOT_INITIALIZED:
+        pError = (char *)"EGL_NOT_INITIALIZED";
+        break;
+      case EGL_BAD_ACCESS:
+        pError = (char *)"EGL_BAD_ACCESS";
+        break;
+      case EGL_BAD_ALLOC:
+        pError = (char *)"EGL_BAD_ALLOC";
+        break;
+      case EGL_BAD_ATTRIBUTE:
+        pError = (char *)"EGL_BAD_ATTRIBUTE";
+        break;
+      case EGL_BAD_CONTEXT:
+        pError = (char *)"EGL_BAD_CONTEXT";
+        break;
+      case EGL_BAD_CONFIG:
+        pError = (char *)"EGL_BAD_CONFIG";
+        break;
+      case EGL_BAD_CURRENT_SURFACE:
+        pError = (char *)"EGL_BAD_CURRENT_SURFACE";
+        break;
+      case EGL_BAD_DISPLAY:
+        pError = (char *)"EGL_BAD_DISPLAY";
+        break;
+      case EGL_BAD_SURFACE:
+        pError = (char *)"EGL_BAD_SURFACE";
+        break;
+      case EGL_BAD_MATCH:
+        pError = (char *)"EGL_BAD_MATCH";
+        break;
+      case EGL_BAD_PARAMETER:
+        pError = (char *)"EGL_BAD_PARAMETER";
+        break;
+      case EGL_BAD_NATIVE_PIXMAP:
+        pError = (char *)"EGL_BAD_NATIVE_PIXMAP";
+        break;
+      case EGL_BAD_NATIVE_WINDOW:
+        pError = (char *)"EGL_BAD_NATIVE_WINDOW";
+        break;
+      case EGL_CONTEXT_LOST:
+        pError = (char *)"EGL_CONTEXT_LOST";
+        break;
+      default:
+        ALOGE("eglError (0x%x) %s:%d\n", error, file, line);
+        return;
+    }
+    ALOGE("eglError (%s) %s:%d\n", pError, file, line);
+    return;
+  }
+  return;
+}
diff --git a/gpu_tonemapper/glengine.h b/gpu_tonemapper/glengine.h
new file mode 100644
index 0000000..c5b166c
--- /dev/null
+++ b/gpu_tonemapper/glengine.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __TONEMAPPER_GLENGINE_H__
+#define __TONEMAPPER_GLENGINE_H__
+#include <EGL/egl.h>
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/eglext.h>
+#include <GLES3/gl31.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3ext.h>
+
+#if defined(CHECK_GL_ERRORS)
+#define GL(func) func;
+#define EGL(func) func;
+#else
+#define GL(func) \
+  func;          \
+  checkGlError(__FILE__, __LINE__);
+#define EGL(func) \
+  func;           \
+  checkEglError(__FILE__, __LINE__);
+#endif
+
+void checkGlError(const char *file, int line);
+void checkEglError(const char *file, int line);
+
+#endif  //__TONEMAPPER_GLENGINE_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/rgba_inverse_tonemap.inl b/gpu_tonemapper/rgba_inverse_tonemap.inl
new file mode 100644
index 0000000..399e2f8
--- /dev/null
+++ b/gpu_tonemapper/rgba_inverse_tonemap.inl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+const char* rgba_inverse_tonemap_shader = ""
+    "#extension GL_OES_EGL_image_external_essl3 : require                                               \n"
+    "precision highp float;                                                                             \n"
+    "precision highp sampler2D;                                                                         \n"
+    "layout(binding = 0) uniform samplerExternalOES externalTexture;                                    \n"
+    "layout(binding = 1) uniform sampler3D tonemapper;                                                  \n"
+    "layout(binding = 2) uniform sampler2D xform;                                                       \n"
+    "in vec2 uv;                                                                                        \n"
+    "out vec4 fs_color;                                                                                 \n"
+    "void main()                                                                                        \n"
+    "{                                                                                                  \n"
+    "vec2 flipped = uv;                                                                                 \n"
+    "flipped.y = 1.0 - flipped.y;                                                                       \n"
+    "flipped.x = flipped.x;                                                                             \n"
+    "vec4 rgb_premulalpha = texture(externalTexture, flipped);                                          \n"
+    "fs_color = rgb_premulalpha;                                                                        \n"
+    "if( rgb_premulalpha.a > 0.0 ) {                                                                    \n"
+    "vec3 rgb = rgb_premulalpha.rgb/rgb_premulalpha.a;                                                  \n"
+    "#if defined(USE_NONUNIFORM_SAMPLING)                                                               \n"
+    "float r = texture(xform, vec2(rgb.r, 0.0f)).r;                                                     \n"
+    "float g = texture(xform, vec2(rgb.g, 0.0f)).g;                                                     \n"
+    "float b = texture(xform, vec2(rgb.b, 0.0f)).b;                                                     \n"
+    "#else                                                                                              \n"
+    "float r = rgb.r;                                                                                   \n"
+    "float g = rgb.g;                                                                                   \n"
+    "float b = rgb.b;                                                                                   \n"
+    "#endif                                                                                             \n"
+    "fs_color.rgb = texture(tonemapper, vec3(r, g, b)).rgb * rgb_premulalpha.a;                         \n"
+    "fs_color.a = rgb_premulalpha.a;                                                                    \n"
+    "}                                                                                                  \n"
+    "}                                                                                                  \n";