Merge "sdm: Reject bit clk updates in inactive state."
diff --git a/composer/Android.mk b/composer/Android.mk
index 306a03a..f4ddbe5 100644
--- a/composer/Android.mk
+++ b/composer/Android.mk
@@ -25,6 +25,7 @@
                                  libsdmcore libqservice libqdutils libqdMetaData \
                                  libdisplaydebug libsdmutils libgrallocutils libui \
                                  libgpu_tonemapper \
+                                 libEGL libGLESv2 libGLESv3 \
                                  vendor.qti.hardware.display.composer@1.0 \
                                  vendor.qti.hardware.display.composer@2.0 \
                                  android.hardware.graphics.composer@2.1 \
@@ -68,7 +69,13 @@
                                  hwc_tonemapper.cpp \
                                  display_null.cpp \
                                  hwc_socket_handler.cpp \
-                                 hwc_buffer_allocator.cpp
+                                 hwc_buffer_allocator.cpp \
+                                 hwc_display_virtual_factory.cpp \
+                                 hwc_display_virtual_dpu.cpp \
+                                 hwc_display_virtual_gpu.cpp \
+                                 gl_common.cpp \
+                                 gl_color_convert.cpp \
+                                 gl_color_convert_impl.cpp
 
 LOCAL_INIT_RC                 := vendor.qti.hardware.display.composer-service.rc
 LOCAL_VINTF_FRAGMENTS         := vendor.qti.hardware.display.composer-service.xml
