display: msm8909w caf release LW.BR.4.0-00800-8x09w.0 for SD2100.

MSM8909W display HAL code copied from CAF release LW.BR.4.0-00800-8x09w.0.

Bug: 79356346
Test: build
Change-Id: Ie801976595c8ed9164b0d91737f5daf40764d8a6
Signed-off-by: Ben Fennema <[email protected]>
diff --git a/msm8909/gpu_tonemapper/Android.mk b/msm8909/gpu_tonemapper/Android.mk
new file mode 100644
index 0000000..77ecc4a
--- /dev/null
+++ b/msm8909/gpu_tonemapper/Android.mk
@@ -0,0 +1,27 @@
+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
+include $(BUILD_COPY_HEADERS)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE              := libgpu_tonemapper
+LOCAL_VENDOR_MODULE       := true
+LOCAL_MODULE_TAGS         := optional
+LOCAL_C_INCLUDES          := $(TARGET_OUT_HEADERS)/qcom/display/
+LOCAL_C_INCLUDES          += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_SHARED_LIBRARIES    := libEGL libGLESv2 libGLESv3 libui libutils liblog
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
+
+LOCAL_CFLAGS              := $(version_flag) -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/msm8909/gpu_tonemapper/EGLImageBuffer.cpp b/msm8909/gpu_tonemapper/EGLImageBuffer.cpp
new file mode 100644
index 0000000..eeb0273
--- /dev/null
+++ b/msm8909/gpu_tonemapper/EGLImageBuffer.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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"
+
+//-----------------------------------------------------------------------------
+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));
+}
diff --git a/msm8909/gpu_tonemapper/EGLImageBuffer.h b/msm8909/gpu_tonemapper/EGLImageBuffer.h
new file mode 100644
index 0000000..23af573
--- /dev/null
+++ b/msm8909/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/msm8909/gpu_tonemapper/EGLImageWrapper.cpp b/msm8909/gpu_tonemapper/EGLImageWrapper.cpp
new file mode 100644
index 0000000..dfc16d8
--- /dev/null
+++ b/msm8909/gpu_tonemapper/EGLImageWrapper.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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 "EGLImageWrapper.h"
+#include <cutils/native_handle.h>
+#include <gralloc_priv.h>
+#include <ui/GraphicBuffer.h>
+#include <fcntl.h>
+#include <linux/msm_ion.h>
+
+//-----------------------------------------------------------------------------
+void free_ion_cookie(int ion_fd, int cookie)
+//-----------------------------------------------------------------------------
+{
+  if (ion_fd && !ioctl(ion_fd, ION_IOC_FREE, &cookie)) {
+  } else {
+      ALOGE("ION_IOC_FREE failed: ion_fd = %d, cookie = %d", ion_fd, cookie);
+  }
+}
+
+//-----------------------------------------------------------------------------
+int get_ion_cookie(int ion_fd, int fd)
+//-----------------------------------------------------------------------------
+{
+   int cookie = fd;
+
+   struct ion_fd_data fdData;
+   memset(&fdData, 0, sizeof(fdData));
+   fdData.fd = fd;
+
+   if (ion_fd && !ioctl(ion_fd, ION_IOC_IMPORT, &fdData)) {
+        cookie = fdData.handle;
+   } else {
+        ALOGE("ION_IOC_IMPORT failed: ion_fd = %d, fd = %d", ion_fd, fd);
+   }
+
+   return cookie;
+}
+
+//-----------------------------------------------------------------------------
+EGLImageWrapper::DeleteEGLImageCallback::DeleteEGLImageCallback(int fd)
+//-----------------------------------------------------------------------------
+{
+    ion_fd = fd;
+}
+
+//-----------------------------------------------------------------------------
+void EGLImageWrapper::DeleteEGLImageCallback::operator()(int& k, EGLImageBuffer*& eglImage)
+//-----------------------------------------------------------------------------
+{
+    free_ion_cookie(ion_fd,  k);
+    if( eglImage != 0 )
+    {
+        delete eglImage;
+    }
+}
+
+//-----------------------------------------------------------------------------
+EGLImageWrapper::EGLImageWrapper()
+//-----------------------------------------------------------------------------
+{
+    eglImageBufferMap = new android::LruCache<int, EGLImageBuffer*>(32);
+    ion_fd = open("/dev/ion", O_RDONLY);
+    callback = new DeleteEGLImageCallback(ion_fd);
+    eglImageBufferMap->setOnEntryRemovedListener(callback);
+}
+
+//-----------------------------------------------------------------------------
+EGLImageWrapper::~EGLImageWrapper()
+//-----------------------------------------------------------------------------
+{
+    if( eglImageBufferMap != 0 )
+    {
+        eglImageBufferMap->clear();
+        delete eglImageBufferMap;
+        eglImageBufferMap = 0;
+    }
+
+    if( callback != 0 )
+    {
+        delete callback;
+        callback = 0;
+    }
+
+    if( ion_fd > 0 )
+    {
+        close(ion_fd);
+    }
+    ion_fd = -1;
+}
+//-----------------------------------------------------------------------------
+static EGLImageBuffer* L_wrap(const private_handle_t *src)
+//-----------------------------------------------------------------------------
+{
+    EGLImageBuffer* result = 0;
+
+    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->unaligned_width, src->unaligned_height, src->format,
+#ifndef __NOUGAT__
+                                   1, // Layer count
+#endif
+                                   flags, src->width /*src->stride*/,
+                                   native_handle, false);
+
+    result = new EGLImageBuffer(graphicBuffer);
+
+    return result;
+}
+
+//-----------------------------------------------------------------------------
+EGLImageBuffer *EGLImageWrapper::wrap(const void *pvt_handle)
+//-----------------------------------------------------------------------------
+{
+    const private_handle_t *src = static_cast<const private_handle_t *>(pvt_handle);
+
+    int ion_cookie = get_ion_cookie(ion_fd, src->fd);
+    EGLImageBuffer* eglImage = eglImageBufferMap->get(ion_cookie);
+    if( eglImage == 0 )
+    {
+        eglImage = L_wrap(src);
+        eglImageBufferMap->put(ion_cookie, eglImage);
+    }
+    else {
+        free_ion_cookie(ion_fd, ion_cookie);
+    }
+
+    return eglImage;
+}
diff --git a/msm8909/gpu_tonemapper/EGLImageWrapper.h b/msm8909/gpu_tonemapper/EGLImageWrapper.h
new file mode 100644
index 0000000..e9a4d68
--- /dev/null
+++ b/msm8909/gpu_tonemapper/EGLImageWrapper.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __TONEMAPPER_EGLIMAGEWRAPPER_H__
+#define __TONEMAPPER_EGLIMAGEWRAPPER_H__
+
+#include <utils/LruCache.h>
+#include "EGLImageBuffer.h"
+
+class EGLImageWrapper {
+    private:
+        class DeleteEGLImageCallback : public android::OnEntryRemoved<int, EGLImageBuffer*>
+        {
+        private:
+          int ion_fd;
+        public:
+          DeleteEGLImageCallback(int ion_fd);
+          void operator()(int& ion_cookie, EGLImageBuffer*& eglImage);
+        };
+
+        android::LruCache<int, EGLImageBuffer *>* eglImageBufferMap;
+        DeleteEGLImageCallback* callback;
+        int ion_fd;
+
+    public:
+        EGLImageWrapper();
+        ~EGLImageWrapper();
+        EGLImageBuffer* wrap(const void *pvt_handle);
+};
+
+#endif  //__TONEMAPPER_EGLIMAGEWRAPPER_H__
diff --git a/msm8909/gpu_tonemapper/TonemapFactory.cpp b/msm8909/gpu_tonemapper/TonemapFactory.cpp
new file mode 100644
index 0000000..db4b8be
--- /dev/null
+++ b/msm8909/gpu_tonemapper/TonemapFactory.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "TonemapFactory.h"
+#include <log/log.h>
+#include "Tonemapper.h"
+#include "engine.h"
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------------
+Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize,
+                                          void *lutXform, int lutXformSize, bool isSecure)
+//----------------------------------------------------------------------------------------------------------------------------------------------------------
+{
+  // build the tonemapper
+  Tonemapper *tonemapper = Tonemapper::build(type, colorMap, colorMapSize, lutXform, lutXformSize, isSecure);
+
+  return tonemapper;
+}
diff --git a/msm8909/gpu_tonemapper/TonemapFactory.h b/msm8909/gpu_tonemapper/TonemapFactory.h
new file mode 100644
index 0000000..17cad40
--- /dev/null
+++ b/msm8909/gpu_tonemapper/TonemapFactory.h
@@ -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.
+ */
+
+#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, bool isSecure);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  //__TONEMAPPER_TONEMAPPERFACTORY_H__
diff --git a/msm8909/gpu_tonemapper/Tonemapper.cpp b/msm8909/gpu_tonemapper/Tonemapper.cpp
new file mode 100644
index 0000000..811e091
--- /dev/null
+++ b/msm8909/gpu_tonemapper/Tonemapper.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 <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;
+  eglImageWrapper = new EGLImageWrapper();
+
+  lutXformScaleOffset[0] = 1.0f;
+  lutXformScaleOffset[1] = 0.0f;
+
+  tonemapScaleOffset[0] = 1.0f;
+  tonemapScaleOffset[1] = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+Tonemapper::~Tonemapper()
+//-----------------------------------------------------------------------------
+{
+  engine_bind(engineContext);
+  engine_deleteInputBuffer(tonemapTexture);
+  engine_deleteInputBuffer(lutXformTexture);
+  engine_deleteProgram(programID);
+
+  // clear EGLImage mappings
+  if (eglImageWrapper != 0) {
+    delete eglImageWrapper;
+    eglImageWrapper = 0;
+  }
+
+  engine_shutdown(engineContext);
+}
+
+//-----------------------------------------------------------------------------
+Tonemapper *Tonemapper::build(int type, void *colorMap, int colorMapSize, void *lutXform,
+                              int lutXformSize, bool isSecure)
+//-----------------------------------------------------------------------------
+{
+  if (colorMapSize <= 0) {
+      ALOGE("Invalid Color Map size = %d", colorMapSize);
+      return NULL;
+  }
+
+  // build new tonemapper
+  Tonemapper *tonemapper = new Tonemapper();
+
+  tonemapper->engineContext = engine_initialize(isSecure);
+
+  engine_bind(tonemapper->engineContext);
+
+  // load the 3d lut
+  tonemapper->tonemapTexture = engine_load3DTexture(colorMap, colorMapSize, 0);
+  tonemapper->tonemapScaleOffset[0] = ((float)(colorMapSize-1))/((float)(colorMapSize));
+  tonemapper->tonemapScaleOffset[1] = 1.0f/(2.0f*colorMapSize);
+
+  // load the non-uniform xform
+  tonemapper->lutXformTexture = engine_load1DTexture(lutXform, lutXformSize, 0);
+  bool bUseXform = (tonemapper->lutXformTexture != 0) && (lutXformSize != 0);
+  if( bUseXform )
+  {
+      tonemapper->lutXformScaleOffset[0] = ((float)(lutXformSize-1))/((float)(lutXformSize));
+      tonemapper->lutXformScaleOffset[1] = 1.0f/(2.0f*lutXformSize);
+  }
+
+  // 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(engineContext);
+
+  // create eglimages if required
+  EGLImageBuffer *dst_buffer = eglImageWrapper->wrap(dst);
+  EGLImageBuffer *src_buffer = eglImageWrapper->wrap(src);
+
+  // bind the program
+  engine_setProgram(programID);
+
+  engine_setData2f(3, tonemapScaleOffset);
+  bool bUseXform = (lutXformTexture != 0);
+  if( bUseXform )
+  {
+    engine_setData2f(4, lutXformScaleOffset);
+  }
+
+  // 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/msm8909/gpu_tonemapper/Tonemapper.h b/msm8909/gpu_tonemapper/Tonemapper.h
new file mode 100644
index 0000000..707cdfe
--- /dev/null
+++ b/msm8909/gpu_tonemapper/Tonemapper.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __TONEMAPPER_TONEMAP_H__
+#define __TONEMAPPER_TONEMAP_H__
+
+#define TONEMAP_FORWARD 0
+#define TONEMAP_INVERSE 1
+
+#include "EGLImageWrapper.h"
+#include "engine.h"
+
+class Tonemapper {
+ private:
+  void* engineContext;
+  unsigned int tonemapTexture;
+  unsigned int lutXformTexture;
+  unsigned int programID;
+  float lutXformScaleOffset[2];
+  float tonemapScaleOffset[2];
+  EGLImageWrapper* eglImageWrapper;
+  Tonemapper();
+
+ public:
+  ~Tonemapper();
+  static Tonemapper *build(int type, void *colorMap, int colorMapSize, void *lutXform,
+                           int lutXformSize, bool isSecure);
+  int blit(const void *dst, const void *src, int srcFenceFd);
+};
+
+#endif  //__TONEMAPPER_TONEMAP_H__
diff --git a/msm8909/gpu_tonemapper/engine.h b/msm8909/gpu_tonemapper/engine.h
new file mode 100644
index 0000000..8fb9452
--- /dev/null
+++ b/msm8909/gpu_tonemapper/engine.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef __TONEMAPPER_ENGINE_H__
+#define __TONEMAPPER_ENGINE_H__
+
+void* engine_initialize(bool isSecure);
+void engine_bind(void*);
+void engine_shutdown(void*);
+
+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);
+void engine_setData2f(int loc, float* data);
+
+int engine_blit(int);
+
+#endif  //__TONEMAPPER_ENGINE_H__
diff --git a/msm8909/gpu_tonemapper/forward_tonemap.inl b/msm8909/gpu_tonemapper/forward_tonemap.inl
new file mode 100644
index 0000000..0d89a9e
--- /dev/null
+++ b/msm8909/gpu_tonemapper/forward_tonemap.inl
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+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"
+    "layout(location = 3) uniform vec2 tSO;                                     \n"
+    "#ifdef USE_NONUNIFORM_SAMPLING                                             \n"
+    "layout(location = 4) uniform vec2 xSO;                                     \n"
+    "#endif                                                                     \n"
+    "in vec2 uv;                                                                \n"
+    "out vec4 fs_color;                                                         \n"
+    "                                                                           \n"
+    "vec3 ScaleOffset(in vec3 samplePt, in vec2 so)                             \n"
+    "{                                                                          \n"
+    "   vec3 adjPt = so.x * samplePt + so.y;                                    \n"
+    "   return adjPt;                                                           \n"
+    "}                                                                          \n"
+    "                                                                           \n"
+    "void main()                                                                \n"
+    "{                                                                          \n"
+    "vec2 flipped = vec2(uv.x, 1.0f - uv.y);                                    \n"
+    "vec4 rgb = texture(externalTexture, flipped);                              \n"
+    "#ifdef USE_NONUNIFORM_SAMPLING                                             \n"
+    "vec3 adj = ScaleOffset(rgb.xyz, xSO);                                      \n"
+    "float r = texture(xform, vec2(adj.r, 0.5f)).r;                             \n"
+    "float g = texture(xform, vec2(adj.g, 0.5f)).g;                             \n"
+    "float b = texture(xform, vec2(adj.b, 0.5f)).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, ScaleOffset(vec3(r, g, b), tSO)).rgb;   \n"
+    "}                                                                          \n";
diff --git a/msm8909/gpu_tonemapper/fullscreen_vertex_shader.inl b/msm8909/gpu_tonemapper/fullscreen_vertex_shader.inl
new file mode 100644
index 0000000..9a70c2b
--- /dev/null
+++ b/msm8909/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/msm8909/gpu_tonemapper/glengine.cpp b/msm8909/gpu_tonemapper/glengine.cpp
new file mode 100644
index 0000000..35e1932
--- /dev/null
+++ b/msm8909/gpu_tonemapper/glengine.cpp
@@ -0,0 +1,415 @@
+/*
+ * 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 "glengine.h"
+#include <log/log.h>
+#include "engine.h"
+
+void checkGlError(const char *, int);
+void checkEglError(const char *, int);
+
+class EngineContext {
+    public:
+    EGLDisplay eglDisplay;
+    EGLContext eglContext;
+    EGLSurface eglSurface;
+    EngineContext()
+    {
+        eglDisplay = EGL_NO_DISPLAY;
+        eglContext = EGL_NO_CONTEXT;
+        eglSurface = EGL_NO_SURFACE;
+    }
+};
+
+//-----------------------------------------------------------------------------
+// Make Current
+void engine_bind(void* context)
+//-----------------------------------------------------------------------------
+{
+  EngineContext* engineContext = (EngineContext*)(context);
+  EGL(eglMakeCurrent(engineContext->eglDisplay, engineContext->eglSurface, engineContext->eglSurface, engineContext->eglContext));
+}
+
+//-----------------------------------------------------------------------------
+// initialize GL
+//
+void* engine_initialize(bool isSecure)
+//-----------------------------------------------------------------------------
+{
+  EngineContext* engineContext = new EngineContext();
+
+  // display
+  engineContext->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  EGL(eglBindAPI(EGL_OPENGL_ES_API));
+
+  // initialize
+  EGL(eglInitialize(engineContext->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(engineContext->eglDisplay, eglConfigAttribList, &eglConfig, 1, &numConfig));
+
+  // context
+  EGLint eglContextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
+                                   isSecure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+                                   isSecure ? EGL_TRUE : EGL_NONE,
+                                   EGL_NONE};
+  engineContext->eglContext = eglCreateContext(engineContext->eglDisplay, eglConfig, NULL, eglContextAttribList);
+
+  // surface
+  EGLint eglSurfaceAttribList[] = {EGL_WIDTH, 1,
+                                   EGL_HEIGHT, 1,
+                                   isSecure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+                                   isSecure ? EGL_TRUE : EGL_NONE,
+                                   EGL_NONE};
+  engineContext->eglSurface = eglCreatePbufferSurface(engineContext->eglDisplay, eglConfig, eglSurfaceAttribList);
+
+  eglMakeCurrent(engineContext->eglDisplay, engineContext->eglSurface, engineContext->eglSurface, engineContext->eglContext);
+
+  ALOGI("In %s context = %p", __FUNCTION__, (void *)(engineContext->eglContext));
+
+  return (void*)(engineContext);
+}
+
+//-----------------------------------------------------------------------------
+// Shutdown.
+void engine_shutdown(void* context)
+//-----------------------------------------------------------------------------
+{
+  EngineContext* engineContext = (EngineContext*)context;
+  EGL(eglMakeCurrent(engineContext->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+  EGL(eglDestroySurface(engineContext->eglDisplay, engineContext->eglSurface));
+  EGL(eglDestroyContext(engineContext->eglDisplay, engineContext->eglContext));
+  EGL(eglTerminate(engineContext->eglDisplay));
+  engineContext->eglDisplay = EGL_NO_DISPLAY;
+  engineContext->eglContext = EGL_NO_CONTEXT;
+  engineContext->eglSurface = EGL_NO_SURFACE;
+}
+
+//-----------------------------------------------------------------------------
+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));
+  }
+}
+
+//-----------------------------------------------------------------------------
+void engine_setData2f(int location, float* data)
+//-----------------------------------------------------------------------------
+{
+    GL(glUniform2f(location, data[0], data[1]));
+}
+
+//-----------------------------------------------------------------------------
+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 = 0;
+  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(eglGetCurrentDisplay(), 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(eglGetCurrentDisplay(), sync, 0));
+      EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------
+int CreateNativeFence()
+//-----------------------------------------------------------------------------
+{
+  int fd = -1;
+
+  EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), 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(eglGetCurrentDisplay(), sync);
+    if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+      ALOGE("%s - Failed to dup sync", __FUNCTION__);
+    }
+    EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), 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/msm8909/gpu_tonemapper/glengine.h b/msm8909/gpu_tonemapper/glengine.h
new file mode 100644
index 0000000..f6aeec8
--- /dev/null
+++ b/msm8909/gpu_tonemapper/glengine.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+
+void checkGlError(const char *file, int line);
+void checkEglError(const char *file, int line);
+
+#endif  //__TONEMAPPER_GLENGINE_H__
diff --git a/msm8909/gpu_tonemapper/rgba_inverse_tonemap.inl b/msm8909/gpu_tonemapper/rgba_inverse_tonemap.inl
new file mode 100644
index 0000000..2865fbe
--- /dev/null
+++ b/msm8909/gpu_tonemapper/rgba_inverse_tonemap.inl
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+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"
+    "layout(location = 3) uniform vec2 tSO;                                                             \n"
+    "#if defined(USE_NONUNIFORM_SAMPLING)                                                               \n"
+    "layout(location = 4) uniform vec2 xSO;                                                             \n"
+    "#endif                                                                                             \n"
+    "in vec2 uv;                                                                                        \n"
+    "out vec4 fs_color;                                                                                 \n"
+    "                                                                                                   \n"
+    "vec3 ScaleOffset(in vec3 samplePt, in vec2 so)                                                     \n"
+    "{                                                                                                  \n"
+    "   vec3 adjPt = so.x * samplePt + so.y;                                                            \n"
+    "   return adjPt;                                                                                   \n"
+    "}                                                                                                  \n"
+    "                                                                                                   \n"
+    "void main()                                                                                        \n"
+    "{                                                                                                  \n"
+    "vec2 flipped = vec2(uv.x, 1.0f - uv.y);                                                            \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"
+    "vec3 adj = ScaleOffset(rgb.xyz, xSO);                                                              \n"
+    "float r = texture(xform, vec2(adj.r, 0.5f)).r;                                                     \n"
+    "float g = texture(xform, vec2(adj.g, 0.5f)).g;                                                     \n"
+    "float b = texture(xform, vec2(adj.b, 0.5f)).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, ScaleOffset(vec3(r, g, b), tSO)).rgb * rgb_premulalpha.a;       \n"
+    "fs_color.a = rgb_premulalpha.a;                                                                    \n"
+    "}                                                                                                  \n"
+    "}                                                                                                  \n";