diff --git a/composer/gl_color_convert.cpp b/composer/gl_color_convert.cpp
new file mode 100644
index 0000000..03f7377
--- /dev/null
+++ b/composer/gl_color_convert.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gl_color_convert_impl.h"
+#include "gl_color_convert.h"
+
+#define __CLASS__ "GLColorConvert"
+
+namespace sdm {
+
+GLColorConvert* GLColorConvert::GetInstance(GLRenderTarget target, bool secure) {
+  GLColorConvertImpl* color_convert =  new GLColorConvertImpl(target, secure);
+  if (color_convert == nullptr) {
+    DLOGE("Failed to create color convert instance for %d target %d secure", target, secure);
+    return nullptr;
+  }
+
+  int status = color_convert->Init();
+  if (status != 0) {
+    DLOGE("Failed to initialize GL Color convert instance %d", status);
+    delete color_convert;
+    return nullptr;
+  }
+
+  DLOGI("Created instance successfully");
+
+  return color_convert;
+}
+
+void GLColorConvert::Destroy(GLColorConvert* intf) {
+  GLColorConvertImpl* color_convert = static_cast<GLColorConvertImpl*>(intf);
+  if (color_convert->Deinit() != 0) {
+    DLOGE("De Init failed");
+  }
+
+  delete color_convert;
+}
+
+}  // namespace sdm
diff --git a/composer/gl_color_convert.h b/composer/gl_color_convert.h
new file mode 100644
index 0000000..2080a97
--- /dev/null
+++ b/composer/gl_color_convert.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GL_COLOR_CONVERT_H__
+#define __GL_COLOR_CONVERT_H__
+
+#include <gralloc_priv.h>
+
+namespace sdm {
+
+enum GLRenderTarget {
+  kTargetRGBA,
+  kTargetYUV,
+};
+
+struct GLRect {
+  float left = 0.0f;
+  float top = 0.0f;
+  float right = 0.0f;
+  float bottom = 0.0f;
+};
+
+class GLColorConvert {
+ public:
+  static GLColorConvert* GetInstance(GLRenderTarget target, bool secure);
+  static void Destroy(GLColorConvert* intf);
+
+  virtual int Blit(const private_handle_t *src_hnd, const private_handle_t *dst_hnd,
+                   const GLRect &src_rect, const GLRect &dst_rect, int src_acquire_fence_fd,
+                   int dst_acquire_fence_fd, int *release_fence_fd) = 0;
+ protected:
+  virtual ~GLColorConvert() { }
+};
+
+}  // namespace sdm
+
+#endif  // __GL_COLOR_CONVERT_H__
diff --git a/composer/gl_color_convert_impl.cpp b/composer/gl_color_convert_impl.cpp
new file mode 100644
index 0000000..fb5d060
--- /dev/null
+++ b/composer/gl_color_convert_impl.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gl_color_convert_impl.h"
+
+#define __CLASS__ "GLColorConvertImpl"
+
+namespace sdm {
+
+const float kFullScreenVertices[] = {
+  -1.0f,  3.0f,
+  -1.0f, -1.0f,
+  3.0f, -1.0f
+};
+
+const float kFullScreenTexCoords[] = {
+  0.0f, 2.0f,
+  0.0f, 0.0f,
+  2.0f, 0.0f
+};
+
+const char* kVertexShader = ""
+  "#version 300 es                                                       \n"
+  "precision highp float;                                                \n"
+  "layout(location = 0) in vec2 in_pos;                                  \n"
+  "layout(location = 1) in vec2 in_uv;                                   \n"
+  "                                                                      \n"
+  "out vec2 uv;                                                          \n"
+  "                                                                      \n"
+  "void main()                                                           \n"
+  "{                                                                     \n"
+  "    gl_Position = vec4(in_pos, 0.0, 1.0);                             \n"
+  "    uv = in_uv;                                                       \n"
+  "}                                                                     \n";
+
+const char* kConvertRgbToYuvShader = ""
+  "#extension GL_EXT_YUV_target : require                                \n"
+  "precision highp float;                                                \n"
+  "                                                                      \n"
+  "layout(binding = 0) uniform sampler2D u_sTexture;                     \n"
+  "                                                                      \n"
+  "in vec2 uv;                                                           \n"
+  "layout (yuv) out vec4 color;                                          \n"
+  "                                                                      \n"
+  "void main()                                                           \n"
+  "{                                                                     \n"
+  "    vec3 rgbColor = texture(u_sTexture, uv).rgb;                      \n"
+  "    color = vec4(rgb_2_yuv(rgbColor, itu_601_full_range), 1.0);       \n"
+  "}                                                                     \n";
+
+int GLColorConvertImpl::CreateContext(GLRenderTarget target, bool secure) {
+  if (target != kTargetRGBA && target != kTargetYUV) {
+    DLOGE("Invalid GLRenderTarget: %d", target);
+    return -1;
+  }
+
+  ctx_.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  EGL(eglBindAPI(EGL_OPENGL_ES_API));
+
+  // Initialize current display.
+  EGL(eglInitialize(ctx_.egl_display, nullptr, nullptr));
+
+  // Get attributes corresponing to render target.
+  // Describes Framebuffer attributes like buffer depth, color space etc;
+  EGLConfig eglConfig;
+  int numConfig = 0;
+  if (target == kTargetRGBA) {
+    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};
+    EGL(eglChooseConfig(ctx_.egl_display, eglConfigAttribList, &eglConfig, 1, &numConfig));
+  } else {
+    EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+                                    EGL_RENDERABLE_TYPE,           EGL_OPENGL_ES2_BIT,
+                                    EGL_COLOR_BUFFER_TYPE,         EGL_YUV_BUFFER_EXT,
+                                    EGL_YUV_ORDER_EXT,             EGL_YUV_ORDER_YUV_EXT,
+                                    EGL_YUV_NUMBER_OF_PLANES_EXT,  2,
+                                    EGL_YUV_SUBSAMPLE_EXT,         EGL_YUV_SUBSAMPLE_4_2_0_EXT,
+                                    EGL_YUV_DEPTH_RANGE_EXT,       EGL_YUV_DEPTH_RANGE_LIMITED_EXT,
+                                    EGL_YUV_CSC_STANDARD_EXT,      EGL_YUV_CSC_STANDARD_601_EXT,
+                                    EGL_YUV_PLANE_BPP_EXT,         EGL_YUV_PLANE_BPP_8_EXT,
+                                    EGL_NONE};
+    EGL(eglChooseConfig(ctx_.egl_display, eglConfigAttribList, &eglConfig, 1, &numConfig));
+  }
+
+  // When GPU runs in protected context it can read from
+  //  - Protected sources
+  //  - UnProtected source
+  // and writes into Protected buffer.
+  // VS in UnProtected context it can read/write happen from/to Unprotected sources.
+  EGLint egl_contextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
+                                    secure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+                                    secure ? EGL_TRUE : EGL_NONE,
+                                    EGL_NONE};
+  ctx_.egl_context = eglCreateContext(ctx_.egl_display, eglConfig, NULL, egl_contextAttribList);
+
+  // eglCreatePbufferSurface creates an off-screen pixel buffer surface and returns its handle
+  EGLint egl_surfaceAttribList[] = {EGL_WIDTH, 1,
+                                    EGL_HEIGHT, 1,
+                                    secure ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+                                    secure ? EGL_TRUE : EGL_NONE,
+                                    EGL_NONE};
+  ctx_.egl_surface = eglCreatePbufferSurface(ctx_.egl_display, eglConfig, egl_surfaceAttribList);
+
+  // eglMakeCurrent attaches rendering context to rendering surface.
+  MakeCurrent(&ctx_);
+
+  DLOGI("Created context = %p", (void *)(&ctx_.egl_context));
+
+  // Load Vertex and Fragment shaders.
+  const char *fragment_shaders[2] = { };
+  int count = 0;
+  const char *version = "#version 300 es\n";
+
+  fragment_shaders[count++] = version;
+
+  // ToDo: Add support to yuv_to_rgb shader.
+  fragment_shaders[count++] = kConvertRgbToYuvShader;
+
+  ctx_.program_id = LoadProgram(1, &kVertexShader, count, fragment_shaders);
+
+  return 0;
+}
+
+int GLColorConvertImpl::Blit(const private_handle_t *src_hnd, const private_handle_t *dst_hnd,
+                             const GLRect &src_rect, const GLRect &dst_rect,
+                             int src_acquire_fence_fd, int dst_acquire_fence_fd,
+                             int *release_fence_fd) {
+  DTRACE_SCOPED();
+  // eglMakeCurrent attaches rendering context to rendering surface.
+  MakeCurrent(&ctx_);
+
+  SetProgram(ctx_.program_id);
+
+  SetSourceBuffer(src_hnd);
+  SetDestinationBuffer(dst_hnd);
+
+  glEnableVertexAttribArray(0);
+  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, kFullScreenVertices);
+  glEnableVertexAttribArray(1);
+  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kFullScreenTexCoords);
+  glDrawArrays(GL_TRIANGLES, 0, 3);
+
+  int in_fence_fd = sync_merge(__CLASS__, src_acquire_fence_fd, dst_acquire_fence_fd);
+  if (in_fence_fd >= 0) {
+    WaitOnInputFence(in_fence_fd);
+  }
+
+  // Create output fence for client to wait on.
+  *release_fence_fd = CreateOutputFence();
+
+  return 0;
+}
+
+int GLColorConvertImpl::Init() {
+  return CreateContext(target_, secure_);
+}
+
+int GLColorConvertImpl::Deinit() {
+  MakeCurrent(&ctx_);
+  DestroyContext(&ctx_);
+
+  return 0;
+}
+
+GLColorConvertImpl::~GLColorConvertImpl() {}
+
+GLColorConvertImpl::GLColorConvertImpl(GLRenderTarget target, bool secure) {
+  target_ = target;
+  secure_ = secure;
+}
+
+}  // namespace sdm
+
diff --git a/composer/gl_color_convert_impl.h b/composer/gl_color_convert_impl.h
new file mode 100644
index 0000000..d684f92
--- /dev/null
+++ b/composer/gl_color_convert_impl.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GL_COLOR_CONVERT_IMPL_H__
+#define __GL_COLOR_CONVERT_IMPL_H__
+
+#include <sync/sync.h>
+
+#include "gl_color_convert.h"
+#include "gl_common.h"
+
+namespace sdm {
+
+class GLColorConvertImpl : public GLColorConvert, public GLCommon {
+ public:
+  GLColorConvertImpl(GLRenderTarget target, bool secure);
+  virtual ~GLColorConvertImpl();
+  virtual int Blit(const private_handle_t *src_hnd, const private_handle_t *dst_hnd,
+                   const GLRect &src_rect, const GLRect &dst_rect,
+                   int src_acquire_fence_fd, int dst_acquire_fence_fd, int *release_fence_fd);
+  virtual int CreateContext(GLRenderTarget target, bool secure);
+  virtual int Init();
+  virtual int Deinit();
+ private:
+  GLRenderTarget target_ = kTargetRGBA;
+  bool secure_ = false;
+  GLContext ctx_;
+};
+
+}  // namespace sdm
+
+#endif  // __GL_COLOR_CONVERT_IMPL_H__
diff --git a/composer/gl_common.cpp b/composer/gl_common.cpp
new file mode 100644
index 0000000..d45b5d9
--- /dev/null
+++ b/composer/gl_common.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gl_common.h"
+
+#define __CLASS__ "GLCommon"
+
+namespace sdm {
+
+GLuint GLCommon::LoadProgram(int vertex_entries, const char **vertex, int fragment_entries,
+                           const char **fragment) {
+  GLuint prog_id = glCreateProgram();
+
+  int vert_id = glCreateShader(GL_VERTEX_SHADER);
+  int frag_id = glCreateShader(GL_FRAGMENT_SHADER);
+
+  GL(glShaderSource(vert_id, vertex_entries, vertex, 0));
+  GL(glCompileShader(vert_id));
+  DumpShaderLog(vert_id);
+
+  GL(glShaderSource(frag_id, fragment_entries, fragment, 0));
+  GL(glCompileShader(frag_id));
+  DumpShaderLog(frag_id);
+
+  GL(glAttachShader(prog_id, vert_id));
+  GL(glAttachShader(prog_id, frag_id));
+
+  GL(glLinkProgram(prog_id));
+
+  GL(glDetachShader(prog_id, vert_id));
+  GL(glDetachShader(prog_id, frag_id));
+
+  GL(glDeleteShader(vert_id));
+  GL(glDeleteShader(frag_id));
+
+  return prog_id;
+}
+
+void GLCommon::DumpShaderLog(int shader) {
+  int success = 0;
+  GLchar infoLog[512];
+  GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success));
+  if (!success) {
+    glGetShaderInfoLog(shader, 512, NULL, infoLog);
+    DLOGI("Shader Failed to compile: %s\n", infoLog);
+  }
+}
+
+void GLCommon::MakeCurrent(const GLContext* ctx) {
+  DTRACE_SCOPED();
+  EGL(eglMakeCurrent(ctx->egl_display, ctx->egl_surface, ctx->egl_surface, ctx->egl_context));
+}
+
+void GLCommon::SetProgram(uint32_t id) {
+  DTRACE_SCOPED();
+  GL(glUseProgram(id));
+}
+
+void GLCommon::DeleteProgram(uint32_t id) {
+  DTRACE_SCOPED();
+  GL(glDeleteProgram(id));
+}
+
+void GLCommon::SetSourceBuffer(const private_handle_t *src_hnd) {
+  DTRACE_SCOPED();
+  EGLImageBuffer *src_buffer = image_wrapper_.wrap(reinterpret_cast<const void *>(src_hnd));
+
+  GL(glActiveTexture(GL_TEXTURE0));
+  if (src_buffer) {
+    GL(glBindTexture(GL_TEXTURE_2D, src_buffer->getTexture(GL_TEXTURE_2D)));
+  }
+}
+
+void GLCommon::SetDestinationBuffer(const private_handle_t *dst_hnd) {
+  DTRACE_SCOPED();
+  EGLImageBuffer *dst_buffer = image_wrapper_.wrap(reinterpret_cast<const void *>(dst_hnd));
+
+  if (dst_buffer) {
+    GL(glBindFramebuffer(GL_FRAMEBUFFER, dst_buffer->getFramebuffer()));
+    GL(glViewport(0, 0, dst_buffer->getWidth(), dst_buffer->getHeight()));
+  }
+}
+
+int GLCommon::WaitOnInputFence(const int in_fence_fd) {
+  DTRACE_SCOPED();
+  EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, in_fence_fd, EGL_NONE};
+  EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                     attribs);
+
+  if (sync == EGL_NO_SYNC_KHR) {
+    DLOGE("Failed to create sync from source fd: %d", in_fence_fd);
+    return -1;
+  } else {
+    EGL(eglWaitSyncKHR(eglGetCurrentDisplay(), sync, 0));
+    EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));
+  }
+
+  return 0;
+}
+
+int GLCommon::CreateOutputFence() {
+  DTRACE_SCOPED();
+  int fd = -1;
+  EGLSyncKHR sync = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+
+  // Swap buffer.
+  GL(glFlush());
+
+  if (sync == EGL_NO_SYNC_KHR) {
+    DLOGE("Failed to create egl sync fence");
+  } else {
+    fd = eglDupNativeFenceFDANDROID(eglGetCurrentDisplay(), sync);
+    if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+      DLOGE("Failed to dup sync");
+    }
+    EGL(eglDestroySyncKHR(eglGetCurrentDisplay(), sync));
+  }
+
+  return fd;
+}
+
+void GLCommon::DestroyContext(const GLContext* ctx) {
+  DTRACE_SCOPED();
+  EGL(eglMakeCurrent(ctx->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+  EGL(eglDestroySurface(ctx->egl_display, ctx->egl_surface));
+  EGL(eglDestroyContext(ctx->egl_display, ctx->egl_context));
+  EGL(DeleteProgram(ctx->program_id));
+  EGL(eglTerminate(ctx->egl_display));
+}
+
+}  // namespace sdm
+
diff --git a/composer/gl_common.h b/composer/gl_common.h
new file mode 100644
index 0000000..4089e87
--- /dev/null
+++ b/composer/gl_common.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GL_COMMON_H__
+#define __GL_COMMON_H__
+
+#include <utils/debug.h>
+
+#include "glengine.h"
+#include "EGLImageWrapper.h"
+
+namespace sdm {
+
+struct GLContext {
+  EGLDisplay egl_display = EGL_NO_DISPLAY;
+  EGLContext egl_context = EGL_NO_CONTEXT;
+  EGLSurface egl_surface = EGL_NO_SURFACE;
+  uint32_t program_id = 0;
+};
+
+class GLCommon {
+ public:
+  virtual GLuint LoadProgram(int vertex_entries, const char **vertex, int fragment_entries,
+                             const char **fragment);
+  virtual void DumpShaderLog(int shader);
+  virtual void MakeCurrent(const GLContext *ctx);
+  virtual void SetProgram(uint32_t id);
+  virtual void SetDestinationBuffer(const private_handle_t *dst_hnd);
+  virtual void SetSourceBuffer(const private_handle_t *src_hnd);
+  virtual void DestroyContext(const GLContext *ctx);
+  virtual void DeleteProgram(uint32_t id);
+  virtual int WaitOnInputFence(const int in_fence_fd);
+  virtual int CreateOutputFence();
+
+ protected:
+  virtual ~GLCommon() { }
+
+ private:
+  EGLImageWrapper image_wrapper_;
+};
+
+}  // namespace sdm
+
+#endif  // __GL_COMMON_H__
diff --git a/composer/hwc_display.h b/composer/hwc_display.h
index 8fea114..bca6f5a 100644
--- a/composer/hwc_display.h
+++ b/composer/hwc_display.h
@@ -458,6 +458,7 @@
   std::vector<uint32_t> hwc_config_map_;
   bool client_connected_ = true;
   bool pending_config_ = false;
+  bool has_client_composition_ = false;
 
  private:
   void DumpInputBuffers(void);
@@ -470,7 +471,6 @@
   uint32_t geometry_changes_ = GeometryChanges::kNone;
   bool animating_ = false;
   int null_display_mode_ = 0;
-  bool has_client_composition_ = false;
   DisplayValidateState validate_state_ = kNormalValidate;
   bool fast_path_enabled_ = true;
   bool first_cycle_ = true;  // false if a display commit has succeeded on the device.
diff --git a/composer/hwc_display_virtual.cpp b/composer/hwc_display_virtual.cpp
index 470d7d2..b2eedc3 100644
--- a/composer/hwc_display_virtual.cpp
+++ b/composer/hwc_display_virtual.cpp
@@ -39,142 +39,45 @@
 
 namespace sdm {
 
-int HWCDisplayVirtual::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                              HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id,
-                              uint32_t width, uint32_t height, int32_t *format,
-                              HWCDisplay **hwc_display, float min_lum, float max_lum) {
-  int status = 0;
-  HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, buffer_allocator,
-                                                                 callbacks, id, sdm_id);
-
-  // TODO(user): Populate format correctly
-  DLOGI("Creating virtual display: w: %d h:%d format:0x%x", width, height, *format);
-
-  status = hwc_display_virtual->Init();
-  if (status) {
-    DLOGW("Failed to initialize virtual display");
-    delete hwc_display_virtual;
-    return status;
-  }
-
-  if (max_lum != -1.0 || min_lum != -1.0) {
-    hwc_display_virtual->SetPanelLuminanceAttributes(min_lum, max_lum);
-  }
-
-  status = hwc_display_virtual->SetConfig(width, height);
-  if (status) {
-    Destroy(hwc_display_virtual);
-    return status;
-  }
-
-  status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On, false /* teardown */));
-  if (status) {
-    DLOGW("Failed to set power mode on virtual display");
-    Destroy(hwc_display_virtual);
-    return status;
-  }
-
-  // TODO(user): Validate that we support this width/height
-  status = hwc_display_virtual->SetFrameBufferResolution(width, height);
-
-  if (status) {
-    DLOGW("Failed to set virtual display FB resolution");
-    Destroy(hwc_display_virtual);
-    return status;
-  }
-
-  *hwc_display = static_cast<HWCDisplay *>(hwc_display_virtual);
-
-  return 0;
-}
-
 void HWCDisplayVirtual::Destroy(HWCDisplay *hwc_display) {
   hwc_display->Deinit();
   delete hwc_display;
 }
 
 HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                                     HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id) :
+                                     HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id,
+                                     uint32_t width, uint32_t height) :
       HWCDisplay(core_intf, buffer_allocator, callbacks, nullptr, nullptr, kVirtual, id, sdm_id,
-                 DISPLAY_CLASS_VIRTUAL) {
+                 DISPLAY_CLASS_VIRTUAL), width_(width), height_(height)  {
 }
 
 int HWCDisplayVirtual::Init() {
-  output_buffer_ = new LayerBuffer();
   flush_on_error_ = true;
-  return HWCDisplay::Init();
+  return 0;
 }
 
 int HWCDisplayVirtual::Deinit() {
-  int status = 0;
-  if (output_buffer_) {
-    if (output_buffer_->acquire_fence_fd >= 0) {
-      close(output_buffer_->acquire_fence_fd);
-    }
-    delete output_buffer_;
-    output_buffer_ = nullptr;
+  if (output_buffer_.acquire_fence_fd >= 0) {
+    close(output_buffer_.acquire_fence_fd);
   }
-  status = HWCDisplay::Deinit();
 
-  return status;
+  return HWCDisplay::Deinit();
 }
 
-HWC2::Error HWCDisplayVirtual::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
-  auto status = HWC2::Error::None;
-
-  if (display_paused_ || active_secure_sessions_.any()) {
-    MarkLayersForGPUBypass();
-    return status;
-  }
-
-  BuildLayerStack();
-  layer_stack_.output_buffer = output_buffer_;
-  // If Output buffer of Virtual Display is not secure, set SKIP flag on the secure layers.
-  if (output_buffer_ && !output_buffer_->flags.secure && layer_stack_.flags.secure_present) {
-    for (auto hwc_layer : layer_set_) {
-      Layer *layer = hwc_layer->GetSDMLayer();
-      if (layer->input_buffer.flags.secure) {
-        layer_stack_.flags.skip_present = true;
-        layer->flags.skip = true;
-      }
-    }
-  }
-
-  if (layer_set_.empty()) {
-    DLOGI("Skipping Validate and Commit");
-    return status;
-  }
-  status = PrepareLayerStack(out_num_types, out_num_requests);
-  return status;
+bool HWCDisplayVirtual::NeedsGPUBypass() {
+  return display_paused_ || active_secure_sessions_.any() || layer_set_.empty();
 }
 
 HWC2::Error HWCDisplayVirtual::Present(int32_t *out_retire_fence) {
-  auto status = HWC2::Error::None;
+  return HWC2::Error::None;
+}
 
-  if (!output_buffer_->buffer_id) {
-    return HWC2::Error::NoResources;
-  }
-
-  if (active_secure_sessions_.any()) {
-    return status;
-  }
-
-  layer_stack_.output_buffer = output_buffer_;
-  if (display_paused_) {
-    validated_ = false;
-    flush_ = true;
-  }
-
-  status = HWCDisplay::CommitLayerStack();
-  if (status != HWC2::Error::None) {
-    return status;
-  }
-
+HWC2::Error HWCDisplayVirtual::DumpVDSBuffer() {
   if (dump_frame_count_ && !flush_ && dump_output_layer_) {
     if (output_handle_) {
       BufferInfo buffer_info;
       const private_handle_t *output_handle =
-        reinterpret_cast<const private_handle_t *>(output_buffer_->buffer_id);
+        reinterpret_cast<const private_handle_t *>(output_buffer_.buffer_id);
       DisplayError error = kErrorNone;
       if (!output_handle->base) {
         error = buffer_allocator_->MapBuffer(output_handle, -1);
@@ -200,30 +103,6 @@
     }
   }
 
-  status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
-
-  return status;
-}
-
-int HWCDisplayVirtual::SetConfig(uint32_t width, uint32_t height) {
-  DisplayConfigVariableInfo variable_info;
-  variable_info.x_pixels = width;
-  variable_info.y_pixels = height;
-  // TODO(user): Need to get the framerate of primary display and update it.
-  variable_info.fps = 60;
-  DisplayError err = display_intf_->SetActiveConfig(&variable_info);
-  if (err != kErrorNone) {
-    return -EINVAL;
-  }
-  return 0;
-}
-
-
-HWC2::Error HWCDisplayVirtual::SetPanelLuminanceAttributes(float min_lum, float max_lum) {
-  DisplayError err = display_intf_->SetPanelLuminanceAttributes(min_lum, max_lum);
-  if (err != kErrorNone) {
-    return HWC2::Error::BadParameter;
-  }
   return HWC2::Error::None;
 }
 
@@ -235,10 +114,7 @@
 
   if (output_handle) {
     int output_handle_format = output_handle->format;
-    int active_aligned_w, active_aligned_h;
-    int new_width, new_height;
-    int new_aligned_w, new_aligned_h;
-    uint32_t active_width, active_height;
+    int aligned_w, aligned_h;
     ColorMetaData color_metadata = {};
 
     if (output_handle_format == HAL_PIXEL_FORMAT_RGBA_8888) {
@@ -255,54 +131,38 @@
       return HWC2::Error::BadParameter;
     }
 
-    GetMixerResolution(&active_width, &active_height);
-    buffer_allocator_->GetCustomWidthAndHeight(output_handle, &new_width, &new_height);
-    buffer_allocator_->GetAlignedWidthAndHeight(INT(new_width), INT(new_height),
-                                                output_handle_format, 0, &new_aligned_w,
-                                                &new_aligned_h);
-    buffer_allocator_->GetAlignedWidthAndHeight(INT(active_width), INT(active_height),
-                                                output_handle_format, 0, &active_aligned_w,
-                                                &active_aligned_h);
-    if (new_aligned_w != active_aligned_w  || new_aligned_h != active_aligned_h) {
-      int status = SetConfig(UINT32(new_width), UINT32(new_height));
-      if (status) {
-        DLOGE("SetConfig failed custom WxH %dx%d", new_width, new_height);
-        return HWC2::Error::BadParameter;
-      }
-      validated_ = false;
-    }
-
-    output_buffer_->width = UINT32(new_aligned_w);
-    output_buffer_->height = UINT32(new_aligned_h);
-    output_buffer_->unaligned_width = UINT32(new_width);
-    output_buffer_->unaligned_height = UINT32(new_height);
-    output_buffer_->flags.secure = 0;
-    output_buffer_->flags.video = 0;
-    output_buffer_->buffer_id = reinterpret_cast<uint64_t>(output_handle);
-    output_buffer_->format = new_sdm_format;
-    output_buffer_->color_metadata = color_metadata;
+    buffer_allocator_->GetCustomWidthAndHeight(output_handle, &aligned_w, &aligned_h);
+    output_buffer_.width = UINT32(width_);
+    output_buffer_.height = UINT32(height_);
+    output_buffer_.unaligned_width = UINT32(aligned_w);
+    output_buffer_.unaligned_height = UINT32(aligned_h);
+    output_buffer_.flags.secure = 0;
+    output_buffer_.flags.video = 0;
+    output_buffer_.buffer_id = reinterpret_cast<uint64_t>(output_handle);
+    output_buffer_.format = new_sdm_format;
+    output_buffer_.color_metadata = color_metadata;
     output_handle_ = output_handle;
 
     // TZ Protected Buffer - L1
     if (output_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
-      output_buffer_->flags.secure = 1;
+      output_buffer_.flags.secure = 1;
     }
 
     // ToDo: Need to extend for non-RGB formats
-    output_buffer_->planes[0].fd = output_handle->fd;
-    output_buffer_->planes[0].offset = output_handle->offset;
-    output_buffer_->planes[0].stride = UINT32(output_handle->width);
+    output_buffer_.planes[0].fd = output_handle->fd;
+    output_buffer_.planes[0].offset = output_handle->offset;
+    output_buffer_.planes[0].stride = UINT32(output_handle->width);
   }
 
   // Close the previous acquire fence and update with the latest release fence to avoid fence leak
   // in case if this function gets invoked multiple times from the client.
-  if (output_buffer_->acquire_fence_fd >= 0) {
-    close(output_buffer_->acquire_fence_fd);
+  if (output_buffer_.acquire_fence_fd >= 0) {
+    close(output_buffer_.acquire_fence_fd);
   }
   // Fill output buffer parameters (width, height, format, plane information, fence)
   // release_fence will be closed by QtiComposerClient::CommandReader::parseSetOutputBuffer() if
   // this::SetOutputBuffer() fails.
-  output_buffer_->acquire_fence_fd = release_fence;
+  output_buffer_.acquire_fence_fd = release_fence;
 
   return HWC2::Error::None;
 }
diff --git a/composer/hwc_display_virtual.h b/composer/hwc_display_virtual.h
index 010c805..e699146 100644
--- a/composer/hwc_display_virtual.h
+++ b/composer/hwc_display_virtual.h
@@ -39,30 +39,29 @@
 
 class HWCDisplayVirtual : public HWCDisplay {
  public:
-  static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id, uint32_t width,
-                    uint32_t height, int32_t *format, HWCDisplay **hwc_display, float min_lum,
-                    float max_lum);
   static void Destroy(HWCDisplay *hwc_display);
   virtual int Init();
   virtual int Deinit();
-  virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
   virtual HWC2::Error SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type,
                                          int32_t format, bool post_processed);
   virtual HWC2::Error GetDisplayType(int32_t *out_type);
-  virtual HWC2::Error SetPanelLuminanceAttributes(float min_lum, float max_lum);
   virtual HWC2::Error SetColorMode(ColorMode mode);
-  HWC2::Error SetOutputBuffer(buffer_handle_t buf, int32_t release_fence);
+  virtual HWC2::Error SetOutputBuffer(buffer_handle_t buf, int32_t release_fence);
+  virtual HWC2::Error DumpVDSBuffer();
+  bool NeedsGPUBypass();
+  HWCDisplayVirtual(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+                    HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id,
+                    uint32_t width, uint32_t height);
+
+ protected:
+  uint32_t width_ = 0;
+  uint32_t height_ = 0;
+  LayerBuffer output_buffer_ = {};
+  const private_handle_t *output_handle_ = nullptr;
 
  private:
-  HWCDisplayVirtual(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
-                    HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id);
-  int SetConfig(uint32_t width, uint32_t height);
-
   bool dump_output_layer_ = false;
-  LayerBuffer *output_buffer_ = NULL;
-  const private_handle_t *output_handle_ = nullptr;
 };
 
 }  // namespace sdm
diff --git a/composer/hwc_display_virtual_dpu.cpp b/composer/hwc_display_virtual_dpu.cpp
new file mode 100644
index 0000000..451b132
--- /dev/null
+++ b/composer/hwc_display_virtual_dpu.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <hwc_display_virtual_dpu.h>
+
+#define __CLASS__ "HWCDisplayVirtualDPU"
+
+namespace sdm {
+
+HWCDisplayVirtualDPU::HWCDisplayVirtualDPU(CoreInterface *core_intf, HWCBufferAllocator
+                                           *buffer_allocator, HWCCallbacks *callbacks,
+                                           hwc2_display_t id, int32_t sdm_id, uint32_t width,
+                                           uint32_t height, float min_lum, float max_lum)
+  : HWCDisplayVirtual(core_intf, buffer_allocator, callbacks, id, sdm_id, width, height),
+    min_lum_(min_lum), max_lum_(max_lum) {
+}
+
+int HWCDisplayVirtualDPU::Init() {
+  int status = HWCDisplay::Init();
+  if (status) {
+    DLOGE("Init failed: %d", status);
+    return status;
+  }
+
+  if (max_lum_ != -1.0 || min_lum_ != -1.0) {
+    SetPanelLuminanceAttributes(min_lum_, max_lum_);
+  }
+
+  status = SetConfig(width_, height_);
+  if (status) {
+    DLOGE("Failed to set width: %d height: %d", width_, height_);
+    return status;
+  }
+
+  status = INT32(SetPowerMode(HWC2::PowerMode::On, false /* teardown */));
+  if (status) {
+    DLOGW("Failed to set power mode on virtual display");
+    return status;
+  }
+
+  // TODO(user): Validate that we support this width/height
+  status = SetFrameBufferResolution(width_, height_);
+  if (status) {
+    DLOGW("Failed to set FrameBuffer resolution on virtual display");
+    return status;
+  }
+
+  return HWCDisplayVirtual::Init();
+}
+
+int HWCDisplayVirtualDPU::SetConfig(uint32_t width, uint32_t height) {
+  DisplayConfigVariableInfo variable_info;
+  variable_info.x_pixels = width;
+  variable_info.y_pixels = height;
+  // TODO(user): Need to get the framerate of primary display and update it.
+  variable_info.fps = 60;
+
+  DisplayError err = display_intf_->SetActiveConfig(&variable_info);
+  if (err != kErrorNone) {
+    return -EINVAL;
+  }
+  return 0;
+}
+
+HWC2::Error HWCDisplayVirtualDPU::SetOutputBuffer(buffer_handle_t buf, int32_t release_fence) {
+  HWC2::Error error = HWCDisplayVirtual::SetOutputBuffer(buf, release_fence);
+  if (error != HWC2::Error::None) {
+    return error;
+  }
+
+  const private_handle_t *output_handle = static_cast<const private_handle_t *>(buf);
+  if (output_handle) {
+    int output_handle_format = output_handle->format;
+    int active_aligned_w, active_aligned_h;
+    int new_width, new_height;
+    int new_aligned_w, new_aligned_h;
+    uint32_t active_width, active_height;
+
+    GetMixerResolution(&active_width, &active_height);
+    buffer_allocator_->GetCustomWidthAndHeight(output_handle, &new_width, &new_height);
+    buffer_allocator_->GetAlignedWidthAndHeight(INT(new_width), INT(new_height),
+                                                output_handle_format, 0, &new_aligned_w,
+                                                &new_aligned_h);
+    buffer_allocator_->GetAlignedWidthAndHeight(INT(active_width), INT(active_height),
+                                                output_handle_format, 0, &active_aligned_w,
+                                                &active_aligned_h);
+    if (new_aligned_w != active_aligned_w  || new_aligned_h != active_aligned_h) {
+      int status = SetConfig(UINT32(new_width), UINT32(new_height));
+      if (status) {
+        DLOGE("SetConfig failed custom WxH %dx%d", new_width, new_height);
+        return HWC2::Error::BadParameter;
+      }
+      validated_ = false;
+    }
+
+    output_buffer_.width = UINT32(new_aligned_w);
+    output_buffer_.height = UINT32(new_aligned_h);
+    output_buffer_.unaligned_width = UINT32(new_width);
+    output_buffer_.unaligned_height = UINT32(new_height);
+  }
+
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCDisplayVirtualDPU::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
+  if (NeedsGPUBypass()) {
+    MarkLayersForGPUBypass();
+    return HWC2::Error::None;
+  }
+
+  BuildLayerStack();
+  layer_stack_.output_buffer = &output_buffer_;
+  // If Output buffer of Virtual Display is not secure, set SKIP flag on the secure layers.
+  if (!output_buffer_.flags.secure && layer_stack_.flags.secure_present) {
+    for (auto hwc_layer : layer_set_) {
+      Layer *layer = hwc_layer->GetSDMLayer();
+      if (layer->input_buffer.flags.secure) {
+        layer_stack_.flags.skip_present = true;
+        layer->flags.skip = true;
+      }
+    }
+  }
+
+  return PrepareLayerStack(out_num_types, out_num_requests);
+}
+
+HWC2::Error HWCDisplayVirtualDPU::Present(int32_t *out_retire_fence) {
+  auto status = HWC2::Error::None;
+
+  if (!output_buffer_.buffer_id) {
+    return HWC2::Error::NoResources;
+  }
+
+  if (active_secure_sessions_.any()) {
+    return status;
+  }
+
+  layer_stack_.output_buffer = &output_buffer_;
+  if (display_paused_) {
+    validated_ = false;
+    flush_ = true;
+  }
+
+  status = HWCDisplay::CommitLayerStack();
+  if (status != HWC2::Error::None) {
+    return status;
+  }
+
+  DumpVDSBuffer();
+
+  status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
+
+  return status;
+}
+
+HWC2::Error HWCDisplayVirtualDPU::SetPanelLuminanceAttributes(float min_lum, float max_lum) {
+  DisplayError err = display_intf_->SetPanelLuminanceAttributes(min_lum, max_lum);
+  if (err != kErrorNone) {
+    return HWC2::Error::BadParameter;
+  }
+  return HWC2::Error::None;
+}
+
+}  // namespace sdm
+
diff --git a/composer/hwc_display_virtual_dpu.h b/composer/hwc_display_virtual_dpu.h
new file mode 100644
index 0000000..e74bc9d
--- /dev/null
+++ b/composer/hwc_display_virtual_dpu.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HWC_DISPLAY_VIRTUAL_DPU_H__
+#define __HWC_DISPLAY_VIRTUAL_DPU_H__
+
+#include "hwc_display_virtual.h"
+
+namespace sdm {
+
+class HWCDisplayVirtualDPU : public HWCDisplayVirtual {
+ public:
+  HWCDisplayVirtualDPU(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+                       HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id,
+                       uint32_t width, uint32_t height, float min_lum, float max_lum);
+  virtual int Init();
+  virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
+  virtual HWC2::Error Present(int32_t *out_retire_fence);
+  virtual HWC2::Error SetOutputBuffer(buffer_handle_t buf, int32_t release_fence);
+  virtual HWC2::Error SetPanelLuminanceAttributes(float min_lum, float max_lum);
+
+ private:
+  int SetConfig(uint32_t width, uint32_t height);
+
+  float min_lum_ = 0.0f;
+  float max_lum_ = 0.0f;
+};
+
+}  // namespace sdm
+
+#endif  // __HWC_DISPLAY_VIRTUAL_DPU_H__
diff --git a/composer/hwc_display_virtual_factory.cpp b/composer/hwc_display_virtual_factory.cpp
new file mode 100644
index 0000000..8767d14
--- /dev/null
+++ b/composer/hwc_display_virtual_factory.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hwc_display_virtual_factory.h"
+#include "hwc_display_virtual_dpu.h"
+#include "hwc_display_virtual_gpu.h"
+
+#define __CLASS__ "HWCVirtualDisplayFactory"
+
+namespace sdm {
+
+int HWCVirtualDisplayFactory::Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+                              HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id,
+                              uint32_t width, uint32_t height, int32_t *format,
+                              float min_lum, float max_lum, HWCDisplay **hwc_display) {
+  int supported_virtual_displays = 0;
+  DisplayError error = core_intf->GetMaxDisplaysSupported(kVirtual, &supported_virtual_displays);
+  if (error != kErrorNone) {
+    DLOGE("Could not find maximum virtual displays supported. Error = %d", error);
+    return -1;
+  }
+
+  HWCDisplayVirtual *hwc_display_virtual = nullptr;
+  if (supported_virtual_displays) {
+    hwc_display_virtual = new HWCDisplayVirtualDPU(core_intf, buffer_allocator, callbacks, id,
+                                                   sdm_id, width, height, min_lum, max_lum);
+  } else {
+    // Create GPU based virtual display.
+    hwc_display_virtual = new HWCDisplayVirtualGPU(core_intf, buffer_allocator, callbacks, id,
+                                                   sdm_id, width, height, min_lum, max_lum);
+  }
+
+  if (hwc_display_virtual == nullptr) {
+    DLOGE("Failed to create instance");
+    return -1;
+  } else {
+    DLOGI("Created %s based virtual display", (supported_virtual_displays ? "DPU" : "GPU"));
+  }
+
+  int status = hwc_display_virtual->Init();
+  if (status) {
+    DLOGW("Failed to initialize virtual display");
+    Destroy(hwc_display_virtual);
+    return status;
+  }
+
+  // TODO(user): Populate format correctly
+  DLOGI("Creating virtual display: w: %d h:%d format:0x%x", width, height, *format);
+
+  *hwc_display = hwc_display_virtual;
+
+  return status;
+}
+
+bool HWCVirtualDisplayFactory::IsGPUColorConvertSupported() {
+  int value = 0;
+  HWCDebugHandler::Get()->GetProperty(DISABLE_GPU_COLOR_CONVERT, &value);
+  return (value == 0);
+}
+
+void HWCVirtualDisplayFactory::Destroy(HWCDisplay *hwc_display) {
+  DLOGI("Destroying virtual display instance");
+  if (hwc_display->Deinit() != 0) {
+    DLOGE("Failed to destroy instance");
+  }
+
+  delete hwc_display;
+}
+
+}  // namespace sdm
diff --git a/composer/hwc_display_virtual_factory.h b/composer/hwc_display_virtual_factory.h
new file mode 100644
index 0000000..38f6a80
--- /dev/null
+++ b/composer/hwc_display_virtual_factory.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __HWC_DISPLAY_VIRTUAL_FACTORY_H__
+#define __HWC_DISPLAY_VIRTUAL_FACTORY_H__
+
+#include <core/core_interface.h>
+
+#include "hwc_callbacks.h"
+#include "hwc_debugger.h"
+#include "hwc_display.h"
+#include "hwc_buffer_allocator.h"
+
+namespace sdm {
+
+class HWCVirtualDisplayFactory {
+ public:
+  int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+             HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id, uint32_t width,
+             uint32_t height, int32_t *format, float min_lum, float max_lum,
+             HWCDisplay **hwc_display);
+  void Destroy(HWCDisplay *hwc_display);
+  bool IsGPUColorConvertSupported();
+};
+
+}  // namespace sdm
+
+#endif  // __HWC_DISPLAY_VIRTUAL_FACTORY_H__
diff --git a/composer/hwc_display_virtual_gpu.cpp b/composer/hwc_display_virtual_gpu.cpp
new file mode 100644
index 0000000..5845e78
--- /dev/null
+++ b/composer/hwc_display_virtual_gpu.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hwc_display_virtual_gpu.h"
+#include "hwc_session.h"
+
+#define __CLASS__ "HWCDisplayVirtualGPU"
+
+namespace sdm {
+
+int HWCDisplayVirtualGPU::Init() {
+  // Create client target.
+  client_target_ = new HWCLayer(id_, buffer_allocator_);
+
+  // Calls into SDM need to be dropped. Create Null Display interface.
+  display_intf_ = new DisplayNull();
+
+  return HWCDisplayVirtual::Init();
+}
+
+int HWCDisplayVirtualGPU::Deinit() {
+  // Destory color convert instance. This destroys thread and underlying GL resources.
+  if (gl_color_convert_) {
+    color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeDestroyInstance, nullptr);
+  }
+
+  delete static_cast<DisplayNull *>(display_intf_);
+  delete client_target_;
+
+  for (auto hwc_layer : layer_set_) {
+    delete hwc_layer;
+  }
+
+  return 0;
+}
+
+HWCDisplayVirtualGPU::HWCDisplayVirtualGPU(CoreInterface *core_intf, HWCBufferAllocator
+                                           *buffer_allocator, HWCCallbacks *callbacks,
+                                           hwc2_display_t id, int32_t sdm_id, uint32_t width,
+                                           uint32_t height, float min_lum, float max_lum) :
+  HWCDisplayVirtual(core_intf, buffer_allocator, callbacks, id, sdm_id, width, height),
+  color_convert_task_(*this) {
+}
+
+HWC2::Error HWCDisplayVirtualGPU::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
+  DTRACE_SCOPED();
+
+  // Mark all layers to GPU if there is no need to bypass.
+  bool needs_gpu_bypass = NeedsGPUBypass();
+  for (auto hwc_layer : layer_set_) {
+    auto layer = hwc_layer->GetSDMLayer();
+    layer->composition = needs_gpu_bypass ? kCompositionSDE : kCompositionGPU;
+
+    if (needs_gpu_bypass) {
+      if (hwc_layer->GetClientRequestedCompositionType() == HWC2::Composition::Client) {
+       layer_changes_[hwc_layer->GetId()] = HWC2::Composition::Device;
+       layer_requests_[hwc_layer->GetId()] = HWC2::LayerRequest::ClearClientTarget;
+      }
+    } else {
+      if (hwc_layer->GetClientRequestedCompositionType() != HWC2::Composition::Client) {
+       layer_changes_[hwc_layer->GetId()] = HWC2::Composition::Client;
+      }
+    }
+  }
+
+  // Derive client target dataspace based on the color mode - bug/115482728
+  int32_t client_target_dataspace = GetDataspaceFromColorMode(GetCurrentColorMode());
+  SetClientTargetDataSpace(client_target_dataspace);
+
+  *out_num_types = UINT32(layer_changes_.size());
+  *out_num_requests = UINT32(layer_requests_.size());;
+  has_client_composition_ = !needs_gpu_bypass;
+  client_target_->ResetValidation();
+
+  validated_ = true;
+
+  return ((*out_num_types > 0) ? HWC2::Error::HasChanges : HWC2::Error::None);
+}
+
+HWC2::Error HWCDisplayVirtualGPU::Present(int32_t *out_retire_fence) {
+  DTRACE_SCOPED();
+
+  auto status = HWC2::Error::None;
+
+  if (!validated_) {
+    return HWC2::Error::NotValidated;
+  }
+
+  if (!output_buffer_.buffer_id) {
+    return HWC2::Error::NoResources;
+  }
+
+  if (active_secure_sessions_.any() || layer_set_.empty()) {
+    return status;
+  }
+
+  layer_stack_.output_buffer = &output_buffer_;
+  if (display_paused_) {
+    validated_ = false;
+  }
+
+  // Ensure that blit is initialized.
+  // GPU context gets in secure or non-secure mode depending on output buffer provided.
+  if (!gl_color_convert_) {
+    // Get instance.
+    color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeGetInstance, nullptr);
+    if (gl_color_convert_ == nullptr) {
+      DLOGE("Failed to get Color Convert Instance");
+      return HWC2::Error::NoResources;
+    } else {
+      DLOGI("Created ColorConvert instance: %p", gl_color_convert_);
+    }
+  }
+
+  ColorConvertBlitContext ctx = {};
+
+  Layer *sdm_layer = client_target_->GetSDMLayer();
+  LayerBuffer &input_buffer = sdm_layer->input_buffer;
+  ctx.src_hnd = reinterpret_cast<const private_handle_t *>(input_buffer.buffer_id);
+  ctx.dst_hnd = reinterpret_cast<const private_handle_t *>(output_handle_);
+  ctx.dst_rect = {0, 0, FLOAT(output_buffer_.width), FLOAT(output_buffer_.height)};
+  ctx.src_acquire_fence_fd = input_buffer.acquire_fence_fd;
+  ctx.dst_acquire_fence_fd = output_buffer_.acquire_fence_fd;
+  ctx.release_fence_fd = -1;
+
+  color_convert_task_.PerformTask(ColorConvertTaskCode::kCodeBlit, &ctx);
+
+  // todo blit
+  DumpVDSBuffer();
+
+  *out_retire_fence = ctx.release_fence_fd;
+
+  return status;
+}
+
+void HWCDisplayVirtualGPU::OnTask(const ColorConvertTaskCode &task_code,
+                                  SyncTask<ColorConvertTaskCode>::TaskContext *task_context) {
+  switch (task_code) {
+    case ColorConvertTaskCode::kCodeGetInstance: {
+        gl_color_convert_ = GLColorConvert::GetInstance(kTargetYUV, output_buffer_.flags.secure);
+      }
+      break;
+    case ColorConvertTaskCode::kCodeBlit: {
+        DTRACE_SCOPED();
+        ColorConvertBlitContext* ctx = reinterpret_cast<ColorConvertBlitContext*>(task_context);
+        gl_color_convert_->Blit(ctx->src_hnd, ctx->dst_hnd, ctx->src_rect, ctx->dst_rect,
+                                ctx->src_acquire_fence_fd, ctx->dst_acquire_fence_fd,
+                                &(ctx->release_fence_fd));
+      }
+      break;
+    case ColorConvertTaskCode::kCodeDestroyInstance: {
+        if (gl_color_convert_) {
+          GLColorConvert::Destroy(gl_color_convert_);
+        }
+      }
+      break;
+  }
+}
+
+}  // namespace sdm
+
diff --git a/composer/hwc_display_virtual_gpu.h b/composer/hwc_display_virtual_gpu.h
new file mode 100644
index 0000000..3c85cd2
--- /dev/null
+++ b/composer/hwc_display_virtual_gpu.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HWC_DISPLAY_VIRTUAL_GPU_H__
+#define __HWC_DISPLAY_VIRTUAL_GPU_H__
+
+#include "utils/sync_task.h"
+#include "hwc_display_virtual.h"
+#include "gl_color_convert.h"
+
+namespace sdm {
+
+enum class ColorConvertTaskCode : int32_t {
+  kCodeGetInstance,
+  kCodeBlit,
+  kCodeDestroyInstance,
+};
+
+struct ColorConvertGetInstanceContext : public SyncTask<ColorConvertTaskCode>::TaskContext {
+  LayerBuffer *output_buffer = NULL;
+};
+
+struct ColorConvertBlitContext : public SyncTask<ColorConvertTaskCode>::TaskContext {
+  const private_handle_t* src_hnd = nullptr;
+  const private_handle_t* dst_hnd = nullptr;
+  GLRect src_rect = {};
+  GLRect dst_rect = {};
+  int src_acquire_fence_fd = -1;
+  int dst_acquire_fence_fd = -1;
+  int release_fence_fd = -1;
+};
+
+class HWCDisplayVirtualGPU : public HWCDisplayVirtual,
+                             public SyncTask<ColorConvertTaskCode>::TaskHandler {
+ public:
+  HWCDisplayVirtualGPU(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+                       HWCCallbacks *callbacks, hwc2_display_t id, int32_t sdm_id,
+                       uint32_t width, uint32_t height, float min_lum, float max_lum);
+  virtual int Init();
+  virtual int Deinit();
+  virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
+  virtual HWC2::Error Present(int32_t *out_retire_fence);
+
+ private:
+  // SyncTask methods.
+  void OnTask(const ColorConvertTaskCode &task_code,
+              SyncTask<ColorConvertTaskCode>::TaskContext *task_context);
+
+  SyncTask<ColorConvertTaskCode> color_convert_task_;
+  GLColorConvert *gl_color_convert_;
+};
+
+}  // namespace sdm
+
+#endif  // __HWC_DISPLAY_VIRTUAL_GPU_H__
diff --git a/composer/hwc_session.cpp b/composer/hwc_session.cpp
index d405bbc..b4dd15e 100644
--- a/composer/hwc_session.cpp
+++ b/composer/hwc_session.cpp
@@ -286,6 +286,11 @@
     return;
   }
 
+  if (max_virtual == 0) {
+    // Check if WB using GPU is supported.
+    max_virtual += virtual_display_factory_.IsGPUColorConvertSupported() ? 1 : 0;
+  }
+
   if (kPluggable == hw_disp_info.type) {
     // If primary is a pluggable display, we have already used one pluggable display interface.
     max_pluggable--;
@@ -1115,9 +1120,9 @@
           continue;
         }
 
-        status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, client_id,
-                                           info.display_id, width, height, format, &hwc_display,
-                                           set_min_lum_, set_max_lum_);
+        status = virtual_display_factory_.Create(core_intf_, &buffer_allocator_, &callbacks_,
+                                                 client_id, info.display_id, width, height,
+                                                 format, set_min_lum_, set_max_lum_, &hwc_display);
         // TODO(user): validate width and height support
         if (status) {
           return HWC2::Error::NoResources;
@@ -2703,7 +2708,7 @@
       HWCDisplayBuiltIn::Destroy(hwc_display);
       break;
     default:
-      HWCDisplayVirtual::Destroy(hwc_display);
+      virtual_display_factory_.Destroy(hwc_display);
       break;
     }
 
diff --git a/composer/hwc_session.h b/composer/hwc_session.h
index 87ebbe0..b4c9fea 100644
--- a/composer/hwc_session.h
+++ b/composer/hwc_session.h
@@ -45,6 +45,7 @@
 #include "hwc_socket_handler.h"
 #include "hwc_display_event_handler.h"
 #include "hwc_buffer_sync_handler.h"
+#include "hwc_display_virtual_factory.h"
 
 namespace sdm {
 
@@ -453,6 +454,7 @@
   HWCCallbacks callbacks_;
   HWCBufferAllocator buffer_allocator_;
   HWCBufferSyncHandler buffer_sync_handler_;
+  HWCVirtualDisplayFactory virtual_display_factory_;
   HWCColorManager *color_mgr_ = nullptr;
   DisplayMapInfo map_info_primary_;                 // Primary display (either builtin or pluggable)
   std::vector<DisplayMapInfo> map_info_builtin_;    // Builtin displays excluding primary
diff --git a/composer/hwc_session_services.cpp b/composer/hwc_session_services.cpp
index 4ff1bdf..cba4481 100644
--- a/composer/hwc_session_services.cpp
+++ b/composer/hwc_session_services.cpp
@@ -739,7 +739,7 @@
   int32_t error = -EINVAL;
 
   vendor_prop_name += prop_name.c_str();
-  if (HWCDebugHandler::Get()->GetProperty(vendor_prop_name.c_str(), value) != kErrorNone) {
+  if (HWCDebugHandler::Get()->GetProperty(vendor_prop_name.c_str(), value) == kErrorNone) {
     result = value;
     error = 0;
   }
diff --git a/gpu_tonemapper/EGLImageBuffer.cpp b/gpu_tonemapper/EGLImageBuffer.cpp
index eeb0273..92817ef 100644
--- a/gpu_tonemapper/EGLImageBuffer.cpp
+++ b/gpu_tonemapper/EGLImageBuffer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -97,11 +97,11 @@
 }
 
 //-----------------------------------------------------------------------------
-unsigned int EGLImageBuffer::getTexture()
+unsigned int EGLImageBuffer::getTexture(int target)
 //-----------------------------------------------------------------------------
 {
   if (textureID == 0) {
-    bindAsTexture();
+    bindAsTexture(target);
   }
 
   return textureID;
@@ -119,22 +119,21 @@
 }
 
 //-----------------------------------------------------------------------------
-void EGLImageBuffer::bindAsTexture()
+void EGLImageBuffer::bindAsTexture(int target)
 //-----------------------------------------------------------------------------
 {
   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(glEGLImageTargetTexture2DOES(target, eglImageID));
   }
 
-  GL(glBindTexture(0x8D65, textureID));
+  GL(glBindTexture(target, textureID));
 }
 
 //-----------------------------------------------------------------------------
diff --git a/gpu_tonemapper/EGLImageBuffer.h b/gpu_tonemapper/EGLImageBuffer.h
index 23af573..1433fdd 100644
--- a/gpu_tonemapper/EGLImageBuffer.h
+++ b/gpu_tonemapper/EGLImageBuffer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016, 2019 The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -38,13 +38,13 @@
   int getWidth();
   int getHeight();
   EGLImageBuffer(android::sp<android::GraphicBuffer>);
-  unsigned int getTexture();
+  unsigned int getTexture(int target);
   unsigned int getFramebuffer();
-  void bindAsTexture();
+  void bindAsTexture(int target);
   void bindAsFramebuffer();
   ~EGLImageBuffer();
   static EGLImageBuffer *from(const private_handle_t *src);
   static void clear();
 };
 
-#endif  //__EGLIMAGE_BUFFER_H__
\ No newline at end of file
+#endif  //__EGLIMAGE_BUFFER_H_
diff --git a/gpu_tonemapper/Tonemapper.cpp b/gpu_tonemapper/Tonemapper.cpp
index 2605c7f..aa86a3c 100644
--- a/gpu_tonemapper/Tonemapper.cpp
+++ b/gpu_tonemapper/Tonemapper.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright 2015 The Android Open Source Project
@@ -143,7 +143,7 @@
   }
   // set source
   if (src_buffer) {
-    engine_setExternalInputBuffer(0, src_buffer->getTexture());
+    engine_setExternalInputBuffer(0, src_buffer->getTexture(0x8D65 /* target texture */));
   }
   // set 3d lut
   engine_set3DInputBuffer(1, tonemapTexture);
diff --git a/include/display_properties.h b/include/display_properties.h
index 91e7696..75a4b67 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -111,6 +111,7 @@
 #define ENABLE_ASYNC_POWERMODE               DISPLAY_PROP("enable_async_powermode")
 #define ENABLE_GPU_TONEMAPPER_PROP           DISPLAY_PROP("enable_gpu_tonemapper")
 #define ENABLE_FORCE_SPLIT                   DISPLAY_PROP("enable_force_split")
+#define DISABLE_GPU_COLOR_CONVERT            DISPLAY_PROP("disable_gpu_color_convert")
 
 // Add all vendor.display properties above
 
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index e324d7b..162e3f0 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -341,6 +341,7 @@
     // will cause flicker.
     InitMaxHDRMetaData();
     in_multiset_ = true;
+    reset_hdr_flag_ = false;
     drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_);
     DumpHDRMetaData(hdr_op);
   } else if (hdr_op == HWHDRLayerInfo::kReset) {