Merge "Disable the build and transfer ownership to the janitors."
diff --git a/.gitignore b/.gitignore
index 1620cc7..606ff44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@
 /pkgconfig/*.pc
 .deps
 .libs
+.dirstamp
 
 # Object files
 *.o
diff --git a/AUTHORS b/AUTHORS
index e2fd75b..f91df7d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,11 +4,12 @@
 Wind Yuan <feng.yuan@intel.com>
 
 Contributors: (orders by first name)
+Andrey Parfenov <a1994ndrey@gmail.com>
 Fei Wang <feix.w.wang@intel.com>
 Jia Meng <jia.meng@intel.com>
 John Ye <john.ye@intel.com>
 Juan Zhao <juan.j.zhao@intel.com>
-Junkai Wu <wujunkai166@gmail.com>
+Junkai Wu <wujunkai166@gmail.com> <junkai.wu@intel.com>
 Sameer Kibey <sameer.kibey@intel.com>
 Shincy Tu <shincy.tu@intel.com>
 Wei Zong <wei.zong@intel.com>
diff --git a/COPYING b/COPYING
index 744d243..6a2f304 100644
--- a/COPYING
+++ b/COPYING
@@ -1,5 +1,5 @@
 
-   Copyright (c) 2014-2015 Intel Corporation
+   Copyright (c) 2014-2019 Intel Corporation
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
diff --git a/ChangeLog b/ChangeLog
index 7182275..e869496 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,68 @@
+2019/04/02: release libxcam version 1.2.2
+ * DNN inference framwork enabling.
+   - enable pedestrian and vehicle detection based on OpenVino
+
+ * OpenCV feature match enabled for image stitching pipeline (GLES/Vulkan/CPU)
+   - support three versions of feature match: default, cluster, capi
+
+ * Abstract OpenCV source in ocv module, and build into a separate static library
+
+2018/12/19: release libxcam version 1.2.1
+ * Vulkan surround-view stitching enabling.
+   - enable features of multi-band blender and geometry remap.
+   - enable Vulkan image stitching. (feature-match may support later)
+
+ * Surrond-view texture rendering.
+   - enable 3D surround view scene rendering and manipulation.
+
+ * require OpenSceneGraph minimal version 3.3.2
+
+2018/10/16: release libxcam version 1.2.0
+ * GLES compute framework enabling.
+   - enable GL image processing framework.
+   - enable features of multi-band blender, geometry remap and data-copy.
+
+ * GLES surround-view stitching enabling.
+   - GLES stitching enabled (feature-match may support later).
+   - performance optimized on compute shaders.
+
+ * Vulkan compute framework enabling.
+   - enabled Vulkan image processing under xcam framework.
+   - vk-copy-handler as sample code.
+
+ * suggest OpenCV version [3.0.0 - 3.4.3]
+ * support CPU stitching based on dual-const and dual-curve scaling factors.
+ * support OpenCL stitching based on auto-scale in vertical 2D-direction.
+ * change test-soft-image to test-surround-view
+
+2018/03/01: release libxcam version 1.1.0
+ * CPU stitching enabled for automotive surround view in Linux/Android.
+   - enable CPU multi-thread image processing framework.
+   - enable multi-band blender, geometry remap, data-copy, OpenCV feature match.
+   - enable 3D-bowl model stitching.
+   - support generic Android platform.
+   - CPU version of surround view stitching upstream to Android Open Source Project.
+
+ * surround-view OpenCL stitching feature enabled and quality improvement.
+   - add dewarp process based on bowl view model in geometry map.
+   - support multiple (4) cameras stitching.
+   - add new selection method based on clustering in feature match to improve quality of stitching.
+   - auto scale in x direction is done and y direction is WIP.
+   - quality tune on different datasets, both indoor and outdoor.
+
+ * support standard OpenCL 2.0+ driver (VPG OCL driver)
+   - support standard OpenCL buffer.
+   - remove libdrm dependency.
+   - drm preview removed from test-device-manager, test-pipe-manager and usb camera.
+
+ * enable deblurring feature based on OpenCV. (GSoC program)
+   - based on deconvolution algorithm filters
+   - support noise estimation
+   - support edgetaper
+
+ * sourround view solution will be integrated into Android EVS (exterior view system) WIP
+ * add sample recipe for yocto build (libxcam/doc/yocto).
+
 2017/07/10: release libxcam version 1.0.0
  * 360 video stitching performance and quality improvement.
    - enable geometry map to improve performance.
diff --git a/LICENSE b/LICENSE
index 744d243..6a2f304 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 
-   Copyright (c) 2014-2015 Intel Corporation
+   Copyright (c) 2014-2019 Intel Corporation
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
diff --git a/METADATA b/METADATA
index 4459c63..149456a 100644
--- a/METADATA
+++ b/METADATA
@@ -1,18 +1,15 @@
 name: "LibXCam"
-description:
-    "libXCam is a project for extended camera and computer "
-    "vision features. This library can work on GPU, CPU and "
-    "other HW platforms to improve image/video quality. "
-    "OpenCL as one of the common parallel computing languages "
-    "is used to improve performance in different platforms. "
-    "Other shading language supports are in roadmap."
-
+description: "libXCam is a project for extended camera and computer vision features. This library can work on GPU, CPU and other HW platforms to improve image/video quality. OpenCL as one of the common parallel computing languages is used to improve performance in different platforms. Other shading language supports are in roadmap."
 third_party {
   url {
     type: GIT
-    value: "https://github.com/01org/libxcam.git"
+    value: "https://github.com/intel/libxcam"
   }
-  version: "1.0.0"
-  last_upgrade_date { year: 2017 month: 9 day: 11 }
+  version: "release_1.2.2"
   license_type: NOTICE
+  last_upgrade_date {
+    year: 2019
+    month: 4
+    day: 4
+  }
 }
diff --git a/Makefile.am b/Makefile.am
index 3f59882..4285b9d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,23 +1,6 @@
-if HAVE_LIBCL
-CLX_KERNEL_DIR = clx_kernel
-else
-CLX_KERNEL_DIR =
-endif
-
-if HAVE_LIBCL
-TESTS_DIR = tests
-else
-if ENABLE_IA_AIQ
-TESTS_DIR = tests
-else
-TESTS_DIR =
-endif
-endif
-
 if ENABLE_CAPI
 CAPI_DIR = capi
-else
-CAPI_DIR =
 endif
-SUBDIRS = xcore $(CLX_KERNEL_DIR) modules plugins \
-          wrapper $(CAPI_DIR) $(TESTS_DIR) pkgconfig
+
+SUBDIRS = xcore shaders modules plugins \
+          wrapper $(CAPI_DIR) tests pkgconfig
diff --git a/README.md b/README.md
index 5958597..095724d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 ## libXCam
 
-Copyright (C) 2014-2017 Intel Corporation
+Copyright (C) 2014-2019 Intel Corporation
 
 libxcam core source code under the terms of Apache License, Version 2.0
 
@@ -12,48 +12,60 @@
 OpenCL is used to improve performance in different platforms.
 
 #### Features:
-  * Image processing features.
+  * Image processing features
     - Advanced features
-      - 360 Image stiching: generate 360 degree panorama photography by
-        stitching multiple neighbor fisheye images.
-      - Digital Video Stabilization:
+      - Automotive surround view(360) stitching (OpenCL/CPU/GLES)
+         - Support bowl view 3D model stitching by 4 video input.
+         - Enable geometry remap for WFoV camera calibration(intrinsic and extrinsic data).
+         - Quality and performance improved (OpenCL/CPU/GLES).
+         - CPU version upstreamed into AOSP for automotive surround view.
+         - Enable Vulkan to improve performance.
+      - 360 video stitching (Equirectangular mode via OpenCL)
+        - Support 2-fisheye (>180 degree) video stream stitching.
+        - Performance and quality improved.
+      - DNN inference framework
+        - Support pedestrian and vehicle detection.
+      - Digital Video Stabilization
         - OpenCV feature-matched based video stabilization.
         - gyroscope 3-DoF (orientation) based video stabilization.
-      - Blender: multi-band blender.
-      - Noise reduction.
+      - Blender: multi-band blender (OpenCL/CPU/GLES)
+      - Noise reduction (OpenCL)
         - adaptive NR based on wavelet-haar and Bayersian shrinkage.
         - 3D-NR with inter-block and intra-block reference.
         - wavelet-hat NR (obsolete).
-      - Wide dynamic range (WDR).
+      - Wide dynamic range (WDR) (OpenCL)
         - histogram adjustment tone-mapping.
         - gaussian-based tone-mapping (obsolete).
-      - Fog removal: retinex and dark channel prior algorithm.
+      - Fog removal: retinex and dark channel prior algorithm (OpenCL)
         - dark channel prior algorithm based defog.
         - multi-scale retinex based defog (obsolete).
-    - Basic pipeline from bayer to YUV/RGB format.
+    - Basic pipeline from bayer to YUV/RGB format (OpenCL / AtomISP)
       - Gamma correction, MACC, color space, demosaicing, simple bilateral
         noise reduction, edge enhancement and temporal noise reduction.
-    - 3A features.
+    - 3A features
       - Auto whitebalance, auto exposure, auto focus, black level correction,
         color correction, 3a-statistics calculation.
-  * Support 3rd party 3A lib which can be loaded dynamically.
+  * Support 3rd party 3A lib which can be loaded dynamically
        - hybrid 3a plugin.
-  * Support 3a analysis tuning framework for different features.
-  * Support smart analysis framework.
+  * Support 3a analysis tuning framework for different features
+  * Support smart analysis framework
        - Face detection interface/plugin.
-  * Enable gstreamer plugin.
+  * Enable gstreamer plugin
        - xcamsrc, capture from usb/isp camera, process 3a/basic/advanced features.
        - xcamfilter, improve image quality by advanced features and smart analysis.
 
 #### Prerequisite:
   * install gcc/g++, automake, autoconf, libtool, gawk, pkg-config
   * Linux kernel > 3.10
-  * install libdrm-dev
   * install ocl-icd-dev, ocl-icd-opencl-dev
-  * If --enable-libcl, need compile ocl driver <https://www.freedesktop.org/wiki/Software/Beignet/>
-  * If --enable-opencv, need compile opencv <http://opencv.org> (or: <https://github.com/opencv/opencv/wiki>)
   * If --enable-gst, need install libgstreamer1.0-dev, libgstreamer-plugins-base1.0-dev
-  * If --enable-aiq, need get ia_imaging lib which we don't support.
+  * If --enable-aiq, need get ia_imaging lib which we don't support
+  * If --enable-libcl, need compile [OpenCL](https://www.freedesktop.org/wiki/Software/Beignet) driver
+  * If --enable-opencv, suggest [OpenCV](http://opencv.org) versions [3.0.0 - 3.4.3] (or: [OpenCV Wiki](https://github.com/opencv/opencv/wiki))
+  * If --enable-render, need compile [OpenSceneGraph](https://github.com/openscenegraph/OpenSceneGraph) library with configure option "-DOSG_WINDOWING_SYSTEM=X11"
+  * If --enable-gles, need to install [Mesa3D](https://www.mesa3d.org) library
+  * If --enable-vulkan, need to install [Mesa3D](https://www.mesa3d.org) library
+  * If --enable-dnn, need to install OpenVino SDK
 
 #### Building and installing:
   * Environment variable settings<BR>
@@ -73,27 +85,53 @@
         --prefix=PREFIX         install architecture-independent files in PREFIX [default=/usr/local]
         --enable-debug          enable debug, [default=no]
         --enable-profiling      enable profiling, [default=no]
-        --enable-drm            enable drm buffer, [default=yes]
+        --enable-drm            enable drm buffer, [default=no]
         --enable-aiq            enable Aiq 3A algorithm build, [default=no]
         --enable-gst            enable gstreamer plugin build, [default=no]
         --enable-libcl          enable libcl image processor, [default=yes]
         --enable-opencv         enable opencv library, [default=no]
+        --enable-capi           enable libxcam-capi library, [default=no]
         --enable-docs           build Doxygen documentation [default=no]
         --enable-3alib          enable 3A lib build, [default=no]
         --enable-smartlib       enable smart analysis lib build, [default=no]
+        --enable-gles           enable gles, [default=no]
+        --enable-vulkan         enable vulkan, [default=no]
+        --enable-render         enable 3D texture render, [default=no]
+        --enable-dnn            enable dnn inference, [default=no]
 
     For example:
 
-        $ ./autogen.sh --prefix=/usr --enable-3alib --enable-aiq --enable-gst --enable-drm \
-          --enable-libcl --enable-opencv --enable-profiling --enable-smartlib
+        $ ./autogen.sh --prefix=/usr --enable-gst --enable-libcl --enable-opencv \
+          --enable-smartlib --enable-profiling --enable-gles --enable-render --enable-dnn
 
   * $ make
   * $ sudo make install
 
 #### Testing:
-  * For detailed test cases, please refer to:<BR>
-    <https://github.com/01org/libxcam/wiki/Tests>
+  * For detailed test cases, please go to [tests](https://github.com/intel/libxcam/wiki/Tests) page
 
 #### Reporting Bugs:
-  * Bugs or suggestions can be reported on the github issues page:<BR>
-    <https://github.com/01org/libxcam/issues>
+  * Bugs or suggestions can be reported on the github [issues](https://github.com/intel/libxcam/issues) page
+  * Security issues, please send email to wei.zong@intel.com directly
+
+#### Mailing list
+  * To post a message to all the list members, please send email to libxcam@lists.01.org
+  * To register libxcam public maillist, please go to [registration](https://lists.01.org/mailman/listinfo/libxcam) page
+
+#### Maintainer:
+  * Wind Yuan <feng.yuan@intel.com>
+  * Wei Zong <wei.zong@intel.com>
+
+#### Contributors: (orders by first name)
+  * Andrey Parfenov <a1994ndrey@gmail.com>
+  * Fei Wang <feix.w.wang@intel.com>
+  * Jia Meng <jia.meng@intel.com>
+  * John Ye <john.ye@intel.com>
+  * Juan Zhao <juan.j.zhao@intel.com>
+  * Junkai Wu <junkai.wu@intel.com>
+  * Sameer Kibey <sameer.kibey@intel.com>
+  * Shincy Tu <shincy.tu@intel.com>
+  * Wei Zong <wei.zong@intel.com>
+  * Yan Zhang <yan.y.zhang@intel.com>
+  * Yao Wang <yao.y.wang@intel.com>
+  * Yinhang Liu <yinhangx.liu@intel.com>
diff --git a/capi/Makefile.am b/capi/Makefile.am
index 029fd7a..6b04110 100644
--- a/capi/Makefile.am
+++ b/capi/Makefile.am
@@ -1,53 +1,51 @@
 lib_LTLIBRARIES = libxcam_capi.la
 
-XCAMCAPI_LIBS =                    \
-    $(LIBCL_LIBS)                  \
-    -ldl                           \
+XCAMCAPI_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)        \
+    $(LIBCL_CFLAGS)         \
+    -I$(top_srcdir)/xcore   \
+    -I$(top_srcdir)/modules \
     $(NULL)
 
-XCAMCAPI_CXXFLAGS =                \
-    $(XCAM_CXXFLAGS)               \
-    $(LIBCL_CFLAGS)                \
-    -I$(top_srcdir)/xcore          \
-    -I$(top_srcdir)/modules        \
+XCAMCAPI_LIBS = \
+    $(LIBCL_LIBS) -ldl                         \
+    $(top_builddir)/xcore/libxcam_core.la      \
+    $(top_builddir)/modules/ocl/libxcam_ocl.la \
     $(NULL)
 
 if HAVE_LIBDRM
 XCAMCAPI_CXXFLAGS += $(LIBDRM_CFLAGS)
-XCAMCAPI_LIBS +=                   \
-    -ldrm_intel                    \
-    $(LIBDRM_LIBS)                 \
+XCAMCAPI_LIBS += \
+    -ldrm_intel    \
+    $(LIBDRM_LIBS) \
     $(NULL)
 endif
 
-xcam_ocl_sources =                 \
-    xcam_handle.cpp                \
-    context_priv.cpp               \
-   $(NULL)
-
-libxcam_capi_la_SOURCES =          \
-    $(xcam_ocl_sources)            \
+xcam_ocl_sources = \
+    xcam_handle.cpp  \
+    context_priv.cpp \
     $(NULL)
 
-libxcam_capi_la_CXXFLAGS =       \
-    $(XCAMCAPI_CXXFLAGS)         \
+libxcam_capi_la_SOURCES = \
+    $(xcam_ocl_sources) \
     $(NULL)
 
-libxcam_capi_la_LIBADD =           \
-    $(top_builddir)/modules/ocl/libxcam_ocl.la \
-    $(top_builddir)/xcore/libxcam_core.la      \
-    $(XCAMCAPI_LIBS)                           \
+libxcam_capi_la_CXXFLAGS = \
+    $(XCAMCAPI_CXXFLAGS) \
     $(NULL)
 
-libxcam_capi_la_LDFLAGS =          \
-    $(XCAM_LT_LDFLAGS)             \
-    $(PTHREAD_LDFLAGS)             \
+libxcam_capi_la_LIBADD = \
+    $(XCAMCAPI_LIBS) \
+    $(NULL)
+
+libxcam_capi_la_LDFLAGS = \
+    $(XCAM_LT_LDFLAGS) \
     $(NULL)
 
 libxcam_capiincludedir = $(includedir)/xcam/capi
 
 nobase_libxcam_capiinclude_HEADERS = \
-    xcam_handle.h                    \
-   $(NULL)
+    xcam_handle.h \
+    $(NULL)
 
 libxcam_capi_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/capi/context_priv.cpp b/capi/context_priv.cpp
index ecbffa6..2e685c1 100644
--- a/capi/context_priv.cpp
+++ b/capi/context_priv.cpp
@@ -59,8 +59,9 @@
     , _alloc_out_buf (false)
 {
     if (!_inbuf_pool.ptr()) {
-        _inbuf_pool = new CLVideoBufferPool ();
-        XCAM_ASSERT (_inbuf_pool.ptr ());
+        SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+        XCAM_ASSERT (pool.ptr ());
+        _inbuf_pool = pool;
     }
 }
 
@@ -222,10 +223,6 @@
     image_360->set_output_size (sttch_width, sttch_height);
     XCAM_LOG_INFO ("stitch output size width:%d height:%d", sttch_width, sttch_height);
 
-#if HAVE_OPENCV
-    image_360->set_feature_match_ocl (_fm_ocl);
-#endif
-
     return image_360;
 }
 
diff --git a/capi/context_priv.h b/capi/context_priv.h
index fe5c0a9..eb7514f 100644
--- a/capi/context_priv.h
+++ b/capi/context_priv.h
@@ -165,7 +165,6 @@
         , _need_seam (false)
         , _fisheye_map (false)
         , _need_lsc (false)
-        , _fm_ocl (false)
         , _scale_mode (CLBlenderScaleLocal)
         , _res_mode (StitchRes1080P)
     {}
@@ -176,7 +175,6 @@
     bool                  _need_seam;
     bool                  _fisheye_map;
     bool                  _need_lsc;
-    bool                  _fm_ocl;
     CLBlenderScaleMode    _scale_mode;
     StitchResMode         _res_mode;
 };
diff --git a/clx_kernel/Makefile.am b/clx_kernel/Makefile.am
deleted file mode 100644
index c87cf1a..0000000
--- a/clx_kernel/Makefile.am
+++ /dev/null
@@ -1,39 +0,0 @@
-clx_kernel_sources = \
-	kernel_csc.clx                \
-	kernel_demo.clx               \
-	kernel_defog_dcp.clx          \
-	kernel_min_filter.clx         \
-	kernel_bi_filter.clx          \
-	kernel_tnr.clx                \
-	kernel_bayer_pipe.clx         \
-	kernel_bayer_basic.clx        \
-	kernel_fisheye.clx            \
-	kernel_rgb_pipe.clx           \
-	kernel_yuv_pipe.clx           \
-	kernel_tonemapping.clx        \
-	kernel_newtonemapping.clx     \
-	kernel_image_scaler.clx       \
-	kernel_retinex.clx            \
-	kernel_gauss.clx              \
-	kernel_gauss_lap_pyramid.clx  \
-	kernel_geo_map.clx            \
-	kernel_wavelet_denoise.clx    \
-	kernel_wavelet_haar.clx       \
-	kernel_wavelet_coeff.clx      \
-	kernel_wire_frame.clx         \
-	kernel_3d_denoise.clx         \
-	kernel_3d_denoise_slm.clx     \
-	kernel_image_warp.clx         \
-	$(NULL)
-
-cl_quotation_sh = \
-	$(top_srcdir)/tools/cl-double-quotation.sh
-
-cl_kernel_dir = $(top_srcdir)/cl_kernel
-
-all-local: $(clx_kernel_sources)
-
-$(clx_kernel_sources): %.clx: $(cl_kernel_dir)/%.cl
-	@$(cl_quotation_sh) $< $@
-
-CLEANFILES = $(clx_kernel_sources)
diff --git a/configure.ac b/configure.ac
index e98ad18..6c8c363 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,8 +2,8 @@
 # Process this file with autoconf to produce a configure script.
 
 m4_define([xcam_major_version], [1])
-m4_define([xcam_minor_version], [1])
-m4_define([xcam_micro_version], [0])
+m4_define([xcam_minor_version], [2])
+m4_define([xcam_micro_version], [2])
 m4_define([xcam_version], [xcam_major_version.xcam_minor_version.xcam_micro_version])
 
 AC_PREREQ([2.60])
@@ -27,6 +27,13 @@
 AC_SUBST(XCAM_LT_VERSION)
 AC_SUBST(XCAM_LT_LDFLAGS)
 
+#xcam required OpenCV version
+XCAM_REQUIRE_CV_MIN=3.0.0
+XCAM_REQUIRE_CV_MAX=3.4.3
+
+#xcam required OpenSceneGraph version
+XCAM_REQUIRE_OSG_MIN=3.3.2
+
 # Checks for programs.
 AC_PROG_CC
 AC_PROG_CXX
@@ -65,6 +72,16 @@
                    [enable libcl image processor, @<:@default=yes@:>@]),
     [], [enable_libcl="yes"])
 
+AC_ARG_ENABLE([gles],
+    AS_HELP_STRING([--enable-gles],
+                   [enable gles, @<:@default=no@:>@]),
+    [], [enable_gles="no"])
+
+AC_ARG_ENABLE([vulkan],
+    AS_HELP_STRING([--enable-vulkan],
+                   [enable vulkan, @<:@default=no@:>@]),
+    [], [enable_vulkan="no"])
+
 AC_ARG_ENABLE(opencv,
     AS_HELP_STRING([--enable-opencv],
                    [enable opencv library, @<:@default=no@:>@]),
@@ -72,8 +89,18 @@
 
 AC_ARG_ENABLE(capi,
     AS_HELP_STRING([--enable-capi],
-                   [enable libxcam-capi library, @<:@default=yes@:>@]),
-    [], [enable_capi="yes"])
+                   [enable libxcam-capi library, @<:@default=no@:>@]),
+    [], [enable_capi="no"])
+
+AC_ARG_ENABLE([render],
+    AS_HELP_STRING([--enable-render],
+                   [enable texture render with OpenSceneGraph library, @<:@default=no@:>@]),
+    [], [enable_render="no"])
+
+AC_ARG_ENABLE([dnn],
+    AS_HELP_STRING([--enable-dnn],
+                   [enable dnn with OpenVino library, @<:@default=no@:>@]),
+    [], [enable_dnn="no"])
 
 # documentation
 AC_ARG_ENABLE(docs,
@@ -118,6 +145,51 @@
     PKG_CHECK_MODULES(LIBCL, [libcl], [HAVE_LIBCL=1], [HAVE_LIBCL=0])
 fi
 
+# check gl
+HAVE_GLES=0
+if test "$enable_gles" = "yes"; then
+    PKG_CHECK_MODULES(LIBGL, [gl], [HAVE_GLES=1], [HAVE_GLES=0])
+fi
+
+# check vulkan
+HAVE_VULKAN=0
+if test "$enable_vulkan" = "yes"; then
+    PKG_CHECK_MODULES(LIBVULKAN, [vulkan], [HAVE_VULKAN=1], [HAVE_VULKAN=0])
+fi
+
+# check open sence graph
+ENABLE_RENDER=0
+if test "$enable_render" = "yes"; then
+    PKG_CHECK_MODULES(
+        [LIBOSG],
+        [openscenegraph-osg >= $XCAM_REQUIRE_OSG_MIN],
+        [HAVE_OSG=1],
+        [HAVE_OSG=0])
+
+    XCAM_OSG_VERSION=`$PKG_CONFIG --modversion openscenegraph-osg`
+    AC_MSG_NOTICE(OpenSceneGraph version: $XCAM_OSG_VERSION)
+
+    if test "$HAVE_OSG" -eq 1; then
+        ENABLE_RENDER=1
+    else
+        AC_MSG_WARN(OpenSceneGraph required version: >= $XCAM_REQUIRE_OSG_MIN)
+        ENABLE_RENDER=0
+    fi
+fi
+
+ENABLE_DNN=0
+if test "$enable_dnn" = "yes"; then
+    if test -z $OPENVINO_IE_INC_PATH; then
+        AC_MSG_WARN(Please export OPENVINO_IE_INC_PATH environment variables)
+        AC_MSG_ERROR(OpenVino inc path has not been set ... disable DNN module!)
+    fi
+    if test -z $OPENVINO_IE_LIBS_PATH; then
+        AC_MSG_WARN(Please export OPENVINO_IE_LIBS_PATH environment variables)
+        AC_MSG_ERROR(OpenVino library path has not been set ... disable DNN module!)
+    fi
+    ENABLE_DNN=1
+fi
+
 if test "$enable_libcl" = "yes" && test "$HAVE_LIBCL" -eq 0; then
     PKG_CHECK_MODULES(LIBCL, [OpenCL], [HAVE_LIBCL=1], [HAVE_LIBCL=0])
 fi
@@ -143,12 +215,21 @@
     fi
 fi
 
-# check opencv minimum version number
+# check opencv version number
 HAVE_OPENCV=0
 if test "$enable_opencv" = "yes"; then
-    OPENCV_VERSION_STR=`$PKG_CONFIG --modversion opencv`
-        PKG_CHECK_MODULES([OPENCV], [opencv >= 3.0.0], [HAVE_OPENCV=1], [HAVE_OPENCV=0])
-        echo "OpenCV version:"$OPENCV_VERSION_STR "minimum required version:3.0.0" "have opencv:"$HAVE_OPENCV
+    PKG_CHECK_MODULES(
+        [OPENCV],
+        [opencv >= $XCAM_REQUIRE_CV_MIN opencv <= $XCAM_REQUIRE_CV_MAX],
+        [HAVE_OPENCV=1],
+        [HAVE_OPENCV=0])
+
+    XCAM_CV_VERSION=`$PKG_CONFIG --modversion opencv`
+    AC_MSG_NOTICE(OpenCV version: $XCAM_CV_VERSION)
+
+    if test "$HAVE_OPENCV" -eq 0; then
+        AC_MSG_ERROR(OpenCV required version: >= $XCAM_REQUIRE_CV_MIN && <= $XCAM_REQUIRE_CV_MAX)
+    fi
 fi
 
 # check opencv videostab module
@@ -193,7 +274,8 @@
 
 # check capi build
 ENABLE_CAPI=0
-if test "$enable_capi" = "yes"; then
+if test "$enable_capi" = "yes" && test "$HAVE_LIBCL" -eq 1; then
+    AC_MSG_NOTICE(enable capi && have libcl: $HAVE_LIBCL)
     ENABLE_CAPI=1
 fi
 
@@ -305,7 +387,7 @@
 AM_CONDITIONAL([ENABLE_GST], [test "$ENABLE_GST" -eq 1])
 
 dnl set XCAM_CFLAGS and XCAM_CXXFLAGS
-XCAM_CFLAGS=" -fPIC -DSTDC99 -W -Wall -D_REENTRANT -Wformat -Wformat-security -fstack-protector"
+XCAM_CFLAGS=" -fPIC -Wall -fstack-protector"
 if test "$enable_debug" = "yes"; then
     XCAM_CFLAGS="$XCAM_CFLAGS -g -DDEBUG"
 fi
@@ -313,9 +395,6 @@
 AC_SUBST(XCAM_CFLAGS)
 AC_SUBST(XCAM_CXXFLAGS)
 
-PTHREAD_LDFLAGS="$PTHREAD_LDFLAGS -pthread"
-AC_SUBST(PTHREAD_LDFLAGS)
-
 # define macor in config.h
 AC_DEFINE_UNQUOTED([ENABLE_PROFILING], $ENABLE_PROFILING,
     [enable profiling])
@@ -328,6 +407,22 @@
     [have libcl])
 AM_CONDITIONAL([HAVE_LIBCL], [test "$HAVE_LIBCL" -eq 1])
 
+AC_DEFINE_UNQUOTED([HAVE_GLES], $HAVE_GLES,
+    [have gles])
+AM_CONDITIONAL([HAVE_GLES], [test "$HAVE_GLES" -eq 1])
+
+AC_DEFINE_UNQUOTED([HAVE_VULKAN], $HAVE_VULKAN,
+    [have vulkan])
+AM_CONDITIONAL([HAVE_VULKAN], [test "$HAVE_VULKAN" -eq 1])
+
+AC_DEFINE_UNQUOTED([ENABLE_RENDER], $ENABLE_RENDER,
+    [enable texture render])
+AM_CONDITIONAL([ENABLE_RENDER], [test "$ENABLE_RENDER" -eq 1])
+
+AC_DEFINE_UNQUOTED([ENABLE_DNN], $ENABLE_DNN,
+    [enable dnn])
+AM_CONDITIONAL([ENABLE_DNN], [test "$ENABLE_DNN" -eq 1])
+
 AC_DEFINE_UNQUOTED([HAVE_OPENCV], $HAVE_OPENCV,
     [have opencv])
 AM_CONDITIONAL([HAVE_OPENCV], [test "$HAVE_OPENCV" -eq 1])
@@ -354,12 +449,19 @@
 AM_CONDITIONAL([USE_LOCAL_AIQ], [test "$USE_LOCAL_AIQ" -eq 1])
 
 AC_CONFIG_FILES([Makefile
-                 clx_kernel/Makefile
+                 shaders/Makefile
+                 shaders/clx/Makefile
+                 shaders/glslx/Makefile
                  xcore/Makefile
                  modules/Makefile
+                 modules/ocv/Makefile
                  modules/soft/Makefile
                  modules/isp/Makefile
                  modules/ocl/Makefile
+                 modules/gles/Makefile
+                 modules/vulkan/Makefile
+                 modules/render/Makefile
+                 modules/dnn/Makefile
                  wrapper/Makefile
                  wrapper/gstreamer/Makefile
                  wrapper/gstreamer/interface/Makefile
@@ -383,8 +485,13 @@
 if test "$USE_LOCAL_AIQ" -eq 1; then use_local_aiq="yes"; else  use_local_aiq="no"; fi
 if test "$USE_LOCAL_ATOMISP" -eq 1; then use_local_atomisp="yes"; else  use_local_atomisp="no"; fi
 if test "$HAVE_LIBCL" -eq 1; then have_libcl="yes"; else  have_libcl="no"; fi
+if test "$HAVE_GLES" -eq 1; then have_gles="yes"; else  have_gles="no"; fi
+if test "$HAVE_VULKAN" -eq 1; then have_vulkan="yes"; else  have_vulkan="no"; fi
 if test "$HAVE_OPENCV" -eq 1; then have_opencv="yes"; else have_opencv="no"; fi
+if test "$ENABLE_RENDER" -eq 1; then enable_render="yes"; else enable_render="no"; fi
+if test "$ENABLE_DNN" -eq 1; then enable_dnn="yes"; else enable_dnn="no"; fi
 if test "$ENABLE_DVS" -eq 1; then enable_dvs="yes"; else enable_dvs="no"; fi
+if test "$ENABLE_CAPI" -eq 1; then enable_capi="yes"; else enable_capi="no"; fi
 
 echo "
      libxcam configuration summary
@@ -396,8 +503,12 @@
      build aiq analyzer         : $enable_aiq
      use local aiq              : $use_local_aiq
      use local atomisp          : $use_local_atomisp
-     have opencl lib            : $have_libcl
-     have opencv lib            : $have_opencv
+     enable OpenCV              : $have_opencv
+     enable OpenCL              : $have_libcl
+     enable GLES                : $have_gles
+     enable Vulkan              : $have_vulkan
+     enable OSG render          : $enable_render
+     enable DNN                 : $enable_dnn
      enable 3a lib              : $enable_3alib
      enable smart analysis lib  : $enable_smartlib
      enable dvs                 : $enable_dvs
diff --git a/doc/xcam_framework_20170407.png b/doc/xcam_framework_20170407.png
deleted file mode 100644
index ea7b7ee..0000000
--- a/doc/xcam_framework_20170407.png
+++ /dev/null
Binary files differ
diff --git a/doc/xcam_framework_20181017.png b/doc/xcam_framework_20181017.png
new file mode 100644
index 0000000..1419323
--- /dev/null
+++ b/doc/xcam_framework_20181017.png
Binary files differ
diff --git a/doc/xcam_framework_20190329.png b/doc/xcam_framework_20190329.png
new file mode 100644
index 0000000..4bcacf1
--- /dev/null
+++ b/doc/xcam_framework_20190329.png
Binary files differ
diff --git a/doc/yocto/libxcam_sample.bb b/doc/yocto/libxcam_sample.bb
index 0ebdd31..26c728e 100644
--- a/doc/yocto/libxcam_sample.bb
+++ b/doc/yocto/libxcam_sample.bb
@@ -1,6 +1,6 @@
 SUMMARY = "Libxcam"
 DESCRIPTION = "Libxcam: Extended camera features and cross platform computer vision project"
-HOMEPAGE = "https://github.com/01org/libxcam/wiki"
+HOMEPAGE = "https://github.com/intel/libxcam/wiki"
 LICENSE = "Apache-2.0"
 
 PR = "r0"
@@ -8,7 +8,7 @@
 
 LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=a739187a9544e0731270d11a8f5be792"
 
-SRC_URI = "git://github.com/01org/libxcam.git;branch=master"
+SRC_URI = "git://github.com/intel/libxcam.git;branch=master"
 SRCREV = "${AUTOREV}"
 
 DEPENDS = "glib-2.0 libdrm beignet opencv gstreamer1.0 gstreamer1.0-plugins-base"
@@ -19,7 +19,7 @@
 
 CFLAGS += "-fPIE -fPIC"
 CFLAGS += "-O2 -D_FORTIFY_SOURCE=2"
-CFLAGS += "-Wformat -Wformat-security"
+CFLAGS += "-Wall -Wno-unused-parameter"
 CFLAGS += "-fstack-protector"
 
 LDFLAGS += "-z noexecstack"
diff --git a/modules/Makefile.am b/modules/Makefile.am
index fd362f8..b4eda9b 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -1,13 +1,29 @@
+if HAVE_OPENCV
+OCV_DIR = ocv
+endif
+
 if HAVE_LIBCL
 OCL_DIR = ocl
-else
-OCL_DIR =
+endif
+
+if HAVE_GLES
+GLES_DIR = gles
+endif
+
+if HAVE_VULKAN
+VULKAN_DIR = vulkan
+endif
+
+if ENABLE_RENDER
+RENDER_DIR = render
 endif
 
 if ENABLE_IA_AIQ
 ISP_DIR = isp
-else
-ISP_DIR =
 endif
 
-SUBDIRS = soft $(ISP_DIR) $(OCL_DIR)
+if ENABLE_DNN
+DNN_DIR = dnn
+endif
+
+SUBDIRS = $(OCV_DIR) soft $(OCL_DIR) $(GLES_DIR) $(VULKAN_DIR) $(RENDER_DIR) $(ISP_DIR) $(DNN_DIR)
diff --git a/modules/dnn/Makefile.am b/modules/dnn/Makefile.am
new file mode 100644
index 0000000..bcad5fd
--- /dev/null
+++ b/modules/dnn/Makefile.am
@@ -0,0 +1,52 @@
+lib_LTLIBRARIES = libxcam_dnn.la
+
+XCAM_DNN_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)        \
+    -I$(top_srcdir)/xcore   \
+    -I$(top_srcdir)/modules \
+    -I$(OPENVINO_IE_INC_PATH)/include \
+    -I$(OPENVINO_IE_INC_PATH)/src/extension \
+    -I$(OPENVINO_IE_INC_PATH)/samples/common/format_reader \
+    $(NULL)
+
+XCAM_DNN_LIBS = \
+    $(top_builddir)/xcore/libxcam_core.la \
+    -L$(OPENVINO_IE_LIBS_PATH) \
+    -linference_engine \
+    -lclDNN64 \
+    -lclDNNPlugin \
+    -lcpu_extension \
+    -lMKLDNNPlugin \
+    -lformat_reader \
+    $(NULL)
+
+xcam_dnn_sources =       \
+    dnn_inference_engine.cpp   \
+    dnn_object_detection.cpp   \
+    $(NULL)
+
+libxcam_dnn_la_SOURCES = \
+    $(xcam_dnn_sources)  \
+    $(NULL)
+
+libxcam_dnn_la_CXXFLAGS = \
+    $(XCAM_DNN_CXXFLAGS)  \
+    $(NULL)
+
+libxcam_dnn_la_LIBADD = \
+    $(XCAM_DNN_LIBS)    \
+    $(NULL)
+
+libxcam_dnn_la_LDFLAGS = \
+    $(XCAM_LT_LDFLAGS)   \
+    -Wl,-rpath,$(OPENVINO_IE_LIBS_PATH) \
+    $(NULL)
+
+libxcam_dnnincludedir = $(includedir)/xcam/dnn
+
+nobase_libxcam_dnninclude_HEADERS = \
+    dnn_inference_engine.h          \
+    dnn_object_detection.h          \
+    $(NULL)
+
+libxcam_dnn_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/dnn/dnn_inference_engine.cpp b/modules/dnn/dnn_inference_engine.cpp
new file mode 100755
index 0000000..8453161
--- /dev/null
+++ b/modules/dnn/dnn_inference_engine.cpp
@@ -0,0 +1,878 @@
+/*
+ * dnn_inference_engine.cpp -  dnn inference engine
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include <iomanip>
+
+#include <format_reader_ptr.h>
+#include <ext_list.hpp>
+
+#include "dnn_inference_engine.h"
+
+using namespace std;
+using namespace InferenceEngine;
+
+namespace XCam {
+
+DnnInferenceEngine::DnnInferenceEngine (DnnInferConfig& config)
+    : _model_created (false)
+    , _model_loaded (false)
+    , _input_image_width (0)
+    , _input_image_height (0)
+{
+    XCAM_LOG_DEBUG ("DnnInferenceEngine::DnnInferenceEngine");
+
+    create_model (config);
+}
+
+
+DnnInferenceEngine::~DnnInferenceEngine ()
+{
+
+}
+
+XCamReturn
+DnnInferenceEngine::create_model (DnnInferConfig& config)
+{
+    XCAM_LOG_DEBUG ("DnnInferenceEngine::create_model");
+    if (_model_created) {
+        XCAM_LOG_INFO ("model already created!");
+        return XCAM_RETURN_NO_ERROR;
+    }
+
+    // 1. Read the Intermediate Representation
+    XCAM_LOG_DEBUG ("pre-trained model file name: %s", config.model_filename);
+    if (NULL == config.model_filename) {
+        XCAM_LOG_ERROR ("Model file name is empty!");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    _network_reader.ReadNetwork (get_filename_prefix (config.model_filename) + ".xml");
+    _network_reader.ReadWeights (get_filename_prefix (config.model_filename) + ".bin");
+
+    // 2. read network from model
+    _network = _network_reader.getNetwork ();
+
+    // 3. Select Plugin - Select the plugin on which to load your network.
+    // 3.1. Create the plugin with the InferenceEngine::PluginDispatcher load helper class.
+    if (NULL == config.plugin_path) {
+        InferenceEngine::PluginDispatcher dispatcher ({""});
+        _plugin = dispatcher.getPluginByDevice (getDeviceName (get_device_from_id (config.target_id)));
+    } else {
+        InferenceEngine::PluginDispatcher dispatcher ({config.plugin_path});
+        _plugin = dispatcher.getPluginByDevice (getDeviceName (get_device_from_id (config.target_id)));
+    }
+
+    // 3.2. Pass per device loading configurations specific to this device,
+    // and register extensions to this device.
+    if (DnnInferDeviceCPU == config.target_id) {
+        /**
+        * cpu_extensions library is compiled from "extension" folder containing
+        * custom MKLDNNPlugin layer implementations. These layers are not supported
+        * by mkldnn, but they can be useful for inferring custom topologies.
+        **/
+        _plugin.AddExtension (std::make_shared<Extensions::Cpu::CpuExtensions>());
+
+        if (NULL != config.cpu_ext_path) {
+            std::string cpu_ext_path (config.cpu_ext_path);
+            // CPU(MKLDNN) extensions are loaded as a shared library and passed as a pointer to base extension
+            auto extensionPtr = InferenceEngine::make_so_pointer<InferenceEngine::IExtension>(cpu_ext_path);
+            _plugin.AddExtension (extensionPtr);
+            XCAM_LOG_DEBUG ("CPU Extension loaded: %s", cpu_ext_path);
+        }
+    } else if (DnnInferDeviceGPU == config.target_id) {
+        if (NULL != config.cldnn_ext_path) {
+            std::string cldnn_ext_path (config.cldnn_ext_path);
+            // clDNN Extensions are loaded from an .xml description and OpenCL kernel files
+            _plugin.SetConfig ({ { InferenceEngine::PluginConfigParams::KEY_CONFIG_FILE, cldnn_ext_path } });
+            XCAM_LOG_DEBUG ("GPU Extension loaded: %s", cldnn_ext_path);
+        }
+    }
+
+    if (config.perf_counter > 0) {
+        _plugin.SetConfig ({ { InferenceEngine::PluginConfigParams::KEY_PERF_COUNT, InferenceEngine::PluginConfigParams::YES } });
+    }
+
+    _model_created = true;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::load_model (DnnInferConfig& config)
+{
+    XCAM_LOG_DEBUG ("DnnInferenceEngine::load_model");
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+    if (_model_loaded) {
+        XCAM_LOG_INFO ("model already loaded!");
+        return XCAM_RETURN_NO_ERROR;
+    }
+
+    InferenceEngine::ExecutableNetwork execute_network = _plugin.LoadNetwork (_network, {});
+
+    _infer_request = execute_network.CreateInferRequest ();
+
+    _model_loaded = true;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::get_info (DnnInferenceEngineInfo& info, DnnInferInfoType type)
+{
+    XCAM_LOG_DEBUG ("DnnInferenceEngine::get_info type %d", type);
+
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    info.type = type;
+    if (DnnInferInfoEngine == type) {
+        info.major = GetInferenceEngineVersion ()->apiVersion.major;
+        info.minor = GetInferenceEngineVersion ()->apiVersion.minor;
+    } else if (DnnInferInfoPlugin == type) {
+        const InferenceEngine::Version *plugin_version = NULL;
+        static_cast<InferenceEngine::InferenceEnginePluginPtr>(_plugin)->GetVersion (plugin_version);
+
+        info.major = plugin_version->apiVersion.major;
+        info.minor = plugin_version->apiVersion.minor;
+        info.desc = plugin_version->description;
+    } else if (DnnInferInfoNetwork == type) {
+        info.major = _network_reader.getVersion ();
+        info.desc = _network_reader.getDescription ().c_str ();
+        info.name = _network_reader.getName ().c_str ();
+    } else {
+        XCAM_LOG_WARNING ("DnnInferenceEngine::get_info type %d not supported!", type);
+    }
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::set_batch_size (const size_t size)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    _network.setBatchSize (size);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+size_t
+DnnInferenceEngine::get_batch_size ()
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return -1;
+    }
+
+    return _network.getBatchSize ();
+}
+
+XCamReturn
+DnnInferenceEngine::start (bool sync)
+{
+    XCAM_LOG_DEBUG ("Start inference sync(%d)", sync);
+
+    if (! _model_loaded) {
+        XCAM_LOG_ERROR ("Please load the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    if (sync) {
+        _infer_request.Infer ();
+    } else {
+        _infer_request.StartAsync ();
+        _infer_request.Wait (IInferRequest::WaitMode::RESULT_READY);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+size_t
+DnnInferenceEngine::get_input_size ()
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return -1;
+    }
+
+    InputsDataMap inputs_info (_network.getInputsInfo());
+    return inputs_info.size ();
+}
+
+size_t
+DnnInferenceEngine::get_output_size ()
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return -1;
+    }
+
+    OutputsDataMap outputs_info (_network.getOutputsInfo());
+    return outputs_info.size ();
+}
+
+XCamReturn
+DnnInferenceEngine::set_input_presion (uint32_t idx, DnnInferPrecisionType precision)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    uint32_t id = 0;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    if (idx > inputs_info.size ()) {
+        XCAM_LOG_ERROR ("Input is out of range");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    for (auto & item : inputs_info) {
+        if (id == idx) {
+            Precision input_precision = convert_precision_type (precision);
+            item.second->setPrecision (input_precision);
+            break;
+        }
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+DnnInferPrecisionType
+DnnInferenceEngine::get_input_presion (uint32_t idx)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return DnnInferPrecisionUnspecified;
+    }
+
+    uint32_t id = 0;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    if (idx > inputs_info.size ()) {
+        XCAM_LOG_ERROR ("Input is out of range");
+        return DnnInferPrecisionUnspecified;
+    }
+
+    for (auto & item : inputs_info) {
+        if (id == idx) {
+            Precision input_precision = item.second->getPrecision ();
+            return convert_precision_type (input_precision);
+        }
+        id++;
+    }
+    return DnnInferPrecisionUnspecified;
+}
+
+XCamReturn
+DnnInferenceEngine::set_output_presion (uint32_t idx, DnnInferPrecisionType precision)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    uint32_t id = 0;
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+
+    if (idx > outputs_info.size ()) {
+        XCAM_LOG_ERROR ("Output is out of range");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    for (auto & item : outputs_info) {
+        if (id == idx) {
+            Precision output_precision = convert_precision_type (precision);
+            item.second->setPrecision (output_precision);
+            break;
+        }
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+DnnInferPrecisionType
+DnnInferenceEngine::get_output_presion (uint32_t idx)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return DnnInferPrecisionUnspecified;
+    }
+
+    uint32_t id = 0;
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+
+    if (idx > outputs_info.size ()) {
+        XCAM_LOG_ERROR ("Input is out of range");
+        return DnnInferPrecisionUnspecified;
+    }
+
+    for (auto & item : outputs_info) {
+        if (id == idx) {
+            Precision output_precision = item.second->getPrecision ();
+            return convert_precision_type (output_precision);
+        }
+        id++;
+    }
+    return DnnInferPrecisionUnspecified;
+}
+
+XCamReturn
+DnnInferenceEngine::set_input_layout (uint32_t idx, DnnInferLayoutType layout)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+    uint32_t id = 0;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    if (idx > inputs_info.size ()) {
+        XCAM_LOG_ERROR ("Input is out of range");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    for (auto & item : inputs_info) {
+        if (id == idx) {
+            /** Creating first input blob **/
+            Layout input_layout = convert_layout_type (layout);
+            item.second->setLayout (input_layout);
+            break;
+        }
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::set_output_layout (uint32_t idx, DnnInferLayoutType layout)
+{
+    if (! _model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    uint32_t id = 0;
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+
+    if (idx > outputs_info.size ()) {
+        XCAM_LOG_ERROR ("Output is out of range");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    for (auto & item : outputs_info) {
+        if (id == idx) {
+            Layout output_layout = convert_layout_type (layout);
+            item.second->setLayout (output_layout);
+            break;
+        }
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::set_model_input_info (DnnInferInputOutputInfo& info)
+{
+    XCAM_LOG_DEBUG ("DnnInferenceEngine::set_model_input_info");
+
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    if (info.numbers != inputs_info.size ()) {
+        XCAM_LOG_ERROR ("Input size is not matched with model info numbers %d !", info.numbers);
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+    int id = 0;
+
+    for (auto & item : inputs_info) {
+        Precision precision = convert_precision_type (info.precision[id]);
+        item.second->setPrecision (precision);
+        Layout layout = convert_layout_type (info.layout[id]);
+        item.second->setLayout (layout);
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::set_model_output_info (DnnInferInputOutputInfo& info)
+{
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+
+    if (info.numbers != outputs_info.size()) {
+        XCAM_LOG_ERROR ("Output size is not matched with model!");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    int id = 0;
+    for (auto & item : outputs_info) {
+        Precision precision = convert_precision_type (info.precision[id]);
+        item.second->setPrecision (precision);
+        Layout layout = convert_layout_type (info.layout[id]);
+        item.second->setLayout (layout);
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::set_input_blob (uint32_t idx, DnnInferData& data)
+{
+    unsigned int id = 0;
+    std::string item_name;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    if (idx > inputs_info.size()) {
+        XCAM_LOG_ERROR ("Input is out of range");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    for (auto & item : inputs_info) {
+        if (id == idx) {
+            item_name = item.first;
+            break;
+        }
+        id++;
+    }
+
+    if (item_name.empty ()) {
+        XCAM_LOG_ERROR ("item name is empty!");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    if (data.batch_idx > get_batch_size ()) {
+        XCAM_LOG_ERROR ("Too many input, it is bigger than batch size!");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    Blob::Ptr blob = _infer_request.GetBlob (item_name);
+    if (data.precision == DnnInferPrecisionFP32) {
+        if (data.data_type == DnnInferDataTypeImage) {
+            copy_image_to_blob<PrecisionTrait<Precision::FP32>::value_type>(data, blob, data.batch_idx);
+        } else {
+            copy_data_to_blob<PrecisionTrait<Precision::FP32>::value_type>(data, blob, data.batch_idx);
+        }
+    } else {
+        if (data.data_type == DnnInferDataTypeImage) {
+            copy_image_to_blob<uint8_t>(data, blob, data.batch_idx);
+        } else {
+            copy_data_to_blob<uint8_t>(data, blob, data.batch_idx);
+        }
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnInferenceEngine::set_inference_data (std::vector<std::string> images)
+{
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    uint32_t idx = 0;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    for (auto & i : images) {
+        FormatReader::ReaderPtr reader (i.c_str ());
+        if (reader.get () == NULL) {
+            XCAM_LOG_WARNING ("Image %d cannot be read!", i);
+            continue;
+        }
+
+        _input_image_width = reader->width ();
+        _input_image_height = reader->height ();
+
+        uint32_t image_width = 0;
+        uint32_t image_height = 0;
+
+        for (auto & item : inputs_info) {
+            image_width = inputs_info[item.first]->getDims()[0];
+            image_height = inputs_info[item.first]->getDims()[1];
+        }
+
+        std::shared_ptr<unsigned char> data (reader->getData (image_width, image_height));
+
+        if (data.get () != NULL) {
+            DnnInferData image;
+            image.width = image_width;
+            image.height = image_height;
+            image.width_stride = image_width;
+            image.height_stride = image_height;
+            image.buffer = data.get ();
+            image.channel_num = 3;
+            image.batch_idx = idx;
+            image.image_format = DnnInferImageFormatBGRPacked;
+
+            // set precision & data type
+            image.precision = get_input_presion (idx);
+            image.data_type = DnnInferDataTypeImage;
+
+            set_input_blob (idx, image);
+
+            idx ++;
+        } else {
+            XCAM_LOG_WARNING ("Valid input images were not found!");
+            continue;
+        }
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+std::shared_ptr<uint8_t>
+DnnInferenceEngine::read_inference_image (std::string image)
+{
+    FormatReader::ReaderPtr reader (image.c_str ());
+    if (reader.get () == NULL) {
+        XCAM_LOG_WARNING ("Image cannot be read!");
+        return NULL;
+    }
+
+    uint32_t image_width =  reader->width ();
+    uint32_t image_height = reader->height ();
+
+    std::shared_ptr<uint8_t> data (reader->getData (image_width, image_height));
+
+    if (data.get () != NULL) {
+        return data;
+    } else {
+        XCAM_LOG_WARNING ("Valid input images were not found!");
+        return NULL;
+    }
+}
+
+InferenceEngine::TargetDevice
+DnnInferenceEngine::get_device_from_string (const std::string &device_name)
+{
+    return InferenceEngine::TargetDeviceInfo::fromStr (device_name);
+}
+
+InferenceEngine::TargetDevice
+DnnInferenceEngine::get_device_from_id (DnnInferTargetDeviceType device)
+{
+    switch (device) {
+    case DnnInferDeviceDefault:
+        return InferenceEngine::TargetDevice::eDefault;
+    case DnnInferDeviceBalanced:
+        return InferenceEngine::TargetDevice::eBalanced;
+    case DnnInferDeviceCPU:
+        return InferenceEngine::TargetDevice::eCPU;
+    case DnnInferDeviceGPU:
+        return InferenceEngine::TargetDevice::eGPU;
+    case DnnInferDeviceFPGA:
+        return InferenceEngine::TargetDevice::eFPGA;
+    case DnnInferDeviceMyriad:
+        return InferenceEngine::TargetDevice::eMYRIAD;
+    case DnnInferDeviceHetero:
+        return InferenceEngine::TargetDevice::eHETERO;
+    default:
+        return InferenceEngine::TargetDevice::eCPU;
+    }
+}
+
+InferenceEngine::Layout
+DnnInferenceEngine::estimate_layout_type (const int ch_num)
+{
+    if (ch_num == 4) {
+        return InferenceEngine::Layout::NCHW;
+    } else if (ch_num == 3) {
+        return InferenceEngine::Layout::CHW;
+    } else if (ch_num == 2) {
+        return InferenceEngine::Layout::NC;
+    } else {
+        return InferenceEngine::Layout::ANY;
+    }
+}
+
+InferenceEngine::Layout
+DnnInferenceEngine::convert_layout_type (DnnInferLayoutType layout)
+{
+    switch (layout) {
+    case DnnInferLayoutNCHW:
+        return InferenceEngine::Layout::NCHW;
+    case DnnInferLayoutNHWC:
+        return InferenceEngine::Layout::NHWC;
+    case DnnInferLayoutOIHW:
+        return InferenceEngine::Layout::OIHW;
+    case DnnInferLayoutC:
+        return InferenceEngine::Layout::C;
+    case DnnInferLayoutCHW:
+        return InferenceEngine::Layout::CHW;
+    case DnnInferLayoutHW:
+        return InferenceEngine::Layout::HW;
+    case DnnInferLayoutNC:
+        return InferenceEngine::Layout::NC;
+    case DnnInferLayoutCN:
+        return InferenceEngine::Layout::CN;
+    case DnnInferLayoutBlocked:
+        return InferenceEngine::Layout::BLOCKED;
+    case DnnInferLayoutAny:
+        return InferenceEngine::Layout::ANY;
+    default:
+        return InferenceEngine::Layout::ANY;
+    }
+}
+
+DnnInferLayoutType
+DnnInferenceEngine::convert_layout_type (InferenceEngine::Layout layout)
+{
+    switch (layout) {
+    case InferenceEngine::Layout::NCHW:
+        return DnnInferLayoutNCHW;
+    case InferenceEngine::Layout::NHWC:
+        return DnnInferLayoutNHWC;
+    case InferenceEngine::Layout::OIHW:
+        return DnnInferLayoutOIHW;
+    case InferenceEngine::Layout::C:
+        return DnnInferLayoutC;
+    case InferenceEngine::Layout::CHW:
+        return DnnInferLayoutCHW;
+    case InferenceEngine::Layout::HW:
+        return DnnInferLayoutHW;
+    case InferenceEngine::Layout::NC:
+        return DnnInferLayoutNC;
+    case InferenceEngine::Layout::CN:
+        return DnnInferLayoutCN;
+    case InferenceEngine::Layout::BLOCKED:
+        return DnnInferLayoutBlocked;
+    case InferenceEngine::Layout::ANY:
+        return DnnInferLayoutAny;
+    default:
+        return DnnInferLayoutAny;
+    }
+}
+
+InferenceEngine::Precision
+DnnInferenceEngine::convert_precision_type (DnnInferPrecisionType precision)
+{
+    switch (precision) {
+    case DnnInferPrecisionMixed:
+        return InferenceEngine::Precision::MIXED;
+    case DnnInferPrecisionFP32:
+        return InferenceEngine::Precision::FP32;
+    case DnnInferPrecisionFP16:
+        return InferenceEngine::Precision::FP16;
+    case DnnInferPrecisionQ78:
+        return InferenceEngine::Precision::Q78;
+    case DnnInferPrecisionI16:
+        return InferenceEngine::Precision::I16;
+    case DnnInferPrecisionU8:
+        return InferenceEngine::Precision::U8;
+    case DnnInferPrecisionI8:
+        return InferenceEngine::Precision::I8;
+    case DnnInferPrecisionU16:
+        return InferenceEngine::Precision::U16;
+    case DnnInferPrecisionI32:
+        return InferenceEngine::Precision::I32;
+    case DnnInferPrecisionCustom:
+        return InferenceEngine::Precision::CUSTOM;
+    case DnnInferPrecisionUnspecified:
+        return InferenceEngine::Precision::UNSPECIFIED;
+    default:
+        return InferenceEngine::Precision::UNSPECIFIED;
+    }
+}
+
+DnnInferPrecisionType
+DnnInferenceEngine::convert_precision_type (InferenceEngine::Precision precision)
+{
+    switch (precision) {
+    case InferenceEngine::Precision::MIXED:
+        return DnnInferPrecisionMixed;
+    case InferenceEngine::Precision::FP32:
+        return DnnInferPrecisionFP32;
+    case InferenceEngine::Precision::FP16:
+        return DnnInferPrecisionFP16;
+    case InferenceEngine::Precision::Q78:
+        return DnnInferPrecisionQ78;
+    case InferenceEngine::Precision::I16:
+        return DnnInferPrecisionI16;
+    case InferenceEngine::Precision::U8:
+        return DnnInferPrecisionU8;
+    case InferenceEngine::Precision::I8:
+        return DnnInferPrecisionI8;
+    case InferenceEngine::Precision::U16:
+        return DnnInferPrecisionU16;
+    case InferenceEngine::Precision::I32:
+        return DnnInferPrecisionI32;
+    case InferenceEngine::Precision::CUSTOM:
+        return DnnInferPrecisionCustom;
+    case InferenceEngine::Precision::UNSPECIFIED:
+        return DnnInferPrecisionUnspecified;
+    default:
+        return DnnInferPrecisionUnspecified;
+    }
+}
+
+std::string
+DnnInferenceEngine::get_filename_prefix (const std::string &file_path)
+{
+    auto pos = file_path.rfind ('.');
+    if (pos == std::string::npos) {
+        return file_path;
+    }
+
+    return file_path.substr (0, pos);
+}
+
+template <typename T> XCamReturn
+DnnInferenceEngine::copy_image_to_blob (const DnnInferData& data, Blob::Ptr& blob, int batch_index)
+{
+    SizeVector blob_size = blob.get()->dims ();
+    const size_t width = blob_size[0];
+    const size_t height = blob_size[1];
+    const size_t channels = blob_size[2];
+    const size_t image_size = width * height;
+    unsigned char* buffer = (unsigned char*)data.buffer;
+    T* blob_data = blob->buffer ().as<T*>();
+
+    if (width != data.width || height != data.height) {
+        XCAM_LOG_ERROR ("Input Image size (%dx%d) is not matched with model required size (%dx%d)!",
+                        data.width, data.height, width, height);
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    int batch_offset = batch_index * height * width * channels;
+
+    if (DnnInferImageFormatBGRPlanar == data.image_format) {
+        // B G R planar input image
+        size_t image_stride_size = data.height_stride * data.width_stride;
+
+        if (data.width == data.width_stride &&
+                data.height == data.height_stride) {
+            std::memcpy (blob_data + batch_offset, buffer, image_size * channels);
+        } else if (data.width == data.width_stride) {
+            for (size_t ch = 0; ch < channels; ++ch) {
+                std::memcpy (blob_data + batch_offset + ch * image_size, buffer + ch * image_stride_size, image_size);
+            }
+        } else {
+            for (size_t ch = 0; ch < channels; ++ch) {
+                for (size_t h = 0; h < height; h++) {
+                    std::memcpy (blob_data + batch_offset + ch * image_size + h * width, buffer + ch * image_stride_size + h * data.width_stride, width);
+                }
+            }
+        }
+    } else if (DnnInferImageFormatBGRPacked == data.image_format) {
+        for (size_t pid = 0; pid < image_size; pid++) {
+            for (size_t ch = 0; ch < channels; ++ch) {
+                blob_data[batch_offset + ch * image_size + pid] = buffer[pid * channels + ch];
+            }
+        }
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+template <typename T> XCamReturn
+DnnInferenceEngine::copy_data_to_blob (const DnnInferData& data, Blob::Ptr& blob, int batch_index)
+{
+    SizeVector blob_size = blob.get ()->dims ();
+    T * buffer = (T *)data.buffer;
+    T* blob_data = blob->buffer ().as<T*>();
+
+    int batch_offset = batch_index * data.size;
+
+    memcpy (blob_data + batch_offset, buffer, data.size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void
+DnnInferenceEngine::print_performance_counts (const std::map<std::string, InferenceEngine::InferenceEngineProfileInfo>& performance_map)
+{
+    long long total_time = 0;
+    XCAM_LOG_DEBUG ("performance counts:");
+    for (const auto & it : performance_map) {
+        std::string to_print(it.first);
+        const int max_layer_name = 30;
+
+        if (it.first.length () >= max_layer_name) {
+            to_print = it.first.substr (0, max_layer_name - 4);
+            to_print += "...";
+        }
+
+        std::cout << std::setw(max_layer_name) << std::left << to_print;
+        switch (it.second.status) {
+        case InferenceEngine::InferenceEngineProfileInfo::EXECUTED:
+            std::cout << std::setw (15) << std::left << "EXECUTED";
+            break;
+        case InferenceEngine::InferenceEngineProfileInfo::NOT_RUN:
+            std::cout << std::setw (15) << std::left << "NOT_RUN";
+            break;
+        case InferenceEngine::InferenceEngineProfileInfo::OPTIMIZED_OUT:
+            std::cout << std::setw(15) << std::left << "OPTIMIZED_OUT";
+            break;
+        }
+        std::cout << std::setw (30) << std::left << "layerType: " + std::string (it.second.layer_type) + " ";
+        std::cout << std::setw (20) << std::left << "realTime: " + std::to_string (it.second.realTime_uSec);
+        std::cout << std::setw (20) << std::left << " cpu: " + std::to_string (it.second.cpu_uSec);
+        std::cout << " execType: " << it.second.exec_type << std::endl;
+        if (it.second.realTime_uSec > 0) {
+            total_time += it.second.realTime_uSec;
+        }
+    }
+    std::cout << std::setw (20) << std::left << "Total time: " + std::to_string (total_time) << " microseconds" << std::endl;
+}
+
+void
+DnnInferenceEngine::print_log (uint32_t flag)
+{
+    std::map<std::string, InferenceEngine::InferenceEngineProfileInfo> perfomance_map;
+
+    if (flag == DnnInferLogLevelNone) {
+        return;
+    }
+
+    if (flag & DnnInferLogLevelEngine) {
+        static_cast<InferenceEngine::InferenceEnginePluginPtr>(_plugin)->GetPerformanceCounts (perfomance_map, NULL);
+        print_performance_counts (perfomance_map);
+    }
+
+    if (flag & DnnInferLogLevelLayer) {
+        perfomance_map = _infer_request.GetPerformanceCounts ();
+        print_performance_counts (perfomance_map);
+    }
+}
+
+}  // namespace XCam
diff --git a/modules/dnn/dnn_inference_engine.h b/modules/dnn/dnn_inference_engine.h
new file mode 100755
index 0000000..ed8ed36
--- /dev/null
+++ b/modules/dnn/dnn_inference_engine.h
@@ -0,0 +1,280 @@
+/*
+ * dnn_inference_engine.h -  dnn inference engine
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef _XCMA_DNN_INFERENCE_ENGINE_H_
+#define _XCMA_DNN_INFERENCE_ENGINE_H_
+
+#pragma once
+
+#include <vector>
+#include <string>
+#include <inference_engine.hpp>
+
+#include <xcam_std.h>
+
+namespace XCam {
+
+enum DnnInferTargetDeviceType {
+    DnnInferDeviceDefault = 0,
+    DnnInferDeviceBalanced = 1,
+    DnnInferDeviceCPU = 2,
+    DnnInferDeviceGPU = 3,
+    DnnInferDeviceFPGA = 4,
+    DnnInferDeviceMyriad = 5,
+    DnnInferDeviceHetero = 8
+};
+
+enum DnnInferPrecisionType {
+    DnnInferPrecisionMixed = 0,
+    DnnInferPrecisionFP32 = 10,
+    DnnInferPrecisionFP16 = 11,
+    DnnInferPrecisionQ78 = 20,
+    DnnInferPrecisionI16 = 30,
+    DnnInferPrecisionU8 = 40,
+    DnnInferPrecisionI8 = 50,
+    DnnInferPrecisionU16 = 60,
+    DnnInferPrecisionI32 = 70,
+    DnnInferPrecisionCustom = 80,
+    DnnInferPrecisionUnspecified = 255
+};
+
+enum DnnInferLayoutType {
+    DnnInferLayoutAny = 0,
+    DnnInferLayoutNCHW = 1,
+    DnnInferLayoutNHWC = 2,
+    DnnInferLayoutOIHW = 64,
+    DnnInferLayoutC = 96,
+    DnnInferLayoutCHW = 128,
+    DnnInferLayoutHW = 192,
+    DnnInferLayoutNC = 193,
+    DnnInferLayoutCN = 194,
+    DnnInferLayoutBlocked = 200
+};
+
+enum DnnInferMemoryType {
+    DnnInferMemoryDefault = 0,
+    DnnInferMemoryHost = 1,
+    DnnInferMemoryGPU = 2,
+    DnnInferMemoryMYRIAD = 3,
+    DnnInferMemoryShared = 4
+};
+
+enum DnnInferImageFormatType {
+    DnnInferImageFormatBGRPacked = 0,
+    DnnInferImageFormatBGRPlanar,
+    DnnInferImageFormatRGBPacked,
+    DnnInferImageFormatRGBPlanar,
+    DnnInferImageFormatGrayPlanar,
+    DnnInferImageFormatGeneric1D,
+    DnnInferImageFormatGeneric2D,
+    DnnInferImageFormatUnknown = -1
+};
+
+enum DnnInferMode {
+    DnnInferModeSync = 0,
+    DnnInferModeAsync = 1
+};
+
+enum DnnInferDataType {
+    DnnInferDataTypeNonImage = 0,
+    DnnInferDataTypeImage = 1
+};
+
+enum DnnInferLogLevel {
+    DnnInferLogLevelNone = 0x0,
+    DnnInferLogLevelEngine = 0x1,
+    DnnInferLogLevelLayer = 0x2
+};
+
+enum DnnInferInfoType {
+    DnnInferInfoEngine = 0x0,
+    DnnInferInfoPlugin = 0x1,
+    DnnInferInfoNetwork = 0x2
+};
+
+struct DnnInferImageSize {
+    uint32_t image_width;
+    uint32_t image_height;
+
+    DnnInferImageSize () {
+        image_width = 0;
+        image_height = 0;
+    }
+};
+
+struct DnnInferenceEngineInfo {
+    DnnInferInfoType type;
+    int32_t major;
+    int32_t minor;
+    const char* desc;
+    const char* name;
+
+    DnnInferenceEngineInfo () {
+        type = DnnInferInfoEngine;
+        major = 0;
+        minor = 0;
+        desc = NULL;
+        name = NULL;
+    };
+};
+
+#define DNN_INFER_MAX_INPUT_OUTPUT 10
+struct DnnInferInputOutputInfo {
+    uint32_t width[DNN_INFER_MAX_INPUT_OUTPUT];
+    uint32_t height[DNN_INFER_MAX_INPUT_OUTPUT];
+    uint32_t channels[DNN_INFER_MAX_INPUT_OUTPUT];
+    uint32_t object_size[DNN_INFER_MAX_INPUT_OUTPUT];
+    DnnInferPrecisionType precision[DNN_INFER_MAX_INPUT_OUTPUT];
+    DnnInferLayoutType layout[DNN_INFER_MAX_INPUT_OUTPUT];
+    DnnInferDataType data_type[DNN_INFER_MAX_INPUT_OUTPUT];
+    uint32_t batch_size;
+    uint32_t numbers;
+};
+
+struct DnnInferData {
+    void * buffer;
+    uint32_t size;
+    uint32_t width;
+    uint32_t height;
+    uint32_t width_stride;
+    uint32_t height_stride;
+    uint32_t channel_num;
+    uint32_t batch_idx;
+    DnnInferPrecisionType precision;
+    DnnInferMemoryType mem_type;
+    DnnInferImageFormatType image_format;
+    DnnInferDataType data_type;
+
+    DnnInferData () {
+        buffer = NULL;
+    };
+};
+
+struct DnnInferConfig {
+    DnnInferTargetDeviceType target_id;
+    DnnInferInputOutputInfo input_infos;
+    DnnInferInputOutputInfo output_infos;
+
+    char * plugin_path;
+    char * cpu_ext_path;
+    char * cldnn_ext_path;
+    char * model_filename;
+    char * output_layer_name;
+    uint32_t  perf_counter;
+    uint32_t infer_req_num;
+
+    DnnInferConfig () {
+        plugin_path = NULL;
+        cpu_ext_path = NULL;
+        cldnn_ext_path = NULL;
+        model_filename = NULL;
+        output_layer_name = NULL;
+    };
+};
+
+class DnnInferenceEngine {
+public:
+    explicit DnnInferenceEngine (DnnInferConfig& config);
+    virtual ~DnnInferenceEngine ();
+
+    XCamReturn create_model (DnnInferConfig& config);
+    XCamReturn load_model (DnnInferConfig& config);
+
+    XCamReturn get_info (DnnInferenceEngineInfo& info, DnnInferInfoType type);
+
+    XCamReturn set_batch_size (const size_t size);
+    size_t get_batch_size ();
+
+    bool ready_to_start ()  const {
+        return _model_created && _model_loaded;
+    };
+
+    XCamReturn start (bool sync = true);
+
+    size_t get_input_size ();
+    size_t get_output_size ();
+
+    XCamReturn set_input_presion (uint32_t idx, DnnInferPrecisionType precision);
+    DnnInferPrecisionType get_input_presion (uint32_t idx);
+    XCamReturn set_output_presion (uint32_t idx, DnnInferPrecisionType precision);
+    DnnInferPrecisionType get_output_presion (uint32_t idx);
+
+    XCamReturn set_input_layout (uint32_t idx, DnnInferLayoutType layout);
+    XCamReturn set_output_layout (uint32_t idx, DnnInferLayoutType layout);
+
+    uint32_t get_input_image_height () const {
+        return _input_image_height;
+    };
+    uint32_t get_input_image_width () const {
+        return _input_image_width;
+    };
+
+    virtual XCamReturn set_model_input_info (DnnInferInputOutputInfo& info) = 0;
+    virtual XCamReturn get_model_input_info (DnnInferInputOutputInfo& info) = 0;
+
+    virtual XCamReturn set_model_output_info (DnnInferInputOutputInfo& info) = 0;
+    virtual XCamReturn get_model_output_info (DnnInferInputOutputInfo& info) = 0;
+
+    virtual XCamReturn set_inference_data (std::vector<std::string> images) = 0;
+    virtual void* get_inference_results (uint32_t idx, uint32_t& size) = 0;
+
+    std::shared_ptr<uint8_t> read_inference_image (std::string image);
+    void print_log (uint32_t flag);
+
+protected:
+
+    InferenceEngine::TargetDevice get_device_from_string (const std::string& device_name);
+    InferenceEngine::TargetDevice get_device_from_id (DnnInferTargetDeviceType device);
+
+    InferenceEngine::Layout estimate_layout_type (const int ch_num);
+    InferenceEngine::Layout convert_layout_type (DnnInferLayoutType layout);
+    DnnInferLayoutType convert_layout_type (InferenceEngine::Layout layout);
+
+    InferenceEngine::Precision convert_precision_type (DnnInferPrecisionType precision);
+    DnnInferPrecisionType convert_precision_type (InferenceEngine::Precision precision);
+
+    std::string get_filename_prefix (const std::string &file_path);
+
+    void print_performance_counts (const std::map<std::string, InferenceEngine::InferenceEngineProfileInfo>& performance_map);
+
+    XCamReturn set_input_blob (uint32_t idx, DnnInferData& data);
+
+private:
+    template <typename T> XCamReturn copy_image_to_blob (const DnnInferData& data, InferenceEngine::Blob::Ptr& blob, int batch_index);
+    template <typename T> XCamReturn copy_data_to_blob (const DnnInferData& data, InferenceEngine::Blob::Ptr& blob, int batch_index);
+
+protected:
+
+    bool _model_created;
+    bool _model_loaded;
+
+    uint32_t _input_image_width;
+    uint32_t _input_image_height;
+
+    InferenceEngine::InferencePlugin _plugin;
+    InferenceEngine::CNNNetReader _network_reader;
+    InferenceEngine::CNNNetwork _network;
+    InferenceEngine::InferRequest _infer_request;
+    std::vector<InferenceEngine::CNNLayerPtr> _layers;
+};
+
+}  // namespace XCam
+
+#endif //_XCMA_DNN_INFERENCE_ENGINE_H_
diff --git a/modules/dnn/dnn_object_detection.cpp b/modules/dnn/dnn_object_detection.cpp
new file mode 100644
index 0000000..42bf29d
--- /dev/null
+++ b/modules/dnn/dnn_object_detection.cpp
@@ -0,0 +1,264 @@
+/*
+ * dnn_object_detection.cpp -  object detection
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include <format_reader_ptr.h>
+
+#include "dnn_object_detection.h"
+
+using namespace std;
+using namespace InferenceEngine;
+
+namespace XCam {
+
+DnnObjectDetection::DnnObjectDetection (DnnInferConfig& config)
+    : DnnInferenceEngine (config)
+{
+    XCAM_LOG_DEBUG ("DnnObjectDetection::DnnObjectDetection");
+
+    create_model (config);
+}
+
+
+DnnObjectDetection::~DnnObjectDetection ()
+{
+
+}
+
+XCamReturn
+DnnObjectDetection::get_model_input_info (DnnInferInputOutputInfo& info)
+{
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    int id = 0;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    for (auto & item : inputs_info) {
+        auto& input = item.second;
+        const InferenceEngine::SizeVector input_dims = input->getDims ();
+
+        info.width[id] = input_dims[0];
+        info.height[id] = input_dims[1];
+        info.channels[id] = input_dims[2];
+        info.object_size[id] = input_dims[3];
+        info.precision[id] = convert_precision_type (input->getPrecision());
+        info.layout[id] = convert_layout_type (input->getLayout());
+
+        item.second->setPrecision(Precision::U8);
+
+        id++;
+    }
+    info.batch_size = get_batch_size ();
+    info.numbers = inputs_info.size ();
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnObjectDetection::set_model_input_info (DnnInferInputOutputInfo& info)
+{
+    XCAM_LOG_DEBUG ("DnnObjectDetection::set_model_input_info");
+
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+    if (info.numbers != inputs_info.size ()) {
+        XCAM_LOG_ERROR ("Input size is not matched with model info numbers %d !", info.numbers);
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+    int id = 0;
+
+    for (auto & item : inputs_info) {
+        Precision precision = convert_precision_type (info.precision[id]);
+        item.second->setPrecision (precision);
+        Layout layout = convert_layout_type (info.layout[id]);
+        item.second->setLayout (layout);
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnObjectDetection::get_model_output_info (DnnInferInputOutputInfo& info)
+{
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    int id = 0;
+    std::string output_name;
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+    DataPtr output_info;
+    for (const auto& out : outputs_info) {
+        if (out.second->creatorLayer.lock()->type == "DetectionOutput") {
+            output_name = out.first;
+            output_info = out.second;
+            break;
+        }
+    }
+    if (output_info.get ()) {
+        const InferenceEngine::SizeVector output_dims = output_info->getTensorDesc().getDims();
+
+        info.width[id]    = output_dims[0];
+        info.height[id]   = output_dims[1];
+        info.channels[id] = output_dims[2];
+        info.object_size[id] = output_dims[3];
+
+        info.precision[id] = convert_precision_type (output_info->getPrecision());
+        info.layout[id] = convert_layout_type (output_info->getLayout());
+
+        info.batch_size = 1;
+        info.numbers = outputs_info.size ();
+    } else {
+        XCAM_LOG_ERROR ("Get output info error!");
+        return XCAM_RETURN_ERROR_UNKNOWN;
+    }
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnObjectDetection::set_model_output_info (DnnInferInputOutputInfo& info)
+{
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+    if (info.numbers != outputs_info.size ()) {
+        XCAM_LOG_ERROR ("Output size is not matched with model!");
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    int id = 0;
+    for (auto & item : outputs_info) {
+        Precision precision = convert_precision_type (info.precision[id]);
+        item.second->setPrecision (precision);
+        Layout layout = convert_layout_type (info.layout[id]);
+        item.second->setLayout (layout);
+        id++;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+DnnObjectDetection::set_inference_data (std::vector<std::string> images)
+{
+    if (!_model_created) {
+        XCAM_LOG_ERROR ("Please create the model firstly!");
+        return XCAM_RETURN_ERROR_ORDER;
+    }
+
+    uint32_t idx = 0;
+    InputsDataMap inputs_info (_network.getInputsInfo ());
+
+    for (auto & i : images) {
+        FormatReader::ReaderPtr reader (i.c_str ());
+        if (reader.get () == NULL) {
+            XCAM_LOG_WARNING ("Image %d cannot be read!", i);
+            continue;
+        }
+
+        _input_image_width = reader->width ();
+        _input_image_height = reader->height ();
+
+        uint32_t image_width = 0;
+        uint32_t image_height = 0;
+
+        for (auto & item : inputs_info) {
+            image_width = inputs_info[item.first]->getDims ()[0];
+            image_height = inputs_info[item.first]->getDims ()[1];
+        }
+
+        std::shared_ptr<unsigned char> data (reader->getData (image_width, image_height));
+
+        if (data.get () != NULL) {
+            DnnInferData image;
+            image.width = image_width;
+            image.height = image_height;
+            image.width_stride = image_width;
+            image.height_stride = image_height;
+            image.buffer = data.get ();
+            image.channel_num = 3;
+            image.batch_idx = idx;
+            image.image_format = DnnInferImageFormatBGRPacked;
+
+            // set precision & data type
+            image.precision = get_input_presion (idx);
+            image.data_type = DnnInferDataTypeImage;
+
+            set_input_blob (idx, image);
+
+            idx ++;
+        } else {
+            XCAM_LOG_WARNING ("Valid input images were not found!");
+            continue;
+        }
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void*
+DnnObjectDetection::get_inference_results (uint32_t idx, uint32_t& size)
+{
+    if (! _model_created || ! _model_loaded) {
+        XCAM_LOG_ERROR ("Please create and load the model firstly!");
+        return NULL;
+    }
+    uint32_t id = 0;
+    std::string item_name;
+
+    OutputsDataMap outputs_info (_network.getOutputsInfo ());
+    if (idx > outputs_info.size ()) {
+        XCAM_LOG_ERROR ("Output is out of range");
+        return NULL;
+    }
+
+    for (auto & item : outputs_info) {
+        if (item.second->creatorLayer.lock()->type == "DetectionOutput") {
+            item_name = item.first;
+            break;
+        }
+        id++;
+    }
+
+    if (item_name.empty ()) {
+        XCAM_LOG_ERROR ("item name is empty!");
+        return NULL;
+    }
+
+    const Blob::Ptr blob = _infer_request.GetBlob (item_name);
+    float* output_result = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(blob->buffer ());
+
+    size = blob->byteSize ();
+
+    return (reinterpret_cast<void *>(output_result));
+}
+
+}  // namespace XCam
diff --git a/modules/dnn/dnn_object_detection.h b/modules/dnn/dnn_object_detection.h
new file mode 100644
index 0000000..6980858
--- /dev/null
+++ b/modules/dnn/dnn_object_detection.h
@@ -0,0 +1,53 @@
+/*
+ * dnn_object_detection.h -  object detection
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef _XCMA_DNN_OBJECT_DETECTION_H_
+#define _XCMA_DNN_OBJECT_DETECTION_H_
+
+#pragma once
+
+#include <string>
+#include <inference_engine.hpp>
+
+#include <xcam_std.h>
+#include "dnn_inference_engine.h"
+
+namespace XCam {
+
+class DnnObjectDetection
+    : public DnnInferenceEngine
+{
+public:
+    explicit DnnObjectDetection (DnnInferConfig& config);
+    virtual ~DnnObjectDetection ();
+
+    XCamReturn set_model_input_info (DnnInferInputOutputInfo& info);
+    XCamReturn get_model_input_info (DnnInferInputOutputInfo& info);
+
+    XCamReturn set_model_output_info (DnnInferInputOutputInfo& info);
+    XCamReturn get_model_output_info (DnnInferInputOutputInfo& info);
+
+    XCamReturn set_inference_data (std::vector<std::string> images);
+    void* get_inference_results (uint32_t idx, uint32_t& size);
+};
+
+}  // namespace XCam
+
+#endif //_XCMA_DNN_INFERENCE_ENGINE_H_
diff --git a/modules/gles/Makefile.am b/modules/gles/Makefile.am
new file mode 100644
index 0000000..8bdf406
--- /dev/null
+++ b/modules/gles/Makefile.am
@@ -0,0 +1,81 @@
+lib_LTLIBRARIES = libxcam_gles.la
+
+XCAM_GLES_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)                \
+    $(LIBGL_CFLAGS)                 \
+    -I$(top_srcdir)/xcore           \
+    -I$(top_srcdir)/modules         \
+    -I$(top_builddir)/shaders/glslx \
+    $(NULL)
+
+XCAM_GLES_LIBS = \
+    $(LIBGL_LIBS) -lEGL                   \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
+
+if HAVE_OPENCV
+XCAM_GLES_LIBS += $(top_builddir)/modules/ocv/libxcam_ocv.la
+endif
+
+xcam_gles_sources = \
+    gles_std.cpp                \
+    gl_buffer.cpp               \
+    gl_program.cpp              \
+    gl_shader.cpp               \
+    gl_video_buffer.cpp         \
+    gl_compute_program.cpp      \
+    gl_command.cpp              \
+    gl_utils.cpp                \
+    gl_image_shader.cpp         \
+    gl_image_handler.cpp        \
+    gl_copy_handler.cpp         \
+    gl_geomap_handler.cpp       \
+    gl_blender_shaders_priv.cpp \
+    gl_blender.cpp              \
+    gl_stitcher.cpp             \
+    egl/egl_utils.cpp           \
+    egl/egl_base.cpp            \
+    $(NULL)
+
+libxcam_gles_la_SOURCES = \
+    $(xcam_gles_sources) \
+    $(NULL)
+
+libxcam_gles_la_CXXFLAGS = \
+    $(XCAM_GLES_CXXFLAGS) \
+    $(NULL)
+
+libxcam_gles_la_LIBADD = \
+    $(XCAM_GLES_LIBS) \
+    $(NULL)
+
+libxcam_gles_la_LDFLAGS = \
+    $(XCAM_LT_LDFLAGS) \
+    $(NULL)
+
+libxcam_glesincludedir = $(includedir)/xcam/gles
+
+nobase_libxcam_glesinclude_HEADERS = \
+    gles_std.h           \
+    gl_buffer.h          \
+    gl_program.h         \
+    gl_shader.h          \
+    gl_video_buffer.h    \
+    gl_compute_program.h \
+    gl_command.h         \
+    gl_utils.h           \
+    gl_image_shader.h    \
+    gl_image_handler.h   \
+    gl_copy_handler.h    \
+    gl_geomap_handler.h  \
+    gl_blender.h         \
+    gl_stitcher.h        \
+    egl/egl_utils.h      \
+    egl/egl_base.h       \
+    $(NULL)
+
+noinst_HEADERS = \
+    gl_blender_shaders_priv.h \
+    $(NULL)
+
+libxcam_gles_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/gles/egl/egl_base.cpp b/modules/gles/egl/egl_base.cpp
new file mode 100644
index 0000000..6ee0b4c
--- /dev/null
+++ b/modules/gles/egl/egl_base.cpp
@@ -0,0 +1,195 @@
+/*
+ * egl_base.cpp - EGL base implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "egl_base.h"
+
+namespace XCam {
+
+EGLBase::EGLBase ()
+    : _display (EGL_NO_DISPLAY)
+    , _context (EGL_NO_CONTEXT)
+    , _surface (EGL_NO_SURFACE)
+{
+}
+
+EGLBase::~EGLBase ()
+{
+    if (_display != EGL_NO_DISPLAY) {
+        if (_context != EGL_NO_CONTEXT) {
+            destroy_context (_display, _context);
+            _context = EGL_NO_CONTEXT;
+        }
+
+        if (_surface != EGL_NO_SURFACE) {
+            destroy_surface (_display, _surface);
+            _surface = EGL_NO_SURFACE;
+        }
+
+        terminate (_display);
+        _display = EGL_NO_DISPLAY;
+    }
+}
+
+bool
+EGLBase::init ()
+{
+    bool ret = get_display (EGL_DEFAULT_DISPLAY, _display);
+    XCAM_FAIL_RETURN (ERROR, ret, false, "EGLInit: get display failed");
+
+    EGLint major, minor;
+    ret = initialize (_display, &major, &minor);
+    XCAM_FAIL_RETURN (ERROR, ret, false, "EGLInit: EGL initialize failed");
+    XCAM_LOG_INFO ("EGL version: %d.%d", major, minor);
+
+    EGLConfig configs;
+    EGLint num_config;
+    EGLint cfg_attribs[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, EGL_NONE};
+    ret = choose_config (_display, cfg_attribs, &configs, 1, &num_config);
+    XCAM_FAIL_RETURN (ERROR, ret, false, "EGLInit: choose config failed");
+
+    EGLint ctx_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+    ret = create_context (_display, configs, EGL_NO_CONTEXT, ctx_attribs, _context);
+    XCAM_FAIL_RETURN (ERROR, ret, false, "EGLInit: create context failed");
+
+    ret = make_current (_display, _surface, _surface, _context);
+    XCAM_FAIL_RETURN (ERROR, ret, false, "EGLInit: make current failed");
+
+    return true;
+}
+
+bool
+EGLBase::get_display (NativeDisplayType native_display, EGLDisplay &display)
+{
+    display = eglGetDisplay (native_display);
+    XCAM_FAIL_RETURN (
+        ERROR, display != EGL_NO_DISPLAY, false,
+        "EGLInit: get display failed");
+    return true;
+}
+
+bool
+EGLBase::initialize (EGLDisplay display, EGLint *major, EGLint *minor)
+{
+    EGLBoolean ret = eglInitialize (display, major, minor);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: initialize failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    return true;
+}
+
+bool
+EGLBase::choose_config (
+    EGLDisplay display, EGLint const *attribs, EGLConfig *configs,
+    EGLint config_size, EGLint *num_config)
+{
+    EGLBoolean ret = eglChooseConfig (display, attribs, configs, config_size, num_config);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: choose config failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    return true;
+}
+
+bool
+EGLBase::create_context (
+    EGLDisplay display, EGLConfig config, EGLContext share_context, EGLint const *attribs,
+    EGLContext &context)
+{
+    context = eglCreateContext (display, config, share_context, attribs);
+    XCAM_FAIL_RETURN (
+        ERROR, context != EGL_NO_CONTEXT, false,
+        "EGLInit: create context failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    return true;
+}
+
+bool
+EGLBase::create_window_surface (
+    EGLDisplay display, EGLConfig config, NativeWindowType native_window, EGLint const *attribs,
+    EGLSurface &surface)
+{
+    surface = eglCreateWindowSurface (display, config, native_window, attribs);
+    XCAM_FAIL_RETURN (
+        ERROR, surface != EGL_NO_SURFACE, false,
+        "EGLInit: create window surface failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    return true;
+}
+
+bool
+EGLBase::make_current (EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context)
+{
+    EGLBoolean ret = eglMakeCurrent (display, draw, read, context);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: make current failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    return true;
+}
+
+bool
+EGLBase::swap_buffers (EGLDisplay display, EGLSurface surface)
+{
+    EGLBoolean ret = eglSwapBuffers (display, surface);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: swap buffers failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    return true;
+}
+
+bool
+EGLBase::destroy_context (EGLDisplay display, EGLContext &context)
+{
+    EGLBoolean ret = eglDestroyContext (display, context);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: destroy context failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    XCAM_FAIL_RETURN (ERROR, ret == EGL_TRUE, false, "EGLInit: destroy context failed");
+    return true;
+}
+
+bool
+EGLBase::destroy_surface (EGLDisplay display, EGLSurface &surface)
+{
+    EGLBoolean ret = eglDestroySurface (display, surface);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: destroy surface failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    XCAM_FAIL_RETURN (ERROR, ret == EGL_TRUE, false, "EGLInit: destroy surface failed");
+    return true;
+}
+
+bool
+EGLBase::terminate (EGLDisplay display)
+{
+    EGLBoolean ret = eglTerminate (display);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == EGL_TRUE, false,
+        "EGLInit: terminate failed, error flag: %s",
+        EGL::error_string (EGL::get_error ()));
+    XCAM_FAIL_RETURN (ERROR, ret == EGL_TRUE, false, "EGLInit: terminate failed");
+    return true;
+}
+
+}
diff --git a/modules/gles/egl/egl_base.h b/modules/gles/egl/egl_base.h
new file mode 100644
index 0000000..baa9a10
--- /dev/null
+++ b/modules/gles/egl/egl_base.h
@@ -0,0 +1,61 @@
+/*
+ * egl_base.h - EGL base class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_EGL_BASE_H
+#define XCAM_EGL_BASE_H
+
+#include <gles/egl/egl_utils.h>
+
+namespace XCam {
+
+class EGLBase {
+public:
+    explicit EGLBase ();
+    ~EGLBase ();
+
+    bool init ();
+
+    bool get_display (NativeDisplayType native_display, EGLDisplay &display);
+    bool initialize (EGLDisplay display, EGLint *major, EGLint *minor);
+    bool choose_config (
+        EGLDisplay display, EGLint const *attribs, EGLConfig *configs,
+        EGLint config_size, EGLint *num_config);
+    bool create_context (
+        EGLDisplay display, EGLConfig config, EGLContext share_context, EGLint const *attribs,
+        EGLContext &context);
+    bool create_window_surface (
+        EGLDisplay display, EGLConfig config, NativeWindowType native_window, EGLint const *attribs,
+        EGLSurface &surface);
+    bool make_current (EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
+    bool swap_buffers (EGLDisplay display, EGLSurface surface);
+
+    bool destroy_context (EGLDisplay display, EGLContext &context);
+    bool destroy_surface (EGLDisplay display, EGLSurface &surface);
+    bool terminate (EGLDisplay display);
+
+private:
+    EGLDisplay        _display;
+    EGLContext        _context;
+    EGLSurface        _surface;
+};
+
+}
+
+#endif // XCAM_EGL_BASE_H
diff --git a/modules/gles/egl/egl_utils.cpp b/modules/gles/egl/egl_utils.cpp
new file mode 100644
index 0000000..71bc4a7
--- /dev/null
+++ b/modules/gles/egl/egl_utils.cpp
@@ -0,0 +1,87 @@
+/*
+ * egl_utils.cpp - EGL utilities
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "egl_utils.h"
+
+namespace XCam {
+namespace EGL {
+
+const char *
+error_string (EGLint flag)
+{
+    static char str[64] = {'\0'};
+
+    switch (flag)
+    {
+    case EGL_SUCCESS:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_SUCCESS");
+        break;
+    case EGL_NOT_INITIALIZED:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_NOT_INITIALIZED");
+        break;
+    case EGL_BAD_ACCESS:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_ACCESS");
+        break;
+    case EGL_BAD_ALLOC:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_ALLOC");
+        break;
+    case EGL_BAD_ATTRIBUTE:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_ATTRIBUTE");
+        break;
+    case EGL_BAD_CONTEXT:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_CONTEXT");
+        break;
+    case EGL_BAD_CONFIG:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_CONFIG");
+        break;
+    case EGL_BAD_CURRENT_SURFACE:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_CURRENT_SURFACE");
+        break;
+    case EGL_BAD_DISPLAY:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_DISPLAY");
+        break;
+    case EGL_BAD_SURFACE:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_SURFACE");
+        break;
+    case EGL_BAD_MATCH:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_MATCH");
+        break;
+    case EGL_BAD_PARAMETER:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_PARAMETER");
+        break;
+    case EGL_BAD_NATIVE_PIXMAP:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_NATIVE_PIXMAP");
+        break;
+    case EGL_BAD_NATIVE_WINDOW:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_BAD_NATIVE_WINDOW");
+        break;
+    case EGL_CONTEXT_LOST:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "EGL_CONTEXT_LOST");
+        break;
+    default:
+        snprintf (str, sizeof (str), "unknown flag:0x%04x", flag);
+        XCAM_LOG_ERROR ("%s", str);
+    }
+
+    return str;
+}
+
+}
+}
diff --git a/modules/gles/egl/egl_utils.h b/modules/gles/egl/egl_utils.h
new file mode 100644
index 0000000..601f171
--- /dev/null
+++ b/modules/gles/egl/egl_utils.h
@@ -0,0 +1,40 @@
+/*
+ * egl_utils.h - EGL utilities
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_EGL_UTILS_H
+#define XCAM_EGL_UTILS_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <xcam_std.h>
+
+namespace XCam {
+namespace EGL {
+
+inline EGLint get_error ()
+{
+    return eglGetError ();
+}
+
+const char *error_string (EGLint flag);
+
+}
+}
+#endif // XCAM_EGL_UTILS_H
diff --git a/modules/gles/gl_blender.cpp b/modules/gles/gl_blender.cpp
new file mode 100644
index 0000000..7f83a47
--- /dev/null
+++ b/modules/gles/gl_blender.cpp
@@ -0,0 +1,852 @@
+/*
+ * gl_blender.cpp - gl blender implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "xcam_utils.h"
+#include "image_file_handle.h"
+#include "gl_utils.h"
+#include "gl_video_buffer.h"
+#include "gl_blender_shaders_priv.h"
+#include "gl_blender.h"
+#include <map>
+
+#define OVERLAP_POOL_SIZE 6
+#define LAP_POOL_SIZE 4
+
+#define GAUSS_RADIUS 2
+#define GAUSS_DIAMETER  ((GAUSS_RADIUS)*2+1)
+
+const float gauss_coeffs[GAUSS_DIAMETER] = {0.152f, 0.222f, 0.252f, 0.222f, 0.152f};
+
+#define DUMP_BUFFER 0
+
+#define CHECK_RET(ret, format, ...) \
+    if ((ret) < XCAM_RETURN_NO_ERROR) {          \
+        XCAM_LOG_ERROR (format, ## __VA_ARGS__); \
+    }
+
+namespace XCam {
+
+using namespace XCamGLShaders;
+
+#if DUMP_BUFFER
+#define dump_buf dump_buf_perfix_path
+
+static void
+dump_level_buf (const SmartPtr<VideoBuffer> &buf, const char *name, uint32_t level, uint32_t idx)
+{
+    XCAM_ASSERT (name);
+
+    char file_name[256];
+    snprintf (file_name, 256, "%s-L%d-Idx%d", name, level, idx);
+    dump_buf_perfix_path (buf, file_name);
+}
+#else
+static void
+dump_level_buf (const SmartPtr<VideoBuffer> &buf, ...) {
+    XCAM_UNUSED (buf);
+}
+
+static void
+dump_buf (const SmartPtr<VideoBuffer> &buf, ...) {
+    XCAM_UNUSED (buf);
+}
+#endif
+
+DECLARE_WORK_CALLBACK (CbGaussScalePyr, GLBlender, gauss_scale_done);
+DECLARE_WORK_CALLBACK (CbLapTransPyr, GLBlender, lap_trans_done);
+DECLARE_WORK_CALLBACK (CbBlendPyr, GLBlender, blend_done);
+DECLARE_WORK_CALLBACK (CbReconstructPyr, GLBlender, reconstruct_done);
+
+namespace GLBlenderPriv {
+
+typedef std::map<void*, SmartPtr<GLBlendPyrShader::Args>> MapBlendArgs;
+typedef std::map<void*, SmartPtr<GLReconstructPyrShader::Args>> MapReconstructArgs;
+
+struct PyramidResource {
+    SmartPtr<BufferPool>                overlap_pool;
+    SmartPtr<GLGaussScalePyrShader>     gauss_scale[GLBlender::BufIdxCount];
+    SmartPtr<GLLapTransPyrShader>       lap_trans[GLBlender::BufIdxCount];
+    SmartPtr<GLReconstructPyrShader>    reconstruct;
+    SmartPtr<GLBuffer>                  coef_mask;
+    MapReconstructArgs                  reconstruct_args;
+};
+
+class BlenderPrivConfig {
+public:
+    PyramidResource               pyr_layer[XCAM_GL_PYRAMID_MAX_LEVEL];
+    uint32_t                      pyr_levels;
+
+    SmartPtr<GLBlendPyrShader>    top_level_blend;
+    SmartPtr<BufferPool>          first_lap_pool;
+    SmartPtr<GLBuffer>            first_mask;
+
+    Mutex                         map_args_mutex;
+    MapBlendArgs                  blend_args;
+
+private:
+    GLBlender                    *_blender;
+    SmartPtr<GLComputeProgram>    _sync_prog;
+
+public:
+    BlenderPrivConfig (GLBlender *blender, uint32_t level)
+        : pyr_levels (level - 1)
+        , _blender (blender)
+    {
+        XCAM_ASSERT (level >= 2 && level <= XCAM_GL_PYRAMID_MAX_LEVEL);
+    }
+
+    XCamReturn init_first_masks (uint32_t width, uint32_t height);
+    XCamReturn scale_down_masks (uint32_t level, uint32_t width, uint32_t height);
+
+    XCamReturn start_gauss_scale (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<VideoBuffer> &in_buf,
+        uint32_t level, GLBlender::BufIdx idx);
+
+    XCamReturn start_lap_trans (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<GLGaussScalePyrShader::Args> &gauss_scale_args,
+        uint32_t level, GLBlender::BufIdx idx);
+
+    XCamReturn start_blend (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<VideoBuffer> &buf, GLBlender::BufIdx idx);
+
+    XCamReturn start_reconstruct_by_lap (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<VideoBuffer> &lap,
+        uint32_t level, GLBlender::BufIdx idx);
+    XCamReturn start_reconstruct_by_gauss (
+        const SmartPtr<ImageHandler::Parameters> &param,
+        const SmartPtr<VideoBuffer> &prev_blend_buf, uint32_t level);
+    XCamReturn start_reconstruct (const SmartPtr<GLReconstructPyrShader::Args> &args, uint32_t level);
+    XCamReturn stop ();
+
+    const SmartPtr<GLComputeProgram> &get_sync_prog ();
+};
+
+XCamReturn
+BlenderPrivConfig::stop ()
+{
+    for (uint32_t i = 0; i < pyr_levels; ++i) {
+        pyr_layer[i].gauss_scale[GLBlender::Idx0].release ();
+        pyr_layer[i].gauss_scale[GLBlender::Idx1].release ();
+        pyr_layer[i].lap_trans[GLBlender::Idx0].release ();
+        pyr_layer[i].lap_trans[GLBlender::Idx1].release ();
+        pyr_layer[i].reconstruct.release ();
+
+        if (pyr_layer[i].overlap_pool.ptr ()) {
+            pyr_layer[i].overlap_pool->stop ();
+        }
+    }
+
+    top_level_blend.release ();
+    if (first_lap_pool.ptr ()) {
+        first_lap_pool->stop ();
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+const SmartPtr<GLComputeProgram> &
+BlenderPrivConfig::get_sync_prog ()
+{
+    if (_sync_prog.ptr ())
+        return _sync_prog;
+
+    _sync_prog = GLComputeProgram::create_compute_program ("sync_program");
+    XCAM_FAIL_RETURN (ERROR, _sync_prog.ptr (), _sync_prog, "create sync program failed");
+
+    return _sync_prog;
+}
+
+XCamReturn
+BlenderPrivConfig::init_first_masks (uint32_t width, uint32_t height)
+{
+    XCAM_ASSERT (!first_mask.ptr ());
+    XCAM_ASSERT (width && (width % GL_BLENDER_ALIGN_X == 0));
+    XCAM_FAIL_RETURN (
+        ERROR, height == 1, XCAM_RETURN_ERROR_PARAM,
+        "blender(%s) mask buffer only supports one-dimensional array", XCAM_STR (_blender->get_name ()));
+
+    uint32_t buf_size = width * sizeof (uint8_t);
+    SmartPtr<GLBuffer> buf = GLBuffer::create_buffer (GL_SHADER_STORAGE_BUFFER, NULL, buf_size);
+    XCAM_ASSERT (buf.ptr ());
+
+    GLBufferDesc desc;
+    desc.width = width;
+    desc.height = 1;
+    desc.size = buf_size;
+    buf->set_buffer_desc (desc);
+
+    std::vector<float> gauss_table;
+    uint32_t quater = width / 4;
+    XCAM_ASSERT (quater > 1);
+
+    get_gauss_table (quater, (quater + 1) / 4.0f, gauss_table, false);
+    for (uint32_t i = 0; i < gauss_table.size (); ++i) {
+        float value = ((i < quater) ? (128.0f * (2.0f - gauss_table[i])) : (128.0f * gauss_table[i]));
+        value = XCAM_CLAMP (value, 0.0f, 255.0f);
+        gauss_table[i] = value;
+    }
+
+    uint8_t *mask_ptr = (uint8_t *) buf->map_range (0, buf_size, GL_MAP_WRITE_BIT);
+    XCAM_FAIL_RETURN (ERROR, mask_ptr, XCAM_RETURN_ERROR_PARAM, "map range failed");
+
+    uint32_t gauss_start_pos = (width - gauss_table.size ()) / 2;
+    uint32_t idx = 0;
+    for (idx = 0; idx < gauss_start_pos; ++idx) {
+        mask_ptr[idx] = 255;
+    }
+    for (uint32_t i = 0; i < gauss_table.size (); ++idx, ++i) {
+        mask_ptr[idx] = (uint8_t) gauss_table[i];
+    }
+    for (; idx < width; ++idx) {
+        mask_ptr[idx] = 0;
+    }
+    buf->unmap ();
+
+    first_mask = buf;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderPrivConfig::scale_down_masks (uint32_t level, uint32_t width, uint32_t height)
+{
+    XCAM_ASSERT (width && (width % GL_BLENDER_ALIGN_X == 0));
+    XCAM_FAIL_RETURN (
+        ERROR, height == 1, XCAM_RETURN_ERROR_PARAM,
+        "blender(%s) mask buffer only supports one-dimensional array", XCAM_STR (_blender->get_name ()));
+
+    uint32_t buf_size = width * sizeof (uint8_t);
+    SmartPtr<GLBuffer> buf = GLBuffer::create_buffer (GL_SHADER_STORAGE_BUFFER, NULL, buf_size);
+    XCAM_ASSERT (buf.ptr ());
+
+    GLBufferDesc desc;
+    desc.width = width;
+    desc.height = 1;
+    desc.size = buf_size;
+    buf->set_buffer_desc (desc);
+
+    SmartPtr<GLBuffer> prev_mask;
+    if (level == 0) {
+        prev_mask = first_mask;
+    } else {
+        prev_mask = pyr_layer[level - 1].coef_mask;
+    }
+    XCAM_ASSERT (prev_mask.ptr ());
+
+    const GLBufferDesc prev_desc = prev_mask->get_buffer_desc ();
+    uint8_t *prev_ptr = (uint8_t *) prev_mask->map_range (0, prev_desc.size, GL_MAP_READ_BIT);
+    XCAM_FAIL_RETURN (ERROR, prev_ptr, XCAM_RETURN_ERROR_PARAM, "map range failed");
+
+    uint8_t *cur_ptr = (uint8_t *) buf->map_range (0, desc.size, GL_MAP_WRITE_BIT);
+    XCAM_FAIL_RETURN (ERROR, cur_ptr, XCAM_RETURN_ERROR_PARAM, "map range failed");
+
+    for (uint32_t i = 0; i < desc.width; ++i) {
+        int prev_start = i * 2 - 2;
+        float sum = 0.0f;
+
+        for (int j = 0; j < GAUSS_DIAMETER; ++j) {
+            int prev_idx = XCAM_CLAMP (prev_start + j, 0, (int)prev_desc.width);
+            sum += prev_ptr[prev_idx] * gauss_coeffs[j];
+        }
+
+        cur_ptr[i] = XCAM_CLAMP (sum, 0.0f, 255.0f);
+    }
+
+    buf->unmap ();
+    prev_mask->unmap ();
+
+    pyr_layer[level].coef_mask = buf;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderPrivConfig::start_gauss_scale (
+    const SmartPtr<ImageHandler::Parameters> &param,
+    const SmartPtr<VideoBuffer> &in_buf,
+    uint32_t level, GLBlender::BufIdx idx)
+{
+    XCAM_ASSERT (in_buf.ptr ());
+    XCAM_ASSERT (level < pyr_levels);
+    XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+    XCAM_ASSERT (pyr_layer[level].gauss_scale[idx].ptr ());
+    XCAM_ASSERT (pyr_layer[level].overlap_pool.ptr ());
+
+    SmartPtr<VideoBuffer> out_buf = pyr_layer[level].overlap_pool->get_buffer ();
+    XCAM_FAIL_RETURN (
+        ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+        "blender(%s) start_gauss_scale failed, output buffer is empty, level:%d, idx:%d",
+        XCAM_STR (_blender->get_name ()), level, (int)idx);
+
+    SmartPtr<GLGaussScalePyrShader::Args> args = new GLGaussScalePyrShader::Args (param, level, idx);
+    XCAM_ASSERT (args.ptr ());
+    args->in_glbuf = get_glbuffer (in_buf);
+    args->out_glbuf = get_glbuffer (out_buf);
+    args->out_video_buf = out_buf;
+
+    if (level == 0) {
+        const Rect area = _blender->get_input_merge_area (idx);
+        XCAM_FAIL_RETURN (
+            ERROR, 
+            area.pos_y == 0 && area.width && area.height &&
+            area.pos_x % GL_BLENDER_ALIGN_X == 0 &&
+            area.width % GL_BLENDER_ALIGN_X == 0 &&
+            area.height % GL_BLENDER_ALIGN_Y == 0,
+            XCAM_RETURN_ERROR_PARAM,
+            "blender(%s) invalid input merge area, pos_x:%d, pos_y:%d, width:%d, height:%d, level:%d, idx:%d",
+            XCAM_STR (_blender->get_name ()), area.pos_x, area.pos_y, area.width, area.height, level, (int)idx);
+
+        args->merge_area = area;
+    } else {
+        const VideoBufferInfo &info = in_buf->get_video_info ();
+        XCAM_FAIL_RETURN (
+            ERROR, 
+            info.width && info.height &&
+            info.width % GL_BLENDER_ALIGN_X == 0 &&
+            info.height % GL_BLENDER_ALIGN_Y == 0,
+            XCAM_RETURN_ERROR_PARAM,
+            "blender(%s) invalid buffer info, width:%d, height:%d, level:%d, idx:%d",
+            XCAM_STR (_blender->get_name ()), info.width, info.height, level, (int)idx);
+
+        args->merge_area = Rect (0, 0, info.width, info.height);
+    }
+
+    return pyr_layer[level].gauss_scale[idx]->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_lap_trans (
+    const SmartPtr<ImageHandler::Parameters> &param,
+    const SmartPtr<GLGaussScalePyrShader::Args> &gauss_scale_args,
+    uint32_t level, GLBlender::BufIdx idx)
+{
+    XCAM_ASSERT (level < pyr_levels);
+    XCAM_ASSERT (pyr_layer[level].lap_trans[idx].ptr ());
+    XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+
+    SmartPtr<VideoBuffer> out_buf;
+    if (level == 0) {
+        XCAM_ASSERT (first_lap_pool.ptr ());
+        out_buf = first_lap_pool->get_buffer ();
+    } else {
+        XCAM_ASSERT (pyr_layer[level - 1].overlap_pool.ptr ());
+        out_buf = pyr_layer[level - 1].overlap_pool->get_buffer ();
+    }
+    XCAM_FAIL_RETURN (
+        ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+        "blender(%s) start_lap_trans failed, output buffer is empty, level:%d, idx:%d",
+        XCAM_STR (_blender->get_name ()), level, (int)idx);
+
+    SmartPtr<GLLapTransPyrShader::Args> args = new GLLapTransPyrShader::Args (param, level, idx);
+    XCAM_ASSERT (args.ptr ());
+    args->in_glbuf = gauss_scale_args->in_glbuf;
+    args->gaussscale_glbuf = gauss_scale_args->out_glbuf;
+    args->out_glbuf = get_glbuffer (out_buf);
+    args->merge_area = gauss_scale_args->merge_area;
+    args->out_video_buf = out_buf;
+
+    return pyr_layer[level].lap_trans[idx]->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_blend (
+    const SmartPtr<ImageHandler::Parameters> &param,
+    const SmartPtr<VideoBuffer> &buf, GLBlender::BufIdx idx)
+{
+    XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+    XCAM_ASSERT (top_level_blend.ptr ());
+
+    uint32_t top_level = pyr_levels - 1;
+    XCAM_ASSERT (pyr_layer[top_level].overlap_pool.ptr ());
+    XCAM_ASSERT (pyr_layer[top_level].coef_mask.ptr ());
+
+    SmartPtr<GLBlendPyrShader::Args> args;
+    {
+        SmartLock locker (map_args_mutex);
+        MapBlendArgs::iterator i = blend_args.find (param.ptr ());
+        if (i == blend_args.end ()) {
+            args = new GLBlendPyrShader::Args (param);
+            XCAM_ASSERT (args.ptr ());
+            blend_args.insert (std::make_pair((void*)param.ptr (), args));
+            XCAM_LOG_DEBUG ("blender(%s) init blend args, idx:%d", XCAM_STR (_blender->get_name ()), (int)idx);
+        } else {
+            args = (*i).second;
+        }
+
+        if (idx == GLBlender::Idx0) {
+            args->in0_glbuf = get_glbuffer (buf);
+        } else {
+            args->in1_glbuf = get_glbuffer (buf);
+        }
+
+        if (!args->in0_glbuf.ptr () || !args->in1_glbuf.ptr ())
+            return XCAM_RETURN_BYPASS;
+
+        blend_args.erase (i);
+    }
+
+    args->mask_glbuf = pyr_layer[top_level].coef_mask;
+
+    SmartPtr<VideoBuffer> out_buf = pyr_layer[top_level].overlap_pool->get_buffer ();
+    XCAM_FAIL_RETURN (
+        ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+        "blender(%s) start_blend failed, output buffer is empty, idx:%d",
+        XCAM_STR (_blender->get_name ()), (int)idx);
+    args->out_glbuf = get_glbuffer (out_buf);
+    args->out_video_buf = out_buf;
+
+    return top_level_blend->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_reconstruct (
+    const SmartPtr<GLReconstructPyrShader::Args> &args, uint32_t level)
+{
+    XCAM_ASSERT (args.ptr ());
+    XCAM_ASSERT (level < pyr_levels);
+    XCAM_ASSERT (pyr_layer[level].reconstruct.ptr ());
+    XCAM_ASSERT (args->lap0_glbuf.ptr () && args->lap1_glbuf.ptr () && args->prev_blend_glbuf.ptr ());
+
+    SmartPtr<VideoBuffer> out_buf;
+    if (level == 0) {
+        const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+        XCAM_ASSERT (param.ptr () && param->out_buf.ptr ());
+        out_buf = param->out_buf;
+
+        XCAM_ASSERT (first_mask.ptr ());
+        args->mask_glbuf = first_mask;
+
+        const Rect area = _blender->get_merge_window ();
+        XCAM_FAIL_RETURN (
+            ERROR, 
+            area.pos_y == 0 && area.width && area.height &&
+            area.pos_x % GL_BLENDER_ALIGN_X == 0 &&
+            area.width % GL_BLENDER_ALIGN_X == 0 &&
+            area.height % GL_BLENDER_ALIGN_Y == 0,
+            XCAM_RETURN_ERROR_PARAM,
+            "blender(%s) invalid output merge area, pos_x:%d, pos_y:%d, width:%d, height:%d, level:%d",
+            XCAM_STR (_blender->get_name ()), area.pos_x, area.pos_y, area.width, area.height, level);
+
+        args->merge_area = area;
+    } else {
+        out_buf = pyr_layer[level - 1].overlap_pool->get_buffer ();
+        XCAM_FAIL_RETURN (
+            ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
+            "blender(%s) start_reconstruct failed, out buffer is empty, level:%d",
+            XCAM_STR (_blender->get_name ()), level);
+
+        XCAM_ASSERT (pyr_layer[level - 1].coef_mask.ptr ());
+        args->mask_glbuf = pyr_layer[level - 1].coef_mask;
+
+        const VideoBufferInfo &info = out_buf->get_video_info ();
+        XCAM_FAIL_RETURN (
+            ERROR, 
+            info.width && info.height &&
+            info.width % GL_BLENDER_ALIGN_X == 0 &&
+            info.height % GL_BLENDER_ALIGN_Y == 0,
+            XCAM_RETURN_ERROR_PARAM,
+            "blender(%s) invalid buffer info, width:%d, height:%d, level:%d",
+            XCAM_STR (_blender->get_name ()), info.width, info.height, level);
+
+        args->merge_area = Rect (0, 0, info.width, info.height);
+    }
+    args->out_glbuf = get_glbuffer (out_buf);
+    args->out_video_buf = out_buf;
+
+    return pyr_layer[level].reconstruct->work (args);
+}
+
+XCamReturn
+BlenderPrivConfig::start_reconstruct_by_gauss (
+    const SmartPtr<ImageHandler::Parameters> &param,
+    const SmartPtr<VideoBuffer> &prev_blend_buf, uint32_t level)
+{
+    XCAM_ASSERT (prev_blend_buf.ptr ());
+    XCAM_ASSERT (level < pyr_levels);
+
+    SmartPtr<GLReconstructPyrShader::Args> args;
+    {
+        SmartLock locker (map_args_mutex);
+        MapReconstructArgs::iterator i = pyr_layer[level].reconstruct_args.find (param.ptr ());
+        if (i == pyr_layer[level].reconstruct_args.end ()) {
+            args = new GLReconstructPyrShader::Args (param, level);
+            XCAM_ASSERT (args.ptr ());
+            pyr_layer[level].reconstruct_args.insert (std::make_pair((void*)param.ptr (), args));
+            XCAM_LOG_DEBUG ("blender(%s) init reconstruct_args, level:%d", XCAM_STR (_blender->get_name ()), level);
+        } else {
+            args = (*i).second;
+        }
+
+        args->prev_blend_glbuf = get_glbuffer (prev_blend_buf);
+
+        if (!args->lap0_glbuf.ptr () || !args->lap1_glbuf.ptr ())
+            return XCAM_RETURN_BYPASS;
+
+        pyr_layer[level].reconstruct_args.erase (i);
+    }
+
+    return start_reconstruct (args, level);
+}
+
+XCamReturn
+BlenderPrivConfig::start_reconstruct_by_lap (
+    const SmartPtr<ImageHandler::Parameters> &param,
+    const SmartPtr<VideoBuffer> &lap,
+    uint32_t level, GLBlender::BufIdx idx)
+{
+    XCAM_ASSERT (lap.ptr ());
+    XCAM_ASSERT (level < pyr_levels);
+    XCAM_ASSERT (idx < GLBlender::BufIdxCount);
+
+    SmartPtr<GLReconstructPyrShader::Args> args;
+    {
+        SmartLock locker (map_args_mutex);
+        MapReconstructArgs::iterator i = pyr_layer[level].reconstruct_args.find (param.ptr ());
+        if (i == pyr_layer[level].reconstruct_args.end ()) {
+            args = new GLReconstructPyrShader::Args (param, level);
+            XCAM_ASSERT (args.ptr ());
+            pyr_layer[level].reconstruct_args.insert (std::make_pair((void*)param.ptr (), args));
+            XCAM_LOG_DEBUG ("blender(%s) init reconstruct_args, level:%d", XCAM_STR (_blender->get_name ()), level);
+        } else {
+            args = (*i).second;
+        }
+
+        if (idx == GLBlender::Idx0)
+            args->lap0_glbuf = get_glbuffer (lap);
+        else
+            args->lap1_glbuf = get_glbuffer (lap);
+
+        if (!args->lap0_glbuf.ptr () || !args->lap1_glbuf.ptr () || !args->prev_blend_glbuf.ptr ())
+            return XCAM_RETURN_BYPASS;
+
+        pyr_layer[level].reconstruct_args.erase (i);
+    }
+
+    return start_reconstruct (args, level);
+}
+
+}
+
+GLBlender::GLBlender (const char *name)
+    : GLImageHandler (name)
+    , Blender (GL_BLENDER_ALIGN_X, GL_BLENDER_ALIGN_Y)
+{
+    SmartPtr<GLBlenderPriv::BlenderPrivConfig> config =
+        new GLBlenderPriv::BlenderPrivConfig (this, XCAM_GL_PYRAMID_DEFAULT_LEVEL);
+    XCAM_ASSERT (config.ptr ());
+    _priv_config = config;
+}
+
+GLBlender::~GLBlender ()
+{
+}
+
+XCamReturn
+GLBlender::finish ()
+{
+    const SmartPtr<GLComputeProgram> prog = _priv_config->get_sync_prog ();
+    XCAM_ASSERT (prog.ptr ());
+    prog->finish ();
+
+    return GLImageHandler::finish ();
+}
+
+XCamReturn
+GLBlender::terminate ()
+{
+    _priv_config->stop ();
+    return GLImageHandler::terminate ();
+}
+
+XCamReturn
+GLBlender::blend (
+    const SmartPtr<VideoBuffer> &in0,
+    const SmartPtr<VideoBuffer> &in1,
+    SmartPtr<VideoBuffer> &out_buf)
+{
+    XCAM_ASSERT (in0.ptr () && in1.ptr ());
+
+    SmartPtr<BlenderParam> param = new BlenderParam (in0, in1, out_buf);
+    XCAM_ASSERT (param.ptr ());
+
+    XCamReturn ret = execute_buffer (param, true);
+
+    finish ();
+    if (xcam_ret_is_ok (ret) && !out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+XCamReturn
+GLBlender::start_work (const SmartPtr<ImageHandler::Parameters> &base)
+{
+    XCAM_ASSERT (base.ptr ());
+    SmartPtr<BlenderParam> param = base.dynamic_cast_ptr<BlenderParam> ();
+    XCAM_ASSERT (param.ptr ());
+    XCAM_ASSERT (param->in_buf.ptr () && param->in1_buf.ptr () && param->out_buf.ptr ());
+
+    dump_level_buf (param->in_buf, "input", 0, 0);
+    dump_level_buf (param->in1_buf, "input", 0, 1);
+
+    // start gauss scale level:0 idx:0
+    XCamReturn ret = _priv_config->start_gauss_scale (param, param->in_buf, 0, GLBlender::Idx0);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "blender(%s) start gauss scale failed, level:0 idx:0", XCAM_STR (get_name ()));
+
+    // start gauss scale level:0 idx:1
+    ret = _priv_config->start_gauss_scale (param, param->in1_buf, 0, GLBlender::Idx1);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "blender(%s) start gauss scale failed, level:0 idx:1", XCAM_STR (get_name ()));
+
+    return ret;
+};
+
+XCamReturn
+GLBlender::configure_resource (const SmartPtr<Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr ());
+    XCAM_ASSERT (_priv_config->pyr_levels <= XCAM_GL_PYRAMID_MAX_LEVEL);
+
+    const VideoBufferInfo &in0_info = param->in_buf->get_video_info ();
+    XCAM_FAIL_RETURN (
+        ERROR, in0_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
+        "blender(%s) only support NV12 format, but input format is %s",
+        XCAM_STR(get_name ()), xcam_fourcc_to_string (in0_info.format));
+
+    Rect in0_area, in1_area, out_area;
+    in0_area = get_input_merge_area (Idx0);
+    in1_area = get_input_merge_area (Idx1);
+    out_area = get_merge_window ();
+    XCAM_FAIL_RETURN (
+        ERROR,
+        in0_area.width && in0_area.height &&
+        in0_area.width == in1_area.width && in0_area.height == in1_area.height &&
+        in0_area.width == out_area.width && in0_area.height == out_area.height,
+        XCAM_RETURN_ERROR_PARAM,
+        "blender(%s) invalid input/output overlap area, input0:%dx%d, input1:%dx%d, output:%dx%d",
+        XCAM_STR(get_name ()), in0_area.width, in0_area.height,
+        in1_area.width, in1_area.height, out_area.width, out_area.height);
+
+    VideoBufferInfo out_info;
+    uint32_t out_width, out_height;
+    get_output_size (out_width, out_height);
+    XCAM_FAIL_RETURN (
+        ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
+        "blender(%s) invalid output size, output size:%dx%d",
+        XCAM_STR(get_name ()), out_width, out_height);
+
+    out_info.init (
+        in0_info.format, out_width, out_height,
+        XCAM_ALIGN_UP (out_width, GL_BLENDER_ALIGN_X), XCAM_ALIGN_UP (out_height, GL_BLENDER_ALIGN_Y));
+    set_out_video_info (out_info);
+
+    VideoBufferInfo overlap_info;
+    Rect merge_size = get_merge_window ();
+    XCAM_FAIL_RETURN (
+            ERROR, 
+            merge_size.width && merge_size.height &&
+            merge_size.width % GL_BLENDER_ALIGN_X == 0 &&
+            merge_size.height % GL_BLENDER_ALIGN_Y == 0,
+            XCAM_RETURN_ERROR_PARAM,
+            "blender(%s) invalid merge size, width:%d, height:%d",
+            XCAM_STR (get_name ()), merge_size.width, merge_size.height);
+
+    overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
+    SmartPtr<BufferPool> first_lap_pool = new GLVideoBufferPool (overlap_info);
+    XCAM_ASSERT (first_lap_pool.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, first_lap_pool->reserve (LAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
+        "blender(%s) reserve lap buffer pool failed, overlap size:%dx%d",
+        XCAM_STR(get_name ()), overlap_info.width, overlap_info.height);
+    _priv_config->first_lap_pool = first_lap_pool;
+
+    SmartPtr<Worker::Callback> gauss_scale_cb = new CbGaussScalePyr (this);
+    SmartPtr<Worker::Callback> lap_trans_cb = new CbLapTransPyr (this);
+    SmartPtr<Worker::Callback> reconstruct_cb = new CbReconstructPyr (this);
+    XCAM_ASSERT (gauss_scale_cb.ptr () && lap_trans_cb.ptr () && reconstruct_cb.ptr ());
+
+    XCamReturn ret = _priv_config->init_first_masks (merge_size.width, 1);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "blender(%s) init first masks failed", XCAM_STR (get_name ()));
+
+    for (uint32_t i = 0; i < _priv_config->pyr_levels; ++i) {
+        merge_size.width = XCAM_ALIGN_UP ((merge_size.width + 1) / 2, GL_BLENDER_ALIGN_X);
+        merge_size.height = XCAM_ALIGN_UP ((merge_size.height + 1) / 2, GL_BLENDER_ALIGN_Y);
+        overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
+
+        SmartPtr<BufferPool> pool = new GLVideoBufferPool (overlap_info);
+        XCAM_ASSERT (pool.ptr ());
+        XCAM_FAIL_RETURN (
+            ERROR, pool->reserve (OVERLAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
+            "blender(%s) reserve buffer pool failed, overlap size:%dx%d",
+            XCAM_STR(get_name ()), overlap_info.width, overlap_info.height);
+        _priv_config->pyr_layer[i].overlap_pool = pool;
+
+        ret = _priv_config->scale_down_masks (i, merge_size.width, 1);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "blender(%s) scale down masks failed, level:%d", XCAM_STR (get_name ()), i);
+
+        _priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx0] = create_gauss_scale_pyr_shader (gauss_scale_cb);
+        XCAM_ASSERT (_priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx0].ptr ());
+        _priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx1] = create_gauss_scale_pyr_shader (gauss_scale_cb);
+        XCAM_ASSERT (_priv_config->pyr_layer[i].gauss_scale[GLBlender::Idx1].ptr ());
+        _priv_config->pyr_layer[i].lap_trans[GLBlender::Idx0] = create_lap_trans_pyr_shader (lap_trans_cb);
+        XCAM_ASSERT (_priv_config->pyr_layer[i].lap_trans[GLBlender::Idx0].ptr ());
+        _priv_config->pyr_layer[i].lap_trans[GLBlender::Idx1] = create_lap_trans_pyr_shader (lap_trans_cb);
+        XCAM_ASSERT (_priv_config->pyr_layer[i].lap_trans[GLBlender::Idx1].ptr ());
+        _priv_config->pyr_layer[i].reconstruct = create_reconstruct_pyr_shader (reconstruct_cb);
+        XCAM_ASSERT (_priv_config->pyr_layer[i].reconstruct.ptr ());
+    }
+
+    SmartPtr<Worker::Callback> blend_cb = new CbBlendPyr (this);
+    XCAM_ASSERT (blend_cb.ptr ());
+    _priv_config->top_level_blend = create_blend_pyr_shader (blend_cb);
+    XCAM_ASSERT (_priv_config->top_level_blend.ptr ());
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void
+GLBlender::gauss_scale_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_UNUSED (error);
+    XCAM_ASSERT (base.ptr ());
+
+    SmartPtr<GLGaussScalePyrShader::Args> args = base.dynamic_cast_ptr<GLGaussScalePyrShader::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    uint32_t level = args->level;
+    XCAM_ASSERT (level < _priv_config->pyr_levels);
+    uint32_t next_level = level + 1;
+    BufIdx idx = args->idx;
+
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    dump_level_buf (args->out_video_buf, "gauss-scale", level, idx);
+
+    XCamReturn ret = _priv_config->start_lap_trans (param, args, level, idx);
+    CHECK_RET (ret, "execute laplace transformation failed, level:%d idx:%d", level, idx);
+
+    if (next_level == _priv_config->pyr_levels) { // top level
+        ret = _priv_config->start_blend (param, args->out_video_buf, idx);
+        CHECK_RET (ret, "execute blend failed, level:%d idx:%d", next_level, idx);
+    } else {
+        ret = _priv_config->start_gauss_scale (param, args->out_video_buf, next_level, idx);
+        CHECK_RET (ret, "execute gauss scale failed, level:%d idx:%d", next_level, idx);
+    }
+}
+
+void
+GLBlender::lap_trans_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_UNUSED (error);
+    XCAM_ASSERT (base.ptr ());
+
+    SmartPtr<GLLapTransPyrShader::Args> args = base.dynamic_cast_ptr<GLLapTransPyrShader::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    uint32_t level = args->level;
+    XCAM_ASSERT (level < _priv_config->pyr_levels);
+    BufIdx idx = args->idx;
+
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    dump_level_buf (args->out_video_buf, "lap", level, idx);
+
+    XCamReturn ret = _priv_config->start_reconstruct_by_lap (param, args->out_video_buf, level, idx);
+    CHECK_RET (ret, "execute reconstruct by lap failed, level:%d idx:%d", level, idx);
+}
+
+void
+GLBlender::blend_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_UNUSED (error);
+    XCAM_ASSERT (base.ptr ());
+
+    SmartPtr<GLBlendPyrShader::Args> args = base.dynamic_cast_ptr<GLBlendPyrShader::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    dump_buf (args->out_video_buf, "blend-top");
+
+    XCamReturn ret = _priv_config->start_reconstruct_by_gauss (param, args->out_video_buf, _priv_config->pyr_levels - 1);
+    CHECK_RET (ret, "execute reconstruct by gauss failed, level:%d", _priv_config->pyr_levels - 1);
+}
+
+void
+GLBlender::reconstruct_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_ASSERT (base.ptr ());
+
+    SmartPtr<GLReconstructPyrShader::Args> args = base.dynamic_cast_ptr<GLReconstructPyrShader::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    uint32_t level = args->level;
+    XCAM_ASSERT (level < _priv_config->pyr_levels);
+
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    dump_level_buf (args->out_video_buf, "reconstruct", level, 0);
+
+    if (level == 0) {
+        execute_done (param, error);
+        return;
+    }
+
+    XCamReturn ret = _priv_config->start_reconstruct_by_gauss (param, args->out_video_buf, level - 1);
+    CHECK_RET (ret, "execute reconstruct by gauss failed, level:%d", level - 1);
+}
+
+SmartPtr<GLImageHandler>
+create_gl_blender ()
+{
+    SmartPtr<GLBlender> blender = new GLBlender();
+    XCAM_ASSERT (blender.ptr ());
+    return blender;
+}
+
+SmartPtr<Blender>
+Blender::create_gl_blender ()
+{
+    SmartPtr<GLImageHandler> handler = XCam::create_gl_blender ();
+    return handler.dynamic_cast_ptr<Blender> ();
+}
+
+}
diff --git a/modules/gles/gl_blender.h b/modules/gles/gl_blender.h
new file mode 100644
index 0000000..54d5a27
--- /dev/null
+++ b/modules/gles/gl_blender.h
@@ -0,0 +1,98 @@
+/*
+ * gl_blender.h - gl blender class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_BLENDER_H
+#define XCAM_GL_BLENDER_H
+
+#include <interface/blender.h>
+#include <gles/gl_image_handler.h>
+
+#define XCAM_GL_PYRAMID_MAX_LEVEL 4
+#define XCAM_GL_PYRAMID_DEFAULT_LEVEL 2
+
+namespace XCam {
+
+namespace GLBlenderPriv {
+class BlenderPrivConfig;
+};
+
+class GLBlender
+    : public GLImageHandler, public Blender
+{
+    friend class GLBlenderPriv::BlenderPrivConfig;
+    friend SmartPtr<GLImageHandler> create_gl_blender ();
+
+public:
+    struct BlenderParam : ImageHandler::Parameters {
+        SmartPtr<VideoBuffer> in1_buf;
+
+        BlenderParam (
+            const SmartPtr<VideoBuffer> &in0,
+            const SmartPtr<VideoBuffer> &in1,
+            const SmartPtr<VideoBuffer> &out)
+            : Parameters (in0, out)
+            , in1_buf (in1)
+        {}
+    };
+
+    enum BufIdx {
+        Idx0 = 0,
+        Idx1,
+        BufIdxCount
+    };
+
+public:
+    ~GLBlender ();
+
+    //derived from GLHandler
+    virtual XCamReturn finish ();
+    virtual XCamReturn terminate ();
+
+    void gauss_scale_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+    void lap_trans_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+    void blend_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+    void reconstruct_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+
+protected:
+    explicit GLBlender (const char *name = "GLBlender");
+
+    //derived from Blender interface
+    XCamReturn blend (
+        const SmartPtr<VideoBuffer> &in0,
+        const SmartPtr<VideoBuffer> &in1,
+        SmartPtr<VideoBuffer> &out_buf);
+
+    //derived from SoftHandler
+    XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    SmartPtr<GLBlenderPriv::BlenderPrivConfig>    _priv_config;
+};
+
+extern SmartPtr<GLImageHandler> create_gl_blender ();
+}
+
+#endif // XCAM_GL_BLENDER_H
diff --git a/modules/gles/gl_blender_shaders_priv.cpp b/modules/gles/gl_blender_shaders_priv.cpp
new file mode 100644
index 0000000..db23416
--- /dev/null
+++ b/modules/gles/gl_blender_shaders_priv.cpp
@@ -0,0 +1,398 @@
+/*
+ * gl_blender_shaders_priv.cpp - gl blender shaders private class implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_blender_shaders_priv.h"
+
+namespace XCam {
+
+namespace XCamGLShaders {
+
+enum {
+    ShaderGaussScalePyr = 0,
+    ShaderLapTransPyr,
+    ShaderBlendPyr,
+    ShaderReconstructPyr
+};
+
+static const GLShaderInfo shaders_info[] = {
+    {
+        GL_COMPUTE_SHADER,
+        "shader_gauss_scale_pyr",
+#include "shader_gauss_scale_pyr.comp.slx"
+        , 0
+    },
+    {
+        GL_COMPUTE_SHADER,
+        "shader_lap_trans_pyr",
+#include "shader_lap_trans_pyr.comp.slx"
+        , 0
+    },
+    {
+        GL_COMPUTE_SHADER,
+        "shader_blend_pyr",
+#include "shader_blend_pyr.comp.slx"
+        , 0
+    },
+    {
+        GL_COMPUTE_SHADER,
+        "shader_reconstruct_pyr",
+#include "shader_reconstruct_pyr.comp.slx"
+        , 0
+    }
+};
+
+bool
+GLGaussScalePyrShader::check_desc (
+    const GLBufferDesc &in_desc, const GLBufferDesc &out_desc, const Rect &merge_area)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        merge_area.pos_y == 0 && merge_area.height == (int32_t)in_desc.height &&
+        merge_area.pos_x + merge_area.width <= (int32_t)in_desc.width &&
+        merge_area.width == (int32_t)out_desc.width * 2 &&
+        merge_area.height == (int32_t)out_desc.height * 2,
+        false, "invalid buffer size: input:%dx%d, output:%dx%d, merge_area:%dx%d",
+        in_desc.width, in_desc.height, out_desc.width, out_desc.height, merge_area.width, merge_area.height);
+
+    return true;
+}
+
+XCamReturn
+GLGaussScalePyrShader::prepare_arguments (const SmartPtr<Worker::Arguments> &base, GLCmdList &cmds)
+{
+    SmartPtr<GLGaussScalePyrShader::Args> args = base.dynamic_cast_ptr<GLGaussScalePyrShader::Args> ();
+    XCAM_ASSERT (args.ptr () && args->in_glbuf.ptr () && args->out_glbuf.ptr ());
+
+    const GLBufferDesc &in_desc = args->in_glbuf->get_buffer_desc ();
+    const GLBufferDesc &out_desc = args->out_glbuf->get_buffer_desc ();
+    const Rect &merge_area = args->merge_area;
+    XCAM_FAIL_RETURN (
+        ERROR, check_desc (in_desc, out_desc, merge_area), XCAM_RETURN_ERROR_PARAM,
+        "GLGaussScalePyrShader(%s) check buffer description failed, level:%d idx:%d",
+        XCAM_STR (get_name ()), args->level, (int)args->idx);
+
+    cmds.push_back (new GLCmdBindBufRange (args->in_glbuf, 0, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->in_glbuf, 1, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 2, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 3, NV12PlaneUVIdx));
+
+    size_t unit_bytes = sizeof (uint32_t);
+    uint32_t in_img_width = XCAM_ALIGN_UP (in_desc.width, unit_bytes) / unit_bytes;
+    uint32_t in_offset_x = XCAM_ALIGN_UP (merge_area.pos_x, unit_bytes) / unit_bytes;
+    uint32_t out_img_width = XCAM_ALIGN_UP (out_desc.width, unit_bytes) / unit_bytes;
+    uint32_t merge_width = XCAM_ALIGN_UP (merge_area.width, unit_bytes) / unit_bytes;
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_width", in_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_height", in_desc.height));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_offset_x", in_offset_x));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_img_width", out_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("merge_width", merge_width));
+
+    GLGroupsSize groups_size;
+    groups_size.x = XCAM_ALIGN_UP (out_img_width, 8) / 8;
+    groups_size.y = XCAM_ALIGN_UP (out_desc.height, 16) / 16;
+    groups_size.z = 1;
+
+    SmartPtr<GLComputeProgram> prog;
+    XCAM_FAIL_RETURN (
+        ERROR, get_compute_program (prog), XCAM_RETURN_ERROR_PARAM,
+        "GLGaussScalePyrShader(%s) get compute program failed", XCAM_STR (get_name ()));
+    prog->set_groups_size (groups_size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+bool
+GLLapTransPyrShader::check_desc (
+    const GLBufferDesc &in_desc, const GLBufferDesc &out_desc,
+    const GLBufferDesc &gs_desc, const Rect &merge_area)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        merge_area.pos_y == 0 && merge_area.height == (int32_t)in_desc.height &&
+        merge_area.pos_x + merge_area.width <= (int32_t)in_desc.width &&
+        merge_area.width == (int32_t)out_desc.width && merge_area.height == (int32_t)out_desc.height &&
+        merge_area.width == (int32_t)gs_desc.width * 2 && merge_area.height == (int32_t)gs_desc.height * 2,
+        false,
+        "invalid buffer size: intput:%dx%d, output:%dx%d, gaussscale:%dx%d, in_area:%dx%d",
+        in_desc.width, in_desc.height, out_desc.width, out_desc.height,
+        gs_desc.width, gs_desc.height, merge_area.width, merge_area.height);
+
+    return true;
+}
+
+XCamReturn
+GLLapTransPyrShader::prepare_arguments (const SmartPtr<Worker::Arguments> &base, GLCmdList &cmds)
+{
+    SmartPtr<GLLapTransPyrShader::Args> args = base.dynamic_cast_ptr<GLLapTransPyrShader::Args> ();
+    XCAM_ASSERT (args.ptr () && args->in_glbuf.ptr () && args->gaussscale_glbuf.ptr () && args->out_glbuf.ptr ());
+
+    const GLBufferDesc &in_desc = args->in_glbuf->get_buffer_desc ();
+    const GLBufferDesc &gs_desc = args->gaussscale_glbuf->get_buffer_desc ();
+    const GLBufferDesc &out_desc = args->out_glbuf->get_buffer_desc ();
+    const Rect &merge_area = args->merge_area;
+    XCAM_FAIL_RETURN (
+        ERROR, check_desc (in_desc, out_desc, gs_desc, merge_area), XCAM_RETURN_ERROR_PARAM,
+        "GLLapTransPyrShader(%s) check buffer description failed, level:%d idx:%d",
+        XCAM_STR (get_name ()), args->level, (int)args->idx);
+
+    cmds.push_back (new GLCmdBindBufRange (args->in_glbuf, 0, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->in_glbuf, 1, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->gaussscale_glbuf, 2, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->gaussscale_glbuf, 3, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 4, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 5, NV12PlaneUVIdx));
+
+    size_t unit_bytes = sizeof (uint32_t) * 2;
+    uint32_t in_img_width = XCAM_ALIGN_UP (in_desc.width, unit_bytes) / unit_bytes;
+    uint32_t in_offset_x = XCAM_ALIGN_UP (merge_area.pos_x, unit_bytes) / unit_bytes;
+    uint32_t gaussscale_img_width = XCAM_ALIGN_UP (gs_desc.width, sizeof (uint32_t)) / sizeof (uint32_t);
+    uint32_t merge_width = XCAM_ALIGN_UP (merge_area.width, unit_bytes) / unit_bytes;
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_width", in_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_height", in_desc.height));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_offset_x", in_offset_x));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("gaussscale_img_width", gaussscale_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("gaussscale_img_height", gs_desc.height));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("merge_width", merge_width));
+
+    GLGroupsSize groups_size;
+    groups_size.x = XCAM_ALIGN_UP (merge_width, 8) / 8;
+    groups_size.y = XCAM_ALIGN_UP (merge_area.height, 32) / 32;
+    groups_size.z = 1;
+
+    SmartPtr<GLComputeProgram> prog;
+    XCAM_FAIL_RETURN (
+        ERROR, get_compute_program (prog), XCAM_RETURN_ERROR_PARAM,
+        "GLLapTransPyrShader(%s) get compute program failed", XCAM_STR (get_name ()));
+    prog->set_groups_size (groups_size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+bool
+GLBlendPyrShader::check_desc (
+    const GLBufferDesc &in0_desc, const GLBufferDesc &in1_desc,
+    const GLBufferDesc &out_desc, const GLBufferDesc &mask_desc)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        in0_desc.width == in1_desc.width && in0_desc.height == in1_desc.height &&
+        in0_desc.width == out_desc.width && in0_desc.height == out_desc.height &&
+        in0_desc.width == mask_desc.width,
+        false,
+        "invalid buffer size: intput0:%dx%d, intput1:%dx%d, output:%dx%d, mask:%dx%d",
+        in0_desc.width, in0_desc.height, in1_desc.width, in1_desc.height,
+        out_desc.width, out_desc.height, mask_desc.width, mask_desc.height);
+
+    XCAM_FAIL_RETURN (
+        ERROR, mask_desc.height == 1, false,
+        "mask buffer only supports one-dimensional array");
+
+    return true;
+}
+
+XCamReturn
+GLBlendPyrShader::prepare_arguments (const SmartPtr<Worker::Arguments> &base, GLCmdList &cmds)
+{
+    SmartPtr<GLBlendPyrShader::Args> args = base.dynamic_cast_ptr<GLBlendPyrShader::Args> ();
+    XCAM_ASSERT (args.ptr () && args->in0_glbuf.ptr () && args->in1_glbuf.ptr () && args->out_glbuf.ptr ());
+    XCAM_ASSERT (args->mask_glbuf.ptr ());
+
+    const GLBufferDesc &in0_desc = args->in0_glbuf->get_buffer_desc ();
+    const GLBufferDesc &in1_desc = args->in1_glbuf->get_buffer_desc ();
+    const GLBufferDesc &out_desc = args->out_glbuf->get_buffer_desc ();
+    const GLBufferDesc &mask_desc = args->mask_glbuf->get_buffer_desc ();
+    XCAM_FAIL_RETURN (
+        ERROR, check_desc (in0_desc, in1_desc, out_desc, mask_desc), XCAM_RETURN_ERROR_PARAM,
+        "GLBlendPyrShader(%s) check buffer description failed", XCAM_STR (get_name ()));
+
+    cmds.push_back (new GLCmdBindBufRange (args->in0_glbuf, 0, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->in0_glbuf, 1, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->in1_glbuf, 2, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->in1_glbuf, 3, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 4, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 5, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufBase (args->mask_glbuf, 6));
+
+    size_t unit_bytes = sizeof (uint32_t) * 2;
+    uint32_t in_img_width = XCAM_ALIGN_UP (in0_desc.width, unit_bytes) / unit_bytes;
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_width", in_img_width));
+
+    GLGroupsSize groups_size;
+    groups_size.x = XCAM_ALIGN_UP (in_img_width, 8) / 8;
+    groups_size.y = XCAM_ALIGN_UP (in0_desc.height, 16) / 16;
+    groups_size.z = 1;
+
+    SmartPtr<GLComputeProgram> prog;
+    XCAM_FAIL_RETURN (
+        ERROR, get_compute_program (prog), XCAM_RETURN_ERROR_PARAM,
+        "GLBlendPyrShader(%s) get compute program failed", XCAM_STR (get_name ()));
+    prog->set_groups_size (groups_size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+bool
+GLReconstructPyrShader::check_desc (
+    const GLBufferDesc &lap0_desc, const GLBufferDesc &lap1_desc, const GLBufferDesc &out_desc,
+    const GLBufferDesc &prev_blend_desc, const GLBufferDesc &mask_desc, const Rect &merge_area)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        merge_area.pos_y == 0 && merge_area.height == (int32_t)out_desc.height &&
+        merge_area.pos_x + merge_area.width <= (int32_t)out_desc.width &&
+        merge_area.width == (int32_t)lap0_desc.width && merge_area.height == (int32_t)lap0_desc.height &&
+        lap0_desc.width == lap1_desc.width && lap0_desc.height == lap1_desc.height &&
+        lap0_desc.width == prev_blend_desc.width * 2 && lap0_desc.height == prev_blend_desc.height * 2 &&
+        lap0_desc.width == mask_desc.width,
+        false,
+        "invalid buffer size: lap0:%dx%d, lap1:%dx%d, output:%dx%d, prev_blend:%dx%d, mask:%dx%d, merge_area:%dx%d",
+        lap0_desc.width, lap0_desc.height, lap1_desc.width, lap1_desc.height,
+        out_desc.width, out_desc.height, prev_blend_desc.width, prev_blend_desc.height,
+        mask_desc.width, mask_desc.height, merge_area.width, merge_area.height);
+
+    XCAM_FAIL_RETURN (
+        ERROR, mask_desc.height == 1, false,
+        "mask buffer only supports one-dimensional array");
+
+    return true;
+}
+
+XCamReturn
+GLReconstructPyrShader::prepare_arguments (const SmartPtr<Worker::Arguments> &base, GLCmdList &cmds)
+{
+    SmartPtr<GLReconstructPyrShader::Args> args = base.dynamic_cast_ptr<GLReconstructPyrShader::Args> ();
+    XCAM_ASSERT (args.ptr () && args->lap0_glbuf.ptr () && args->lap1_glbuf.ptr () && args->out_glbuf.ptr ());
+    XCAM_ASSERT (args->mask_glbuf.ptr ());
+
+    const GLBufferDesc &lap0_desc = args->lap0_glbuf->get_buffer_desc ();
+    const GLBufferDesc &lap1_desc = args->lap1_glbuf->get_buffer_desc ();
+    const GLBufferDesc &out_desc = args->out_glbuf->get_buffer_desc ();
+    const GLBufferDesc &prev_blend_desc = args->prev_blend_glbuf->get_buffer_desc ();
+    const GLBufferDesc &mask_desc = args->mask_glbuf->get_buffer_desc ();
+    const Rect &merge_area = args->merge_area;
+    XCAM_FAIL_RETURN (
+        ERROR, check_desc (lap0_desc, lap1_desc, out_desc, prev_blend_desc, mask_desc, merge_area),
+        XCAM_RETURN_ERROR_PARAM,
+        "GLReconstructPyrShader(%s) check buffer description failed, level:%d",
+        XCAM_STR (get_name ()), args->level);
+
+    cmds.push_back (new GLCmdBindBufRange (args->lap0_glbuf, 0, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->lap0_glbuf, 1, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->lap1_glbuf, 2, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->lap1_glbuf, 3, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 4, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_glbuf, 5, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->prev_blend_glbuf, 6, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->prev_blend_glbuf, 7, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufBase (args->mask_glbuf, 8));
+
+    size_t unit_bytes = sizeof (uint32_t) * 2;
+    uint32_t lap_img_width = XCAM_ALIGN_UP (lap0_desc.width, unit_bytes) / unit_bytes;
+    uint32_t out_img_width = XCAM_ALIGN_UP (out_desc.width, unit_bytes) / unit_bytes;
+    uint32_t out_offset_x = XCAM_ALIGN_UP (merge_area.pos_x, unit_bytes) / unit_bytes;
+    uint32_t prev_blend_img_width = XCAM_ALIGN_UP (prev_blend_desc.width, sizeof (uint32_t)) / sizeof (uint32_t);
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("lap_img_width", lap_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("lap_img_height", lap0_desc.height));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_img_width", out_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_offset_x", out_offset_x));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("prev_blend_img_width", prev_blend_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("prev_blend_img_height", prev_blend_desc.height));
+
+    GLGroupsSize groups_size;
+    groups_size.x = XCAM_ALIGN_UP (lap_img_width, 8) / 8;
+    groups_size.y = XCAM_ALIGN_UP (lap0_desc.height, 32) / 32;
+    groups_size.z = 1;
+
+    SmartPtr<GLComputeProgram> prog;
+    XCAM_FAIL_RETURN (
+        ERROR, get_compute_program (prog), XCAM_RETURN_ERROR_PARAM,
+        "GLReconstructPyrShader(%s) get compute program failed", XCAM_STR (get_name ()));
+    prog->set_groups_size (groups_size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+SmartPtr<GLGaussScalePyrShader>
+create_gauss_scale_pyr_shader (SmartPtr<Worker::Callback> &cb)
+{
+    XCAM_ASSERT (cb.ptr ());
+
+    SmartPtr<GLGaussScalePyrShader> shader = new GLGaussScalePyrShader (cb);
+    XCAM_ASSERT (shader.ptr ());
+
+    XCamReturn ret = shader->create_compute_program (shaders_info[ShaderGaussScalePyr], "gauss_scale_pyr_program");
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
+        "create gauss scale pyramid program failed");
+
+    return shader;
+}
+
+SmartPtr<GLLapTransPyrShader>
+create_lap_trans_pyr_shader (SmartPtr<Worker::Callback> &cb)
+{
+    XCAM_ASSERT (cb.ptr ());
+
+    SmartPtr<GLLapTransPyrShader> shader = new GLLapTransPyrShader (cb);
+    XCAM_ASSERT (shader.ptr ());
+
+    XCamReturn ret = shader->create_compute_program (shaders_info[ShaderLapTransPyr], "lap_trans_pyr_program");
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
+        "create laplace transformation pyramid program failed");
+
+    return shader;
+}
+
+SmartPtr<GLBlendPyrShader>
+create_blend_pyr_shader (SmartPtr<Worker::Callback> &cb)
+{
+    XCAM_ASSERT (cb.ptr ());
+
+    SmartPtr<GLBlendPyrShader> shader = new GLBlendPyrShader (cb);
+    XCAM_ASSERT (shader.ptr ());
+
+    XCamReturn ret = shader->create_compute_program (shaders_info[ShaderBlendPyr], "blend_pyr_program");
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
+        "create blend pyramid program failed");
+
+    return shader;
+}
+
+SmartPtr<GLReconstructPyrShader>
+create_reconstruct_pyr_shader (SmartPtr<Worker::Callback> &cb)
+{
+    XCAM_ASSERT (cb.ptr ());
+
+    SmartPtr<GLReconstructPyrShader> shader = new GLReconstructPyrShader (cb);
+    XCAM_ASSERT (shader.ptr ());
+
+    XCamReturn ret = shader->create_compute_program (shaders_info[ShaderReconstructPyr], "reconstruct_pyr_program");
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
+        "create reconstruct pyramid program failed");
+
+    return shader;
+}
+
+}
+
+}
diff --git a/modules/gles/gl_blender_shaders_priv.h b/modules/gles/gl_blender_shaders_priv.h
new file mode 100644
index 0000000..f3e363a
--- /dev/null
+++ b/modules/gles/gl_blender_shaders_priv.h
@@ -0,0 +1,182 @@
+/*
+ * gl_blender_shaders_priv.h - gl blender shaders private class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_BLENDER_SHADERS_PRIV_H
+#define XCAM_GL_BLENDER_SHADERS_PRIV_H
+
+#include <interface/data_types.h>
+#include <gles/gl_image_shader.h>
+#include <gles/gl_image_handler.h>
+#include <gles/gl_buffer.h>
+#include <gles/gl_blender.h>
+
+#define GL_BLENDER_ALIGN_X 8
+#define GL_BLENDER_ALIGN_Y 4
+
+namespace XCam {
+
+namespace XCamGLShaders {
+
+class GLGaussScalePyrShader
+    : public GLImageShader
+{
+public:
+    struct Args : GLArgs {
+        SmartPtr<GLBuffer>         in_glbuf;
+        SmartPtr<GLBuffer>         out_glbuf;
+        Rect                       merge_area;
+
+        const uint32_t             level;
+        const GLBlender::BufIdx    idx;
+        SmartPtr<VideoBuffer>      out_video_buf;
+
+        Args (
+            const SmartPtr<ImageHandler::Parameters> &param,
+            uint32_t l, GLBlender::BufIdx i)
+            : GLArgs (param)
+            , level (l)
+            , idx (i)
+        {}
+    };
+
+public:
+    explicit GLGaussScalePyrShader (const SmartPtr<Worker::Callback> &cb)
+        : GLImageShader ("GLGaussScalePyrShader", cb)
+    {}
+
+private:
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+    bool check_desc (const GLBufferDesc &in_desc, const GLBufferDesc &out_desc, const Rect &merge_area);
+};
+
+class GLLapTransPyrShader
+    : public GLImageShader
+{
+public:
+    struct Args : GLArgs {
+        SmartPtr<GLBuffer>         in_glbuf;
+        SmartPtr<GLBuffer>         out_glbuf;
+        SmartPtr<GLBuffer>         gaussscale_glbuf;
+        Rect                       merge_area;
+
+        const uint32_t             level;
+        const GLBlender::BufIdx    idx;
+        SmartPtr<VideoBuffer>      out_video_buf;
+
+        Args (
+            const SmartPtr<ImageHandler::Parameters> &param,
+            uint32_t l, GLBlender::BufIdx i)
+            : GLArgs (param)
+            , level (l)
+            , idx (i)
+        {}
+    };
+
+public:
+    explicit GLLapTransPyrShader (const SmartPtr<Worker::Callback> &cb)
+        : GLImageShader ("GLLapTransPyrShader", cb)
+    {}
+
+private:
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+    bool check_desc (
+        const GLBufferDesc &in_desc, const GLBufferDesc &out_desc,
+        const GLBufferDesc &gs_desc, const Rect &merge_area);
+};
+
+class GLBlendPyrShader
+    : public GLImageShader
+{
+public:
+    struct Args : GLArgs {
+        SmartPtr<GLBuffer>       in0_glbuf;
+        SmartPtr<GLBuffer>       in1_glbuf;
+        SmartPtr<GLBuffer>       out_glbuf;
+        SmartPtr<GLBuffer>       mask_glbuf;
+
+        SmartPtr<VideoBuffer>    out_video_buf;
+
+        Args (const SmartPtr<ImageHandler::Parameters> &param)
+            : GLArgs (param)
+        {}
+    };
+
+public:
+    explicit GLBlendPyrShader (const SmartPtr<Worker::Callback> &cb)
+        : GLImageShader ("GLBlendPyrShader", cb)
+    {}
+
+private:
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+    bool check_desc (
+        const GLBufferDesc &in0_desc, const GLBufferDesc &in1_desc,
+        const GLBufferDesc &out_desc, const GLBufferDesc &mask_desc);
+};
+
+class GLReconstructPyrShader
+    : public GLImageShader
+{
+public:
+    struct Args : GLArgs {
+        SmartPtr<GLBuffer>       lap0_glbuf;
+        SmartPtr<GLBuffer>       lap1_glbuf;
+        SmartPtr<GLBuffer>       out_glbuf;
+        SmartPtr<GLBuffer>       prev_blend_glbuf;
+        SmartPtr<GLBuffer>       mask_glbuf;
+        Rect                     merge_area;
+
+        const uint32_t           level;
+        SmartPtr<VideoBuffer>    out_video_buf;
+
+        Args (const SmartPtr<ImageHandler::Parameters> &param, uint32_t l)
+            : GLArgs (param)
+            , level (l)
+        {}
+    };
+
+public:
+    explicit GLReconstructPyrShader (const SmartPtr<Worker::Callback> &cb)
+        : GLImageShader ("GLReconstructPyrShader", cb)
+    {}
+
+private:
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+    bool check_desc (
+        const GLBufferDesc &lap0_desc, const GLBufferDesc &lap1_desc, const GLBufferDesc &out_desc,
+        const GLBufferDesc &prev_blend_desc, const GLBufferDesc &mask_desc, const Rect &merge_area);
+};
+
+SmartPtr<GLGaussScalePyrShader>
+create_gauss_scale_pyr_shader (SmartPtr<Worker::Callback> &cb);
+
+SmartPtr<GLLapTransPyrShader>
+create_lap_trans_pyr_shader (SmartPtr<Worker::Callback> &cb);
+
+SmartPtr<GLBlendPyrShader>
+create_blend_pyr_shader (SmartPtr<Worker::Callback> &cb);
+
+SmartPtr<GLReconstructPyrShader>
+create_reconstruct_pyr_shader (SmartPtr<Worker::Callback> &cb);
+
+}
+
+}
+
+#endif // XCAM_GL_BLENDER_SHADERS_PRIV_H
diff --git a/modules/gles/gl_buffer.cpp b/modules/gles/gl_buffer.cpp
new file mode 100644
index 0000000..7cb8c8e
--- /dev/null
+++ b/modules/gles/gl_buffer.cpp
@@ -0,0 +1,246 @@
+/*
+ * gl_buffer.cpp - GL buffer
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "gl_buffer.h"
+
+namespace XCam {
+
+GLBufferDesc::GLBufferDesc ()
+    : format (V4L2_PIX_FMT_NV12)
+    , width (0)
+    , height (0)
+    , aligned_width (0)
+    , aligned_height (0)
+    , size (0)
+{
+    xcam_mem_clear (strides);
+    xcam_mem_clear (slice_size);
+    xcam_mem_clear (offsets);
+}
+
+GLBuffer::MapRange::MapRange ()
+    : offset (0)
+    , len (0)
+    , flags (0)
+    , ptr (0)
+{
+}
+
+void
+GLBuffer::MapRange::clear ()
+{
+    offset = 0;
+    len = 0;
+    flags = 0;
+    ptr = NULL;
+}
+
+bool
+GLBuffer::MapRange::is_mapped () const
+{
+    return ptr;
+}
+
+GLBuffer::GLBuffer (GLuint id, GLenum target, GLenum usage, uint32_t size)
+    : _target (target)
+    , _usage (usage)
+    , _buf_id (id)
+    , _size (size)
+{
+}
+
+XCamReturn
+GLBuffer::bind ()
+{
+    glBindBuffer (_target, _buf_id);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GL bind buffer:%d failed, error flag: %s", _buf_id, gl_error_string (error));
+    return XCAM_RETURN_NO_ERROR;
+}
+
+GLBuffer::~GLBuffer ()
+{
+    if (_buf_id) {
+        glDeleteBuffers (1, &_buf_id);
+
+        GLenum error = gl_error ();
+        if (error != GL_NO_ERROR) {
+            XCAM_LOG_WARNING (
+                "GL Buffer delete buffer failed, error flag: %s", gl_error_string (error));
+        }
+    }
+}
+
+SmartPtr<GLBuffer>
+GLBuffer::create_buffer (
+    GLenum target,
+    const GLvoid *data, uint32_t size,
+    GLenum usage)
+{
+    XCAM_ASSERT (size > 0);
+
+    GLuint buf_id = 0;
+    glGenBuffers (1, &buf_id);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, buf_id && (error == GL_NO_ERROR), NULL,
+        "GL buffer creation failed, error flag: %s", gl_error_string (error));
+
+    glBindBuffer (target, buf_id);
+    XCAM_FAIL_RETURN (
+        ERROR, (error = gl_error ()) == GL_NO_ERROR, NULL,
+        "GL buffer creation failed when bind buffer:%d, error flag: %s",
+        buf_id, gl_error_string (error));
+
+    glBufferData (target, size, data, usage);
+    XCAM_FAIL_RETURN (
+        ERROR, (error = gl_error ()) == GL_NO_ERROR, NULL,
+        "GL buffer creation failed in glBufferData, id:%d, error flag: %s",
+        buf_id, gl_error_string (error));
+
+    SmartPtr<GLBuffer> buf_obj =
+        new GLBuffer (buf_id, target, usage, size);
+
+    return buf_obj;
+}
+
+void *
+GLBuffer::map_range (uint32_t offset, uint32_t length, GLbitfield flags)
+{
+    if (length == 0)
+        length = _size;
+
+    if (_mapped_range.is_mapped () &&
+            _mapped_range.flags == flags &&
+            _mapped_range.offset == offset &&
+            _mapped_range.len == length) {
+        return _mapped_range.ptr;
+    }
+    _mapped_range.clear ();
+
+    XCamReturn ret = bind ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), NULL,
+        "GL bind buffer failed, buf_id:%d", _buf_id);
+
+    void *ptr = glMapBufferRange (_target, offset, length, flags);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, ptr && (error == GL_NO_ERROR), NULL,
+        "GL buffer map range failed, buf_id:%d, offset:%d, len:%d, flags:%d, error flag: %s",
+        _buf_id, offset, length, flags, gl_error_string (error));
+
+    _mapped_range.offset = offset;
+    _mapped_range.len = length;
+    _mapped_range.flags = flags;
+    _mapped_range.ptr = ptr;
+
+    return ptr;
+}
+
+XCamReturn
+GLBuffer::flush_map ()
+{
+    if (!_mapped_range.is_mapped ())
+        return XCAM_RETURN_ERROR_ORDER;
+
+    XCAM_FAIL_RETURN (
+        ERROR, _mapped_range.flags & GL_MAP_FLUSH_EXPLICIT_BIT,
+        XCAM_RETURN_ERROR_GLES,
+        "GL buffer flush_map buf:%d failed, invalid flags(:%d)",
+        _buf_id, _mapped_range.flags);
+
+    XCamReturn ret = bind ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GL bind buffer failed, buf_id:%d", _buf_id);
+
+    glFlushMappedBufferRange (_target, _mapped_range.offset,  _mapped_range.len);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR,
+        XCAM_RETURN_ERROR_GLES,
+        "GL buffer flush_map buf:%d failed, error flag: %s",
+        _buf_id, gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLBuffer::unmap ()
+{
+    if (!_mapped_range.is_mapped ())
+        return XCAM_RETURN_ERROR_ORDER;
+
+    XCamReturn ret = bind ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GL bind buffer failed, buf_id:%d", _buf_id);
+
+    XCAM_FAIL_RETURN (
+        ERROR, glUnmapBuffer (_target), XCAM_RETURN_ERROR_GLES,
+        "GL buffer unmap buf:%d failed, error flag: %s",
+        _buf_id, gl_error_string (gl_error ()));
+
+    _mapped_range.clear ();
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLBuffer::bind_buffer_base (uint32_t index)
+{
+    XCamReturn ret = bind ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GL bind buffer failed, buf_id:%d", _buf_id);
+
+    glBindBufferBase (_target, index, _buf_id);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GL bind buffer base failed. buf_id:%d failed, idx:%d, error flag: %s",
+        _buf_id, index, gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLBuffer::bind_buffer_range (uint32_t index, uint32_t offset, uint32_t size)
+{
+    XCamReturn ret = bind ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GL bind buffer failed, buf_id:%d", _buf_id);
+
+    glBindBufferRange (_target, index, _buf_id, offset, size);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GL bind buffer range failed. buf_id:%d failed, idx:%d, error flag: %s",
+        _buf_id, index, gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
+
diff --git a/modules/gles/gl_buffer.h b/modules/gles/gl_buffer.h
new file mode 100644
index 0000000..5bd3d48
--- /dev/null
+++ b/modules/gles/gl_buffer.h
@@ -0,0 +1,110 @@
+/*
+ * gl_buffer.h - GL buffer
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_GL_BUFFER_H
+#define XCAM_GL_BUFFER_H
+
+#include <gles/gles_std.h>
+#include <map>
+
+#define XCAM_GL_MAX_COMPONENTS 4
+
+namespace XCam {
+
+struct GLBufferDesc {
+    uint32_t        format;
+    uint32_t        width;
+    uint32_t        height;
+    uint32_t        aligned_width;
+    uint32_t        aligned_height;
+    uint32_t        size;
+    uint32_t        strides[XCAM_GL_MAX_COMPONENTS];
+    uint32_t        offsets[XCAM_GL_MAX_COMPONENTS];
+    uint32_t        slice_size[XCAM_GL_MAX_COMPONENTS];
+
+    GLBufferDesc ();
+};
+
+class GLBuffer
+{
+public:
+    ~GLBuffer ();
+    static SmartPtr<GLBuffer> create_buffer (
+        GLenum target, const GLvoid *data = NULL, uint32_t size = 0, GLenum usage = GL_STATIC_DRAW);
+
+    GLuint get_buffer_id () const {
+        return _buf_id;
+    }
+    GLenum get_target () const {
+        return _target;
+    }
+    GLenum get_usage () const {
+        return _usage;
+    }
+    uint32_t get_size () const {
+        return _size;
+    }
+
+    void set_buffer_desc (const GLBufferDesc &desc) {
+        _desc = desc;
+    }
+    const GLBufferDesc &get_buffer_desc () {
+        return _desc;
+    }
+
+    void *map_range (
+        uint32_t offset = 0, uint32_t length = 0,
+        GLbitfield flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
+    XCamReturn flush_map ();
+    XCamReturn unmap ();
+
+    XCamReturn bind ();
+    XCamReturn bind_buffer_base (uint32_t index);
+    XCamReturn bind_buffer_range (uint32_t index, uint32_t offset, uint32_t size);
+
+private:
+    explicit GLBuffer (GLuint id, GLenum type, GLenum usage, uint32_t size);
+
+private:
+    XCAM_DEAD_COPY (GLBuffer);
+
+    struct MapRange {
+        uint32_t    offset;
+        uint32_t    len;
+        GLbitfield  flags;
+        void       *ptr;
+
+        MapRange ();
+        void clear ();
+        bool is_mapped () const;
+    };
+
+private:
+    GLenum        _target;
+    GLenum        _usage;
+    GLuint        _buf_id;
+    uint32_t      _size;
+    MapRange      _mapped_range;
+    GLBufferDesc  _desc;
+};
+
+}
+
+#endif  //XCAM_GL_BUFFER_H
diff --git a/modules/gles/gl_command.cpp b/modules/gles/gl_command.cpp
new file mode 100644
index 0000000..38b92b0
--- /dev/null
+++ b/modules/gles/gl_command.cpp
@@ -0,0 +1,265 @@
+/*
+ * gl_command.cpp - GL command implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_command.h"
+#include "gl_buffer.h"
+
+namespace XCam {
+
+namespace UniformOps {
+
+template <>
+GLenum uniform <GLfloat> (GLint location, GLfloat value)
+{
+    glUniform1f (location, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform <GLint> (GLint location, GLint value)
+{
+    glUniform1i (location, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform <GLuint> (GLint location, GLuint value)
+{
+    glUniform1ui (location, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_array <GLfloat> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniform1fv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_array <GLint> (GLint location, const GLint *value, GLsizei count)
+{
+    glUniform1iv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_array <GLuint> (GLint location, const GLuint *value, GLsizei count)
+{
+    glUniform1uiv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLfloat, 2> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniform2fv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLfloat, 3> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniform3fv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLfloat, 4> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniform4fv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLint, 2> (GLint location, const GLint *value, GLsizei count)
+{
+    glUniform2iv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLint, 3> (GLint location, const GLint *value, GLsizei count)
+{
+    glUniform3iv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLint, 4> (GLint location, const GLint *value, GLsizei count)
+{
+    glUniform4iv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLuint, 2> (GLint location, const GLuint *value, GLsizei count)
+{
+    glUniform2uiv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLuint, 3> (GLint location, const GLuint *value, GLsizei count)
+{
+    glUniform3uiv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_vect <GLuint, 4> (GLint location, const GLuint *value, GLsizei count)
+{
+    glUniform4uiv (location, count, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_mat <GLfloat, 2> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniformMatrix2fv (location, count, GL_FALSE, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_mat <GLfloat, 3> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniformMatrix3fv (location, count, GL_FALSE, value);
+    return gl_error ();
+}
+
+template <>
+GLenum uniform_mat <GLfloat, 4> (GLint location, const GLfloat *value, GLsizei count)
+{
+    glUniformMatrix4fv (location, count, GL_FALSE, value);
+    return gl_error ();
+}
+
+}
+
+GLCmdUniform::GLCmdUniform (const GLchar *name)
+{
+    XCAM_ASSERT (name);
+    strncpy (_name, name, XCAM_GL_NAME_LENGTH - 1);
+}
+
+GLCmdUniform::~GLCmdUniform ()
+{
+}
+
+XCamReturn
+GLCmdUniform::run (GLuint program)
+{
+    GLint location = get_uniform_location (program, _name);
+    XCAM_FAIL_RETURN (ERROR, location >= 0, XCAM_RETURN_ERROR_UNKNOWN, "get_uniform_location failed");
+
+    GLenum error = uniform (location);
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_UNKNOWN,
+        "uniform failed, name:%s, error flag: %s", _name, gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+GLint
+GLCmdUniform::get_uniform_location (GLuint program, const GLchar *name)
+{
+    GLint location = glGetUniformLocation (program, name);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, -1,
+        "get_uniform_location failed, name:%s, error flag: %s",
+        XCAM_STR (name), gl_error_string (error));
+
+    XCAM_FAIL_RETURN (
+        WARNING, location >= 0, -1,
+        "get_uniform_location invalid or unnecessary parameter, name:%s location:%d",
+        XCAM_STR (name), location);
+
+    return location;
+}
+
+GLCmdBindBufBase::GLCmdBindBufBase (const SmartPtr<GLBuffer> &buf, uint32_t index)
+    : _index (index)
+{
+    XCAM_ASSERT (buf.ptr ());
+    _buf = buf;
+}
+
+GLCmdBindBufBase::~GLCmdBindBufBase ()
+{
+}
+
+XCamReturn
+GLCmdBindBufBase::run (GLuint program)
+{
+    XCAM_UNUSED (program);
+
+    XCamReturn ret = _buf->bind_buffer_base (_index);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLCmdBindBufBase failed, idx:%d", _index);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+GLCmdBindBufRange::GLCmdBindBufRange (const SmartPtr<GLBuffer> &buf, uint32_t index, uint32_t offset_x)
+    : _index (index)
+    , _offset (offset_x)
+    , _size (0)
+{
+    XCAM_ASSERT (buf.ptr ());
+    _buf = buf;
+
+    const GLBufferDesc &desc = buf->get_buffer_desc ();
+    _size = desc.size - offset_x;
+}
+
+GLCmdBindBufRange::GLCmdBindBufRange (
+    const SmartPtr<GLBuffer> &buf, uint32_t index, NV12PlaneIdx plane, uint32_t offset_in_plane)
+    : _index (index)
+    , _offset (0)
+    , _size (0)
+{
+    XCAM_ASSERT (buf.ptr ());
+    _buf = buf;
+
+    const GLBufferDesc &desc = buf->get_buffer_desc ();
+    _offset = desc.offsets [plane] + offset_in_plane;
+    _size = desc.slice_size [plane] - offset_in_plane;
+}
+
+GLCmdBindBufRange::~GLCmdBindBufRange ()
+{
+}
+
+XCamReturn
+GLCmdBindBufRange::run (GLuint program)
+{
+    XCAM_UNUSED (program);
+
+    XCamReturn ret = _buf->bind_buffer_range (_index, _offset, _size);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLCmdBindBufRange failed, idx:%d", _index);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
diff --git a/modules/gles/gl_command.h b/modules/gles/gl_command.h
new file mode 100644
index 0000000..8906eee
--- /dev/null
+++ b/modules/gles/gl_command.h
@@ -0,0 +1,206 @@
+/*
+ * gl_command.h - GL command class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_COMMAND_H
+#define XCAM_GL_COMMAND_H
+
+#include <list>
+#include <gles/gles_std.h>
+
+namespace XCam {
+
+namespace UniformOps {
+
+template <typename TType>
+GLenum uniform (GLint location, TType value);
+
+template <typename TType>
+GLenum uniform_array (GLint location, const TType *value, GLsizei count);
+
+template <typename TType, uint32_t TDim>
+GLenum uniform_vect (GLint location, const TType *value, GLsizei count = 1);
+
+template <typename TType, uint32_t TDim>
+GLenum uniform_mat (GLint location, const TType *value, GLsizei count = 1);
+}
+
+class GLCommand
+{
+public:
+    virtual ~GLCommand () {}
+    virtual XCamReturn run (GLuint program) = 0;
+
+protected:
+    explicit GLCommand () {}
+
+private:
+    XCAM_DEAD_COPY (GLCommand);
+};
+typedef std::list<SmartPtr<GLCommand> > GLCmdList;
+
+class GLCmdUniform
+    : public GLCommand
+{
+public:
+    virtual ~GLCmdUniform ();
+    virtual XCamReturn run (GLuint program);
+
+protected:
+    explicit GLCmdUniform (const GLchar *name);
+
+private:
+    GLint get_uniform_location (GLuint program, const GLchar *name);
+    virtual GLenum uniform (GLint location) = 0;
+
+protected:
+    GLchar        _name[XCAM_GL_NAME_LENGTH];
+};
+
+/* uniform single variable */
+template <typename TType>
+class GLCmdUniformT
+    : public GLCmdUniform
+{
+public:
+    GLCmdUniformT (const GLchar *name, TType value)
+        : GLCmdUniform (name)
+        , _value (value)
+    {}
+    ~GLCmdUniformT () {}
+
+private:
+    virtual GLenum uniform (GLint location) {
+        return UniformOps::uniform <TType> (location, _value);
+    }
+
+private:
+    TType        _value;
+};
+
+/* uniform array: TType array[TCount] */
+template <typename TType, int TCount>
+class GLCmdUniformTArray
+    : public GLCmdUniform
+{
+public:
+    GLCmdUniformTArray (const GLchar *name, const TType *value)
+        : GLCmdUniform (name)
+    {
+        XCAM_ASSERT (value);
+        memcpy (&_value[0], value, sizeof (TType) * TCount);
+    }
+    ~GLCmdUniformTArray () {}
+
+private:
+    virtual GLenum uniform (GLint location) {
+        return UniformOps::uniform_array <TType> (location, _value, TCount);
+    }
+
+private:
+    TType        _value[TCount];
+};
+
+/* uniform vectors: TType vec{TDim}[TCount]*/
+template <typename TType, int TDim, int TCount = 1>
+class GLCmdUniformTVect
+    : public GLCmdUniform
+{
+public:
+    GLCmdUniformTVect (const GLchar *name, const TType *value)
+        : GLCmdUniform (name)
+    {
+        XCAM_ASSERT (value);
+        memcpy (&_value[0], value, sizeof (TType) * TDim * TCount);
+    }
+    ~GLCmdUniformTVect () {}
+
+private:
+    virtual GLenum uniform (GLint location) {
+        return UniformOps::uniform_vect <TType, TDim> (location, _value, TCount);
+    }
+
+private:
+    TType        _value[TDim * TCount];
+};
+
+/* uniform matrix: TType mat{TColumns}x{TRows}[TCount], only support square matrix */
+template <typename TType, int TColumns, int TRows, int TCount = 1>
+class GLCmdUniformTMat
+    : public GLCmdUniform
+{
+public:
+    GLCmdUniformTMat (const GLchar *name, const TType *value)
+        : GLCmdUniform (name)
+    {
+        XCAM_ASSERT (value);
+        memcpy (&_value[0], value, sizeof (TType) * TColumns * TRows * TCount);
+    }
+    ~GLCmdUniformTMat () {}
+
+private:
+    virtual GLenum uniform (GLint location) {
+        XCAM_FAIL_RETURN (
+            ERROR, TColumns == TRows, -1,
+            "uniform_mat only support square matrix, invalid dimension:%dx%d", TColumns, TRows);
+
+        return UniformOps::uniform_mat <TType, TColumns> (location, _value, TCount);
+    }
+
+private:
+    TType        _value[TColumns * TRows * TCount];
+};
+
+class GLBuffer;
+
+class GLCmdBindBufBase
+    : public GLCommand
+{
+public:
+    GLCmdBindBufBase (const SmartPtr<GLBuffer> &buf, uint32_t index);
+    virtual ~GLCmdBindBufBase ();
+
+    virtual XCamReturn run (GLuint program);
+
+private:
+    SmartPtr<GLBuffer>        _buf;
+    uint32_t                  _index;
+};
+
+class GLCmdBindBufRange
+    : public GLCommand
+{
+public:
+    GLCmdBindBufRange (const SmartPtr<GLBuffer> &buf, uint32_t index, uint32_t offset_x = 0);
+    GLCmdBindBufRange (
+        const SmartPtr<GLBuffer> &buf, uint32_t index, NV12PlaneIdx plane, uint32_t offset_in_plane = 0);
+    virtual ~GLCmdBindBufRange ();
+
+    virtual XCamReturn run (GLuint program);
+
+private:
+    SmartPtr<GLBuffer>        _buf;
+    uint32_t                  _index;
+    uint32_t                  _offset;
+    uint32_t                  _size;
+};
+
+}
+
+#endif // XCAM_GL_COMMAND_H
\ No newline at end of file
diff --git a/modules/gles/gl_compute_program.cpp b/modules/gles/gl_compute_program.cpp
new file mode 100644
index 0000000..13649ad
--- /dev/null
+++ b/modules/gles/gl_compute_program.cpp
@@ -0,0 +1,178 @@
+/*
+ * gl_compute_program.cpp - GL compute program implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_compute_program.h"
+
+namespace XCam {
+
+GLGroupsSize GLComputeProgram::_max_groups_size;
+
+GLComputeProgram::GLComputeProgram (GLuint id, const char *name)
+    : GLProgram (id, name)
+    , _barrier (false)
+    , _barrier_bit (GL_SHADER_STORAGE_BARRIER_BIT)
+{
+    if (_max_groups_size.x == 0 && _max_groups_size.y == 0 && _max_groups_size.z == 0) {
+        get_max_groups_size (_max_groups_size);
+    }
+}
+
+GLComputeProgram::~GLComputeProgram ()
+{
+}
+
+SmartPtr<GLComputeProgram>
+GLComputeProgram::create_compute_program (const char *name)
+{
+    GLuint prog_id = glCreateProgram ();
+    XCAM_FAIL_RETURN (
+        ERROR, prog_id, NULL,
+        "create GL program(%s) failed, prog_id: %d, error flag: %s",
+        XCAM_STR (name), prog_id, gl_error_string (gl_error ()));
+
+    SmartPtr<GLComputeProgram> compute_prog = new GLComputeProgram (prog_id, name);
+    XCAM_FAIL_RETURN (
+        ERROR, compute_prog.ptr (), NULL,
+        "create GL compute program(%s) failed", XCAM_STR (name));
+
+    return compute_prog;
+}
+
+bool query_max_groups_size (GLuint idx, GLint &value)
+{
+    glGetIntegeri_v (GL_MAX_COMPUTE_WORK_GROUP_COUNT, idx, &value);
+
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, false,
+        "GLComputeProgram query max groups size failed, idx:%d, error flag: %s",
+        idx, gl_error_string (error));
+
+    return true;
+}
+
+bool
+GLComputeProgram::get_max_groups_size (GLGroupsSize &size)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        query_max_groups_size (0, size.x) &&
+        query_max_groups_size (1, size.y) &&
+        query_max_groups_size (2, size.z),
+        false,
+        "GLComputeProgram(%s) get max groups size failed", XCAM_STR (get_name ()));
+
+    return true;
+}
+
+bool
+GLComputeProgram::check_groups_size (const GLGroupsSize &size)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        size.x > 0 && size.x <= _max_groups_size.x &&
+        size.y > 0 && size.y <= _max_groups_size.y &&
+        size.z > 0 && size.z <= _max_groups_size.z,
+        false,
+        "GLComputeProgram(%s) invalid groups size: %dx%dx%d",
+        XCAM_STR (get_name ()), size.x, size.y, size.z);
+
+    return true;
+}
+
+bool
+GLComputeProgram::set_groups_size (const GLGroupsSize &size)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, check_groups_size (size), false,
+        "GLComputeProgram(%s) set groups size failed, groups size: %dx%dx%d",
+        XCAM_STR (get_name ()), size.x, size.y, size.z);
+
+    _groups_size = size;
+
+    return true;
+}
+
+XCamReturn
+GLComputeProgram::work ()
+{
+    XCamReturn ret = dispatch ();
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLComputeProgram(%s) dispatch failed", XCAM_STR (get_name ()));
+
+    if (_barrier) {
+        ret = barrier (_barrier_bit);
+        XCAM_FAIL_RETURN (
+            ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+            "GLComputeProgram(%s) barrier failed", XCAM_STR (get_name ()));
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLComputeProgram::barrier (GLbitfield barrier_bit)
+{
+    glMemoryBarrier (barrier_bit);
+
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GLComputeProgram(%s) barrier failed, barrier bit: %d, error flag: %s",
+        XCAM_STR (get_name ()), barrier_bit, gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLComputeProgram::finish ()
+{
+    glFinish ();
+
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GLComputeProgram(%s) finish failed, error flag: %s",
+        XCAM_STR (get_name ()), gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLComputeProgram::dispatch ()
+{
+    XCAM_FAIL_RETURN (
+        ERROR, check_groups_size (_groups_size), XCAM_RETURN_ERROR_PARAM,
+        "GLComputeProgram(%s) dispatch invalid groups size: %dx%dx%d",
+        XCAM_STR (get_name ()), _groups_size.x, _groups_size.y, _groups_size.z);
+
+    glDispatchCompute (_groups_size.x, _groups_size.y, _groups_size.z);
+
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GLComputeProgram(%s) dispatch failed, groups size: %dx%dx%d, error flag: %s",
+        XCAM_STR (get_name ()), _groups_size.x, _groups_size.y, _groups_size.z, gl_error_string (error));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
diff --git a/modules/gles/gl_compute_program.h b/modules/gles/gl_compute_program.h
new file mode 100644
index 0000000..66a5c81
--- /dev/null
+++ b/modules/gles/gl_compute_program.h
@@ -0,0 +1,70 @@
+/*
+ * gl_compute_program.h - GL compute program class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_COMPUTE_PROGRAM_H
+#define XCAM_GL_COMPUTE_PROGRAM_H
+
+#include <gles/gl_program.h>
+
+namespace XCam {
+
+struct GLGroupsSize {
+    GLint x, y, z;
+    GLGroupsSize () : x (0), y (0), z (0) {}
+};
+
+class GLComputeProgram
+    : public GLProgram
+{
+public:
+    static SmartPtr<GLComputeProgram> create_compute_program (const char *name = NULL);
+    ~GLComputeProgram ();
+
+    bool set_groups_size (const GLGroupsSize &size);
+    void set_barrier (bool barrier, GLbitfield barrier_bit = GL_SHADER_STORAGE_BARRIER_BIT) {
+        _barrier = barrier;
+        _barrier_bit = barrier_bit;
+    }
+
+    virtual XCamReturn work ();
+    virtual XCamReturn finish ();
+
+private:
+    explicit GLComputeProgram (GLuint id, const char *name);
+
+    XCamReturn dispatch ();
+    XCamReturn barrier (GLbitfield barrier_bit);
+
+    bool get_max_groups_size (GLGroupsSize &size);
+    bool check_groups_size (const GLGroupsSize &size);
+
+private:
+    XCAM_DEAD_COPY (GLComputeProgram);
+
+private:
+    bool                       _barrier;
+    GLbitfield                 _barrier_bit;
+    GLGroupsSize               _groups_size;
+    static GLGroupsSize        _max_groups_size;
+};
+
+}
+
+#endif // XCAM_GL_COMPUTE_PROGRAM_H
diff --git a/modules/gles/gl_copy_handler.cpp b/modules/gles/gl_copy_handler.cpp
new file mode 100644
index 0000000..a29c23a
--- /dev/null
+++ b/modules/gles/gl_copy_handler.cpp
@@ -0,0 +1,228 @@
+/*
+ * gl_copy_handler.cpp - gl copy handler implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_copy_handler.h"
+#include "gl_utils.h"
+
+#define INVALID_INDEX (uint32_t)(-1)
+
+namespace XCam {
+
+DECLARE_WORK_CALLBACK (CbCopyShader, GLCopyHandler, copy_shader_done);
+
+const GLShaderInfo shader_info = {
+    GL_COMPUTE_SHADER,
+    "shader_copy",
+#include "shader_copy.comp.slx"
+    , 0
+};
+
+XCamReturn
+GLCopyShader::prepare_arguments (const SmartPtr<Worker::Arguments> &base, GLCmdList &cmds)
+{
+    SmartPtr<GLCopyShader::Args> args = base.dynamic_cast_ptr<GLCopyShader::Args> ();
+    XCAM_ASSERT (args.ptr () && args->in_buf.ptr () && args->out_buf.ptr ());
+
+    const GLBufferDesc &in_desc = args->in_buf->get_buffer_desc ();
+    const GLBufferDesc &out_desc = args->out_buf->get_buffer_desc ();
+    const Rect &in_area = args->in_area;
+    const Rect &out_area = args->out_area;
+
+    XCAM_ASSERT (in_area.pos_y == 0 && out_area.pos_y == 0);
+    XCAM_ASSERT (in_area.width == out_area.width && in_area.height == out_area.height);
+    XCAM_ASSERT (uint32_t(in_area.height) == in_desc.height && uint32_t(out_area.height) == out_desc.height);
+
+    cmds.push_back (new GLCmdBindBufRange (args->in_buf, 0));
+    cmds.push_back (new GLCmdBindBufRange (args->out_buf, 1));
+
+    size_t unit_bytes = 4 * sizeof (uint32_t);
+    uint32_t in_img_width = XCAM_ALIGN_UP (in_desc.aligned_width, unit_bytes) / unit_bytes;
+    uint32_t in_x_offset = XCAM_ALIGN_UP (in_area.pos_x, unit_bytes) / unit_bytes;
+    uint32_t out_img_width = XCAM_ALIGN_UP (out_desc.aligned_width, unit_bytes) / unit_bytes;
+    uint32_t out_x_offset = XCAM_ALIGN_UP (out_area.pos_x, unit_bytes) / unit_bytes;
+    uint32_t copy_width = XCAM_ALIGN_UP (in_area.width, unit_bytes) / unit_bytes;
+    uint32_t copy_height = XCAM_ALIGN_UP (in_area.height, 2) / 2 * 3;
+
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_width", in_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_x_offset", in_x_offset));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_img_width", out_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_x_offset", out_x_offset));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("copy_width", copy_width));
+
+    GLGroupsSize groups_size;
+    groups_size.x = XCAM_ALIGN_UP (copy_width, 8) / 8;
+    groups_size.y = XCAM_ALIGN_UP (copy_height, 8) / 8;
+    groups_size.z = 1;
+
+    SmartPtr<GLComputeProgram> prog;
+    XCAM_FAIL_RETURN (
+        ERROR, get_compute_program (prog), XCAM_RETURN_ERROR_PARAM,
+        "GLCopyShader(%s) get compute program (idx:%d) failed", XCAM_STR (get_name ()), args->index);
+    prog->set_groups_size (groups_size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+GLCopyHandler::GLCopyHandler (const char *name)
+    : GLImageHandler (name)
+    , _index (INVALID_INDEX)
+{
+}
+
+GLCopyHandler::~GLCopyHandler ()
+{
+}
+
+XCamReturn
+GLCopyHandler::copy (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf)
+{
+    SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in_buf, out_buf);
+    XCAM_ASSERT (param.ptr ());
+
+    XCamReturn ret = execute_buffer (param, false);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GLCopyHandler(%s) copy failed", XCAM_STR (get_name ()));
+
+    _copy_shader->finish ();
+    if (!out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+bool
+GLCopyHandler::set_copy_area (uint32_t idx, const Rect &in_area, const Rect &out_area)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        idx != INVALID_INDEX &&
+        in_area.width == out_area.width && in_area.height == out_area.height,
+        false,
+        "GLCopyHandler(%s): set copy area(idx:%d) failed, input size:%dx%d output size:%dx%d", 
+        XCAM_STR (get_name ()), idx, in_area.width, in_area.height, out_area.width, out_area.height);
+
+    _index = idx;
+    _in_area = in_area;
+    _out_area = out_area;
+
+    XCAM_LOG_DEBUG ("GLCopyHandler: copy area (idx:%d) input area(%d, %d, %d, %d) output area(%d, %d, %d, %d)",
+        idx,
+        in_area.pos_x, in_area.pos_y, in_area.width, in_area.height,
+        out_area.pos_x, out_area.pos_y, out_area.width, out_area.height);
+
+    return true;
+}
+
+XCamReturn
+GLCopyHandler::configure_resource (const SmartPtr<Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr ());
+    XCAM_ASSERT (!_copy_shader.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR,
+        _index != INVALID_INDEX &&
+        _in_area.width && _in_area.height && _out_area.width && _out_area.height,
+        XCAM_RETURN_ERROR_PARAM,
+        "GLCopyHandler(%s) invalid copy area, need set copy area first", XCAM_STR (get_name ()));
+
+    _copy_shader = create_copy_shader ();
+    XCAM_FAIL_RETURN (
+        ERROR, _copy_shader.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "GLCopyHandler(%s) create copy shader (idx:%d) failed", XCAM_STR (get_name ()), _index);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLCopyHandler::start_work (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ());
+
+    XCamReturn ret = start_copy_shader (param);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GLCopyHandler(%s) start work (idx:%d) failed", XCAM_STR (get_name ()), _index);
+
+    param->in_buf.release ();
+
+    return ret;
+};
+
+XCamReturn
+GLCopyHandler::terminate ()
+{
+    if (_copy_shader.ptr ()) {
+        _copy_shader.release ();
+    }
+    return GLImageHandler::terminate ();
+}
+
+SmartPtr<GLCopyShader>
+GLCopyHandler::create_copy_shader ()
+{
+    SmartPtr<Worker::Callback> cb = new CbCopyShader (this);
+    XCAM_ASSERT (cb.ptr ());
+
+    SmartPtr<GLCopyShader> shader = new GLCopyShader (cb);
+    XCAM_ASSERT (shader.ptr ());
+
+    XCamReturn ret = shader->create_compute_program (shader_info, "copy_program");
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
+        "GLCopyHandler(%s) create compute program failed", XCAM_STR (get_name ()));
+
+    return shader;
+}
+
+XCamReturn
+GLCopyHandler::start_copy_shader (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ());
+    XCAM_ASSERT (_copy_shader.ptr ());
+
+    SmartPtr<GLCopyShader::Args> args = new GLCopyShader::Args (param);
+    XCAM_ASSERT (args.ptr ());
+    args->in_buf = get_glbuffer (param->in_buf);
+    args->out_buf = get_glbuffer (param->out_buf);
+    args->index = _index;
+    args->in_area = _in_area;
+    args->out_area = _out_area;
+
+    return _copy_shader->work (args);
+}
+
+void
+GLCopyHandler::copy_shader_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_ASSERT (worker.ptr () == _copy_shader.ptr ());
+
+    SmartPtr<GLCopyShader::Args> args = base.dynamic_cast_ptr<GLCopyShader::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+}
+
+}
diff --git a/modules/gles/gl_copy_handler.h b/modules/gles/gl_copy_handler.h
new file mode 100644
index 0000000..9235cfb
--- /dev/null
+++ b/modules/gles/gl_copy_handler.h
@@ -0,0 +1,93 @@
+/*
+ * gl_copy_handler.h - gl copy handler class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_COPY_HANDER_H
+#define XCAM_GL_COPY_HANDER_H
+
+#include <xcam_utils.h>
+#include <gles/gl_image_shader.h>
+#include <gles/gl_image_handler.h>
+
+namespace XCam {
+
+class GLCopyShader
+    : public GLImageShader
+{
+public:
+    struct Args : GLArgs {
+        uint32_t                  index;
+        Rect                      in_area, out_area;
+        SmartPtr<GLBuffer>        in_buf, out_buf;
+
+        Args (const SmartPtr<ImageHandler::Parameters> &param)
+            : GLArgs (param)
+            , index (0)
+        {}
+    };
+
+public:
+    explicit GLCopyShader (const SmartPtr<Worker::Callback> &cb)
+        : GLImageShader ("GLCopyShader", cb)
+    {}
+
+    ~GLCopyShader () {}
+
+private:
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+};
+
+class GLCopyHandler
+    : public GLImageHandler
+{
+    friend class CbCopyShader;
+
+public:
+    GLCopyHandler (const char *name = "GLCopyHandler");
+    ~GLCopyHandler ();
+
+    bool set_copy_area (uint32_t idx, const Rect &in_area, const Rect &out_area);
+    uint32_t get_index () {
+        return _index;
+    }
+    XCamReturn copy (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf);
+
+    //derived from ImageHandler
+    virtual XCamReturn terminate ();
+
+protected:
+    //derived from GLImageHandler
+    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    virtual XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    SmartPtr<GLCopyShader> create_copy_shader ();
+    XCamReturn start_copy_shader (const SmartPtr<ImageHandler::Parameters> &param);
+    void copy_shader_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error);
+
+private:
+    uint32_t                      _index;
+    Rect                          _in_area;
+    Rect                          _out_area;
+    SmartPtr<GLCopyShader>        _copy_shader;
+};
+
+}
+#endif // XCAM_GL_COPY_HANDER_H
diff --git a/modules/gles/gl_geomap_handler.cpp b/modules/gles/gl_geomap_handler.cpp
new file mode 100644
index 0000000..67a06de
--- /dev/null
+++ b/modules/gles/gl_geomap_handler.cpp
@@ -0,0 +1,403 @@
+/*
+ * gl_geomap_handler.cpp - gl geometry map handler implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_geomap_handler.h"
+#include "gl_utils.h"
+
+#define XCAM_GL_GEOMAP_ALIGN_X 4
+#define XCAM_GL_GEOMAP_ALIGN_Y 2
+
+namespace XCam {
+
+DECLARE_WORK_CALLBACK (CbGeoMapShader, GLGeoMapHandler, geomap_shader_done);
+
+const GLShaderInfo shader_info = {
+    GL_COMPUTE_SHADER,
+    "shader_geomap",
+#include "shader_geomap.comp.slx"
+    , 0
+};
+
+bool
+GLGeoMapShader::set_std_step (float factor_x, float factor_y)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f), false,
+        "GLGeoMapShader(%s) invalid standard factors: x:%f, y:%f", XCAM_STR (get_name ()), factor_x, factor_y);
+
+    _lut_std_step[0] = 1.0f / factor_x;
+    _lut_std_step[1] = 1.0f / factor_y;
+
+    return true;
+}
+
+XCamReturn
+GLGeoMapShader::prepare_arguments (const SmartPtr<Worker::Arguments> &base, GLCmdList &cmds)
+{
+    SmartPtr<GLGeoMapShader::Args> args = base.dynamic_cast_ptr<GLGeoMapShader::Args> ();
+    XCAM_ASSERT (args.ptr () && args->in_buf.ptr () && args->out_buf.ptr () && args->lut_buf.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR,
+        !XCAM_DOUBLE_EQUAL_AROUND (args->factors[0], 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (args->factors[1], 0.0f) &&
+        !XCAM_DOUBLE_EQUAL_AROUND (args->factors[2], 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (args->factors[3], 0.0f),
+        XCAM_RETURN_ERROR_PARAM,
+        "GLGeoMapHandler(%s) invalid factors: %f, %f, %f, %f",
+        XCAM_STR (get_name ()), args->factors[0], args->factors[1], args->factors[2], args->factors[3]);
+
+    const GLBufferDesc &in_desc = args->in_buf->get_buffer_desc ();
+    const GLBufferDesc &out_desc = args->out_buf->get_buffer_desc ();
+    const GLBufferDesc &lut_desc = args->lut_buf->get_buffer_desc ();
+
+    cmds.push_back (new GLCmdBindBufRange (args->in_buf, 0, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->in_buf, 1, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_buf, 2, NV12PlaneYIdx));
+    cmds.push_back (new GLCmdBindBufRange (args->out_buf, 3, NV12PlaneUVIdx));
+    cmds.push_back (new GLCmdBindBufBase (args->lut_buf, 4));
+
+    size_t unit_bytes = sizeof (uint32_t);
+    uint32_t in_img_width = XCAM_ALIGN_UP (in_desc.width, unit_bytes) / unit_bytes;
+    uint32_t out_img_width = XCAM_ALIGN_UP (out_desc.width, unit_bytes) / unit_bytes;
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_width", in_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("in_img_height", in_desc.height));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_img_width", out_img_width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("out_img_height", out_desc.height));
+
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("lut_width", lut_desc.width));
+    cmds.push_back (new GLCmdUniformT<uint32_t> ("lut_height", lut_desc.height));
+
+    float lut_step[4];
+    lut_step[0] = 1.0f / args->factors[0];
+    lut_step[1] = 1.0f / args->factors[1];
+    lut_step[2] = 1.0f / args->factors[2];
+    lut_step[3] = 1.0f / args->factors[3];
+    cmds.push_back (new GLCmdUniformTVect<float, 4> ("lut_step", lut_step));
+    cmds.push_back (new GLCmdUniformTVect<float, 2> ("lut_std_step", _lut_std_step));
+
+    GLGroupsSize groups_size;
+    groups_size.x = XCAM_ALIGN_UP (out_img_width, 8) / 8;
+    groups_size.y = XCAM_ALIGN_UP (out_desc.height, 16) / 16;
+    groups_size.z = 1;
+
+    SmartPtr<GLComputeProgram> prog;
+    XCAM_FAIL_RETURN (
+        ERROR, get_compute_program (prog), XCAM_RETURN_ERROR_PARAM,
+        "GLGeoMapShader(%s) get compute program failed", XCAM_STR (get_name ()));
+    prog->set_groups_size (groups_size);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+GLGeoMapHandler::GLGeoMapHandler (const char *name)
+    : GLImageHandler (name)
+{
+}
+
+GLGeoMapHandler::~GLGeoMapHandler ()
+{
+}
+
+XCamReturn
+GLGeoMapHandler::remap (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf)
+{
+    SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in_buf, out_buf);
+    XCAM_ASSERT (param.ptr ());
+
+    XCamReturn ret = execute_buffer (param, false);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GLGeoMapHandler(%s) remap failed", XCAM_STR (get_name ()));
+
+    _geomap_shader->finish ();
+    if (!out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+bool
+GLGeoMapHandler::set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, data && width && height, false,
+        "GLGeoMapHandler(%s) set look up table failed, data ptr:%p, width:%d, height:%d",
+        XCAM_STR (get_name ()), data, width, height);
+    XCAM_ASSERT (!_lut_buf.ptr ());
+
+    uint32_t lut_size = width * height * 2 * sizeof (float);
+    SmartPtr<GLBuffer> buf = GLBuffer::create_buffer (GL_SHADER_STORAGE_BUFFER, NULL, lut_size);
+    XCAM_ASSERT (buf.ptr ());
+
+    GLBufferDesc desc;
+    desc.width = width;
+    desc.height = height;
+    desc.size = lut_size;
+    buf->set_buffer_desc (desc);
+
+    float *ptr = (float *) buf->map_range (0, lut_size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
+    XCAM_FAIL_RETURN (ERROR, ptr, false, "GLGeoMapHandler(%s) map range failed", XCAM_STR (get_name ()));
+    for (uint32_t i = 0; i < height; ++i) {
+        float *ret = &ptr[i * width * 2];
+        const PointFloat2 *line = &data[i * width];
+
+        for (uint32_t j = 0; j < width; ++j) {
+            ret[j * 2] = line[j].x;
+            ret[j * 2 + 1] = line[j].y;
+        }
+    }
+    buf->unmap ();
+    _lut_buf = buf;
+
+    return true;
+}
+
+bool
+GLGeoMapHandler::init_factors ()
+{
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+
+    if (!XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f))
+        return true;
+
+    const GLBufferDesc &lut_desc = _lut_buf->get_buffer_desc ();
+    return auto_calculate_factors (lut_desc.width, lut_desc.height);
+}
+
+XCamReturn
+GLGeoMapHandler::configure_resource (const SmartPtr<Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, _lut_buf.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "GLGeoMapHandler(%s) configure failed, look up table is empty", XCAM_STR (get_name ()));
+
+    const VideoBufferInfo &in_info = param->in_buf->get_video_info ();
+    XCAM_FAIL_RETURN (
+        ERROR, in_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
+        "GLGeoMapHandler(%s) only support NV12 format, but input format is %s",
+        XCAM_STR (get_name ()), xcam_fourcc_to_string (in_info.format));
+
+    uint32_t width, height;
+    get_output_size (width, height);
+    VideoBufferInfo out_info;
+    out_info.init (
+        in_info.format, width, height,
+        XCAM_ALIGN_UP (width, XCAM_GL_GEOMAP_ALIGN_X),
+        XCAM_ALIGN_UP (height, XCAM_GL_GEOMAP_ALIGN_Y));
+    set_out_video_info (out_info);
+
+    init_factors ();
+
+    XCAM_ASSERT (!_geomap_shader.ptr ());
+    _geomap_shader = create_geomap_shader ();
+    XCAM_FAIL_RETURN (
+        ERROR, _geomap_shader.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "GLGeoMapHandler(%s) create geomap shader failed", XCAM_STR (get_name ()));
+
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+    _geomap_shader->set_std_step (factor_x, factor_y);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLGeoMapHandler::start_work (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ());
+
+    XCamReturn ret = start_geomap_shader (param);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "GLGeoMapHandler(%s) start work failed", XCAM_STR (get_name ()));
+
+    param->in_buf.release ();
+
+    return ret;
+};
+
+XCamReturn
+GLGeoMapHandler::terminate ()
+{
+    if (_geomap_shader.ptr ()) {
+        _geomap_shader.release ();
+    }
+
+    return GLImageHandler::terminate ();
+}
+
+SmartPtr<GLGeoMapShader>
+GLGeoMapHandler::create_geomap_shader ()
+{
+    SmartPtr<Worker::Callback> cb = new CbGeoMapShader (this);
+    XCAM_ASSERT (cb.ptr ());
+    SmartPtr<GLGeoMapShader> shader = new GLGeoMapShader (cb);
+    XCAM_ASSERT (shader.ptr ());
+
+    XCamReturn ret = shader->create_compute_program (shader_info, "geomap_program");
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, NULL,
+        "GLGeoMapHandler(%s) create compute program failed", XCAM_STR (get_name ()));
+
+    return shader;
+}
+
+XCamReturn
+GLGeoMapHandler::start_geomap_shader (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ());
+    XCAM_ASSERT (_geomap_shader.ptr ());
+    XCAM_ASSERT (_lut_buf.ptr ());
+
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+
+    SmartPtr<GLGeoMapShader::Args> args = new GLGeoMapShader::Args (param);
+    XCAM_ASSERT (args.ptr ());
+    args->in_buf = get_glbuffer (param->in_buf);
+    args->out_buf = get_glbuffer (param->out_buf);
+    args->lut_buf = _lut_buf;
+    args->factors[0] = factor_x;
+    args->factors[1] = factor_y;
+    args->factors[2] = args->factors[0];
+    args->factors[3] = args->factors[1];
+
+    return _geomap_shader->work (args);
+}
+
+void
+GLGeoMapHandler::geomap_shader_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_ASSERT (worker.ptr () == _geomap_shader.ptr ());
+
+    SmartPtr<GLGeoMapShader::Args> args = base.dynamic_cast_ptr<GLGeoMapShader::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+}
+
+GLDualConstGeoMapHandler::GLDualConstGeoMapHandler (const char *name)
+    : GLGeoMapHandler (name)
+    , _left_factor_x (0.0f)
+    , _left_factor_y (0.0f)
+    , _right_factor_x (0.0f)
+    , _right_factor_y (0.0f)
+{
+}
+
+GLDualConstGeoMapHandler::~GLDualConstGeoMapHandler ()
+{
+}
+
+bool
+GLDualConstGeoMapHandler::set_left_factors (float x, float y)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f), false,
+        "GLGeoMapHandler(%s) set factors failed: x:%f, y:%f", XCAM_STR (get_name ()), x, y);
+
+    _left_factor_x = x;
+    _left_factor_y = y;
+
+    return true;
+}
+
+bool
+GLDualConstGeoMapHandler::set_right_factors (float x, float y)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f), false,
+        "GLGeoMapHandler(%s) set factors failed: x:%f, y:%f", XCAM_STR (get_name ()), x, y);
+
+    _right_factor_x = x;
+    _right_factor_y = y;
+
+    return true;
+}
+
+bool
+GLDualConstGeoMapHandler::init_factors ()
+{
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+
+    if (!XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f))
+        return true;
+
+    const GLBufferDesc &lut_desc = _lut_buf->get_buffer_desc ();
+    XCAM_FAIL_RETURN (
+        ERROR, auto_calculate_factors (lut_desc.width, lut_desc.height), false,
+        "GLGeoMapHandler(%s) auto calculate factors failed");
+
+    get_factors (factor_x, factor_y);
+    _left_factor_x = factor_x;
+    _left_factor_y = factor_y;
+    _right_factor_x = _left_factor_x;
+    _right_factor_y = _left_factor_y;
+
+    return true;
+}
+
+XCamReturn
+GLDualConstGeoMapHandler::start_geomap_shader (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ());
+    XCAM_ASSERT (_geomap_shader.ptr ());
+    XCAM_ASSERT (_lut_buf.ptr ());
+
+    SmartPtr<GLGeoMapShader::Args> args = new GLGeoMapShader::Args (param);
+    XCAM_ASSERT (args.ptr ());
+    args->in_buf = get_glbuffer (param->in_buf);
+    args->out_buf = get_glbuffer (param->out_buf);
+    args->lut_buf = _lut_buf;
+
+    float factor_x, factor_y;
+    get_left_factors (factor_x, factor_y);
+    args->factors[0] = factor_x;
+    args->factors[1] = factor_y;
+
+    get_right_factors (factor_x, factor_y);
+    args->factors[2] = factor_x;
+    args->factors[3] = factor_y;
+
+    return _geomap_shader->work (args);
+}
+
+SmartPtr<GLImageHandler> create_gl_geo_mapper ()
+{
+    SmartPtr<GLImageHandler> mapper = new GLGeoMapHandler ();
+    XCAM_ASSERT (mapper.ptr ());
+
+    return mapper;
+}
+
+SmartPtr<GeoMapper>
+GeoMapper::create_gl_geo_mapper ()
+{
+    SmartPtr<GLImageHandler> handler = XCam::create_gl_geo_mapper ();
+    return handler.dynamic_cast_ptr<GeoMapper> ();
+}
+
+}
diff --git a/modules/gles/gl_geomap_handler.h b/modules/gles/gl_geomap_handler.h
new file mode 100644
index 0000000..30ee221
--- /dev/null
+++ b/modules/gles/gl_geomap_handler.h
@@ -0,0 +1,130 @@
+/*
+ * gl_geomap_handler.h - gl geometry map handler class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_GEOMAP_HANDER_H
+#define XCAM_GL_GEOMAP_HANDER_H
+
+#include <interface/geo_mapper.h>
+#include <gles/gl_image_shader.h>
+#include <gles/gl_image_handler.h>
+
+namespace XCam {
+
+class GLGeoMapShader
+    : public GLImageShader
+{
+public:
+    struct Args : GLArgs {
+        SmartPtr<GLBuffer>        in_buf, out_buf;
+        SmartPtr<GLBuffer>        lut_buf;
+        float                     factors[4];
+
+        Args (const SmartPtr<ImageHandler::Parameters> &param)
+            : GLArgs (param)
+        {}
+    };
+
+public:
+    explicit GLGeoMapShader (const SmartPtr<Worker::Callback> &cb)
+        : GLImageShader ("GLGeoMapShader", cb)
+    {
+        xcam_mem_clear (_lut_std_step);
+    }
+
+    ~GLGeoMapShader () {}
+    bool set_std_step (float factor_x, float factor_y);
+
+private:
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+    XCAM_DEAD_COPY (GLGeoMapShader);
+
+private:
+    float        _lut_std_step[2];
+};
+
+class GLGeoMapHandler
+    : public GLImageHandler, public GeoMapper
+{
+    friend class CbGeoMapShader;
+
+public:
+    GLGeoMapHandler (const char *name = "GLGeoMapHandler");
+    ~GLGeoMapHandler ();
+
+    bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height);
+
+    XCamReturn remap (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf);
+
+    //derived from ImageHandler
+    virtual XCamReturn terminate ();
+
+protected:
+    //derived from GLImageHandler
+    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    virtual XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    virtual bool init_factors ();
+
+    virtual SmartPtr<GLGeoMapShader> create_geomap_shader ();
+    virtual XCamReturn start_geomap_shader (const SmartPtr<ImageHandler::Parameters> &param);
+    virtual void geomap_shader_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error);
+
+    XCAM_DEAD_COPY (GLGeoMapHandler);
+
+protected:
+    SmartPtr<GLBuffer>              _lut_buf;
+    SmartPtr<GLGeoMapShader>        _geomap_shader;
+};
+
+class GLDualConstGeoMapHandler
+    : public GLGeoMapHandler
+{
+public:
+    GLDualConstGeoMapHandler (const char *name = "GLDualConstGeoMapHandler");
+    ~GLDualConstGeoMapHandler ();
+
+    bool set_left_factors (float x, float y);
+    void get_left_factors (float &x, float &y) {
+        x = _left_factor_x;
+        y = _left_factor_y;
+    }
+    bool set_right_factors (float x, float y);
+    void get_right_factors (float &x, float &y) {
+        x = _right_factor_x;
+        y = _right_factor_y;
+    }
+
+private:
+    virtual bool init_factors ();
+    virtual XCamReturn start_geomap_shader (const SmartPtr<ImageHandler::Parameters> &param);
+
+private:
+    float        _left_factor_x;
+    float        _left_factor_y;
+    float        _right_factor_x;
+    float        _right_factor_y;
+};
+
+extern SmartPtr<GLImageHandler> create_gl_geo_mapper ();
+
+}
+#endif // XCAM_GL_GEOMAP_HANDER_H
diff --git a/modules/gles/gl_image_handler.cpp b/modules/gles/gl_image_handler.cpp
new file mode 100644
index 0000000..d95b151
--- /dev/null
+++ b/modules/gles/gl_image_handler.cpp
@@ -0,0 +1,41 @@
+/*
+ * gl_image_handler.cpp - GL image handler implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_image_handler.h"
+#include "gl_video_buffer.h"
+
+namespace XCam {
+
+GLImageHandler::GLImageHandler (const char* name)
+    : ImageHandler (name)
+{
+}
+
+GLImageHandler::~GLImageHandler ()
+{
+}
+
+SmartPtr<BufferPool>
+GLImageHandler::create_allocator ()
+{
+    return new GLVideoBufferPool;
+}
+
+}
diff --git a/modules/gles/gl_image_handler.h b/modules/gles/gl_image_handler.h
new file mode 100644
index 0000000..db5ee54
--- /dev/null
+++ b/modules/gles/gl_image_handler.h
@@ -0,0 +1,47 @@
+/*
+ * gl_image_handler.h - GL image handler class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_IMAGE_HANDLER_H
+#define XCAM_GL_IMAGE_HANDLER_H
+
+#include <image_handler.h>
+#include <gles/gles_std.h>
+
+namespace XCam {
+
+class GLImageHandler
+    : public ImageHandler
+{
+public:
+    explicit GLImageHandler (const char* name);
+    ~GLImageHandler ();
+
+private:
+    SmartPtr<BufferPool> create_allocator ();
+
+private:
+    XCAM_DEAD_COPY (GLImageHandler);
+
+private:
+};
+
+}
+
+#endif // XCAM_GL_IMAGE_HANDLER_H
diff --git a/modules/gles/gl_image_shader.cpp b/modules/gles/gl_image_shader.cpp
new file mode 100644
index 0000000..3b1a92f
--- /dev/null
+++ b/modules/gles/gl_image_shader.cpp
@@ -0,0 +1,191 @@
+/*
+ * gl_image_shader.cpp - gl image shader implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_image_shader.h"
+
+#define ENABLE_DEBUG_SHADER 0
+
+namespace XCam {
+
+GLImageShader::GLImageShader (const char *name, const SmartPtr<Callback> &cb)
+    : Worker (name, cb)
+{
+    XCAM_OBJ_PROFILING_INIT;
+}
+
+GLImageShader::~GLImageShader ()
+{
+}
+
+XCamReturn
+GLImageShader::finish ()
+{
+    _program->finish ();
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLImageShader::stop ()
+{
+    return XCAM_RETURN_NO_ERROR;
+}
+
+bool
+GLImageShader::get_compute_program (SmartPtr<GLComputeProgram> &prog)
+{
+    prog = _program.dynamic_cast_ptr<GLComputeProgram> ();
+    XCAM_FAIL_RETURN (
+        ERROR, prog.ptr (), false,
+        "GLImageShader(%s) convert to GLComputeProgram failed", XCAM_STR (get_name ()));
+
+    return true;
+}
+
+XCamReturn
+GLImageShader::work (const SmartPtr<Worker::Arguments> &args)
+{
+    XCamReturn ret = _program->use ();
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) use program failed", XCAM_STR (get_name ()));
+
+    ret = pre_work (args);
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) pre-work failed", XCAM_STR (get_name ()));
+
+#if ENABLE_DEBUG_SHADER
+    XCAM_OBJ_PROFILING_START;
+#endif
+
+    ret = _program->work ();
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) work failed", XCAM_STR (get_name ()));
+
+#if ENABLE_DEBUG_SHADER
+    ret = _program->finish ();
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) finish failed", XCAM_STR (get_name ()));
+
+    char name[XCAM_GL_NAME_LENGTH] = {'\0'};
+    snprintf (name, sizeof (name), "%s-%p", XCAM_STR (get_name ()), this);
+    XCAM_OBJ_PROFILING_END (name, XCAM_OBJ_DUR_FRAME_NUM);
+#endif
+
+    ret = _program->disuse ();
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) disuse program failed", XCAM_STR (get_name ()));
+
+    status_check (args, ret);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLImageShader::pre_work (const SmartPtr<Worker::Arguments> &args)
+{
+    GLCmdList cmds;
+
+    XCamReturn ret = prepare_arguments (args, cmds);
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) prepare arguments failed", XCAM_STR (get_name ()));
+
+    ret = set_commands (cmds);
+    XCAM_FAIL_RETURN (
+        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) set commands failed", XCAM_STR (get_name ()));
+
+    return ret;
+}
+XCamReturn
+GLImageShader::prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds)
+{
+    XCAM_UNUSED (args);
+    XCAM_UNUSED (cmds);
+
+    XCAM_LOG_ERROR ("GLImageShader(%s) prepare arguments error", XCAM_STR (get_name ()));
+    return XCAM_RETURN_ERROR_GLES;
+}
+
+XCamReturn
+GLImageShader::set_commands (const GLCmdList &cmds)
+{
+    GLuint prog_id = _program->get_program_id();
+    XCAM_FAIL_RETURN (
+        WARNING, prog_id, XCAM_RETURN_ERROR_PARAM,
+        "GLImageShader(%s) invalid program id:%d", XCAM_STR (get_name ()), prog_id);
+
+    uint32_t i_count = 0;
+    for (GLCmdList::const_iterator iter = cmds.begin (); iter != cmds.end (); ++iter, ++i_count) {
+        const SmartPtr<GLCommand> &cmd = *iter;
+        XCAM_FAIL_RETURN (
+            WARNING, cmd.ptr (), XCAM_RETURN_ERROR_MEM,
+            "GLImageShader(%s) command(idx:%d) is NULL", XCAM_STR (get_name ()), i_count);
+
+        XCamReturn ret = cmd->run (prog_id);
+        XCAM_FAIL_RETURN (
+            WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
+            "GLImageShader(%s) command(idx:%d) run failed", XCAM_STR (get_name ()));
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLImageShader::create_compute_program (const GLShaderInfo &info, const char *name)
+{
+    SmartPtr<GLComputeProgram> program = GLComputeProgram::create_compute_program (name);
+    XCAM_FAIL_RETURN (
+        ERROR, program.ptr (), XCAM_RETURN_ERROR_GLES,
+        "GLImageShader(%s) create compute program(%s) failed", XCAM_STR (get_name ()), XCAM_STR (name));
+
+    XCamReturn ret = program->link_shader (info);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) program(%s) pour shader failed", XCAM_STR (get_name ()), XCAM_STR (name));
+
+    _program = program;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLImageShader::create_compute_program (const GLShaderInfoList &infos, const char *name)
+{
+    SmartPtr<GLComputeProgram> program = GLComputeProgram::create_compute_program (name);
+    XCAM_FAIL_RETURN (
+        ERROR, program.ptr (), XCAM_RETURN_ERROR_GLES,
+        "GLImageShader(%s) create compute program(%s) failed", XCAM_STR (get_name ()), XCAM_STR (name));
+
+    XCamReturn ret = program->link_shaders (infos);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLImageShader(%s) program(%s) pour shaders failed", XCAM_STR (get_name ()), XCAM_STR (name));
+
+    _program = program;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+};
diff --git a/modules/gles/gl_image_shader.h b/modules/gles/gl_image_shader.h
new file mode 100644
index 0000000..47666d3
--- /dev/null
+++ b/modules/gles/gl_image_shader.h
@@ -0,0 +1,81 @@
+/*
+ * gl_image_shader.h - gl image shader class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_IMAGE_SHADER_H
+#define XCAM_GL_IMAGE_SHADER_H
+
+#include <worker.h>
+#include <image_handler.h>
+#include <gles/gles_std.h>
+#include <gles/gl_command.h>
+#include <gles/gl_compute_program.h>
+
+namespace XCam {
+
+struct GLArgs
+    : Worker::Arguments
+{
+private:
+    SmartPtr<ImageHandler::Parameters> _param;
+
+public:
+    explicit GLArgs (const SmartPtr<ImageHandler::Parameters> &param = NULL) : _param (param) {}
+    inline const SmartPtr<ImageHandler::Parameters> &get_param () const {
+        return _param;
+    }
+    inline void set_param (const SmartPtr<ImageHandler::Parameters> &param) {
+        XCAM_ASSERT (param.ptr ());
+        _param = param;
+    }
+};
+
+class GLImageShader
+    : public Worker
+{
+public:
+    explicit GLImageShader (const char *name, const SmartPtr<Callback> &cb = NULL);
+    virtual ~GLImageShader ();
+
+    XCamReturn set_commands (const GLCmdList &cmds);
+    bool get_compute_program (SmartPtr<GLComputeProgram> &prog);
+
+    // derived from Worker
+    virtual XCamReturn work (const SmartPtr<Arguments> &args);
+    virtual XCamReturn finish ();
+    virtual XCamReturn stop ();
+
+    XCamReturn create_compute_program (const GLShaderInfo &info, const char *name = NULL);
+    XCamReturn create_compute_program (const GLShaderInfoList &infos, const char *name  = NULL);
+
+private:
+    XCamReturn pre_work (const SmartPtr<Worker::Arguments> &args);
+    virtual XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args, GLCmdList &cmds);
+
+private:
+    XCAM_DEAD_COPY (GLImageShader);
+
+private:
+    SmartPtr<GLProgram>        _program;
+
+    XCAM_OBJ_PROFILING_DEFINES;
+};
+
+}
+#endif // XCAM_GL_IMAGE_SHADER_H
diff --git a/modules/gles/gl_program.cpp b/modules/gles/gl_program.cpp
new file mode 100644
index 0000000..f6b9166
--- /dev/null
+++ b/modules/gles/gl_program.cpp
@@ -0,0 +1,247 @@
+/*
+ * gl_program.cpp - GL Program
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "gl_program.h"
+
+namespace XCam {
+
+GLProgram::GLProgram (GLuint id, const char *name)
+    : _program_id (id)
+    , _state (GLProgram::StateIntiated)
+{
+    strncpy (_name, XCAM_STR (name), XCAM_GL_NAME_LENGTH - 1);
+}
+
+GLProgram::~GLProgram ()
+{
+    disuse ();
+    clear_shaders ();
+    if (_program_id) {
+        glDeleteProgram (_program_id);
+
+        GLenum error = gl_error ();
+        if (error != GL_NO_ERROR) {
+            XCAM_LOG_WARNING (
+                "GL Program delete program failed, error flag: %s",
+                gl_error_string (error));
+        }
+    }
+}
+
+SmartPtr<GLProgram>
+GLProgram::create_program (const char *name)
+{
+    GLuint program_id = glCreateProgram ();
+    XCAM_FAIL_RETURN (
+        ERROR, program_id, NULL,
+        "Create GL program(%s) failed, error flag: %s",
+        XCAM_STR (name), gl_error_string (gl_error ()));
+
+    return new GLProgram (program_id, name ? name : "null");
+}
+
+XCamReturn
+GLProgram::attach_shader (const SmartPtr<GLShader> &shader)
+{
+    GLuint shader_id = shader->get_shader_id ();
+    XCAM_ASSERT (shader_id);
+    XCAM_FAIL_RETURN (
+        ERROR, _shaders.find (shader_id) == _shaders.end (),
+        XCAM_RETURN_ERROR_PARAM,
+        "GL program(:%s) already have shader (id:%d), do not attach twice",
+        get_name(), shader_id);
+
+    glAttachShader (_program_id, shader_id);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GL program(:%s) attach shader (id:%d) failed, error flag: %s",
+        get_name(), shader_id, gl_error_string (error));
+
+    _shaders.insert (ShaderList::value_type (shader_id, shader));
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::detach_shader (const SmartPtr<GLShader> &shader)
+{
+    GLuint shader_id = shader->get_shader_id ();
+    XCAM_ASSERT (shader_id);
+    ShaderList::iterator pos = _shaders.find (shader_id);
+
+    XCAM_FAIL_RETURN (
+        WARNING, pos == _shaders.end (),
+        XCAM_RETURN_ERROR_PARAM,
+        "GL program(:%s) do not need to detach shader (id:%d) which is not exist",
+        get_name(), shader_id);
+
+    glDetachShader (_program_id, shader_id);
+    GLenum error = gl_error ();
+    if (error != GL_NO_ERROR) {
+        XCAM_LOG_WARNING (
+            "GL program(:%s) detach shader (id:%d) failed but continued, error flag: %s",
+            get_name(), shader_id, gl_error_string (error));
+    }
+    _shaders.erase (pos);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::clear_shaders ()
+{
+    for (ShaderList::iterator i = _shaders.begin (); i != _shaders.end (); ++i) {
+        SmartPtr<GLShader> shader = i->second;
+        glDetachShader (_program_id, shader->get_shader_id ());
+
+        GLenum error = gl_error ();
+        if (error != GL_NO_ERROR) {
+            XCAM_LOG_WARNING (
+                "GL program(:%s) detach shader (id:%d) failed, error flag: %s",
+                get_name(), shader->get_shader_id (), gl_error_string (error));
+        }
+    }
+    _shaders.clear ();
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::link ()
+{
+    XCAM_ASSERT (_program_id);
+
+    glLinkProgram (_program_id);
+    GLenum error = gl_error ();
+
+    GLint status;
+    std::vector<char> link_log;
+    glGetProgramiv (_program_id, GL_LINK_STATUS, &status);
+    if(status == GL_FALSE) {
+        GLint length;
+        glGetProgramiv (_program_id, GL_INFO_LOG_LENGTH, &length);
+        link_log.resize (length + 1);
+        glGetProgramInfoLog (_program_id, length, &length, &link_log[0]);
+        XCAM_LOG_ERROR(
+            "GL program(:%s) link failed, error flag: %s, link log:%s",
+            get_name(), gl_error_string (error), link_log.data());
+        return XCAM_RETURN_ERROR_GLES;
+    }
+
+    _state = StateLinked;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::use ()
+{
+    XCAM_ASSERT (_program_id);
+    XCAM_FAIL_RETURN (
+        WARNING, _state == StateLinked && !_shaders.empty (), XCAM_RETURN_ERROR_PARAM,
+        "GL program(:%s) use must be called after link", get_name());
+
+    glUseProgram (_program_id);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, error == GL_NO_ERROR, XCAM_RETURN_ERROR_GLES,
+        "GL program(:%s) use failed, error flag: %s",
+        get_name(), gl_error_string (error));
+
+    _state = StateInUse;
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::disuse ()
+{
+    if (_state != StateInUse)
+        return XCAM_RETURN_BYPASS;
+
+    glUseProgram (0);
+    GLenum error = gl_error ();
+    if (error != GL_NO_ERROR) {
+        XCAM_LOG_WARNING (
+            "GL program(:%s) disuse failed, error flag: %s",
+            get_name(), gl_error_string (error));
+    }
+
+    _state = StateLinked;
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::link_shader (const GLShaderInfo &info)
+{
+    SmartPtr<GLShader> shader = GLShader::compile_shader (info);
+    XCAM_FAIL_RETURN (
+        ERROR, shader->get_shader_id (), XCAM_RETURN_ERROR_GLES,
+        "GLProgram(%s) create shader(%s) failed", get_name (), info.name);
+
+    XCamReturn ret = attach_shader (shader);
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLProgram(%s) attach shader(%s) failed", get_name (), info.name);
+
+    ret = link ();
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLProgram(%s) link program failed", get_name ());
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::link_shaders (const GLShaderInfoList &infos)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+    for (GLShaderInfoList::const_iterator iter = infos.begin (); iter != infos.end (); ++iter) {
+        const GLShaderInfo &info = *(*iter);
+
+        SmartPtr<GLShader> shader = GLShader::compile_shader (info);
+        XCAM_FAIL_RETURN (
+            ERROR, shader->get_shader_id (), XCAM_RETURN_ERROR_GLES,
+            "GLProgram(%s) create shader(%s) failed", get_name (), info.name);
+
+        ret = attach_shader (shader);
+        XCAM_FAIL_RETURN (
+            ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+            "GLProgram(%s) attach shader(%s) failed", get_name (), info.name);
+    }
+
+    ret = link ();
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
+        "GLProgram(%s) link program(%s) failed", get_name ());
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::work ()
+{
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GLProgram::finish ()
+{
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
diff --git a/modules/gles/gl_program.h b/modules/gles/gl_program.h
new file mode 100644
index 0000000..39090c7
--- /dev/null
+++ b/modules/gles/gl_program.h
@@ -0,0 +1,79 @@
+/*
+ * gl_program.h - GL Program
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_GL_PROGRAM_H
+#define XCAM_GL_PROGRAM_H
+
+#include <gles/gles_std.h>
+#include <gles/gl_shader.h>
+#include <map>
+
+namespace XCam {
+
+class GLProgram
+{
+public:
+    typedef std::map<GLuint, SmartPtr<GLShader>> ShaderList;
+    enum State {
+        StateIntiated  = 0,
+        StateLinked    = 2,
+        StateInUse     = 3,
+    };
+
+    virtual ~GLProgram ();
+    static SmartPtr<GLProgram> create_program (const char *name = NULL);
+    GLuint get_program_id () const {
+        return _program_id;
+    }
+    const char *get_name () {
+        return _name;
+    }
+
+    XCamReturn link_shader (const GLShaderInfo &info);
+    XCamReturn link_shaders (const GLShaderInfoList &infos);
+
+    XCamReturn use ();
+    XCamReturn disuse ();
+
+    virtual XCamReturn work ();
+    virtual XCamReturn finish ();
+
+protected:
+    explicit GLProgram (GLuint id, const char *name);
+
+private:
+    XCamReturn attach_shader (const SmartPtr<GLShader> &shader);
+    XCamReturn detach_shader (const SmartPtr<GLShader> &shader);
+    XCamReturn clear_shaders ();
+    XCamReturn link ();
+
+private:
+    XCAM_DEAD_COPY (GLProgram);
+
+private:
+    ShaderList    _shaders;
+    GLuint        _program_id;
+    State         _state;
+    char          _name [XCAM_GL_NAME_LENGTH];
+};
+
+}
+
+#endif  //XCAM_GL_PROGRAM_H
diff --git a/modules/gles/gl_shader.cpp b/modules/gles/gl_shader.cpp
new file mode 100644
index 0000000..1810c70
--- /dev/null
+++ b/modules/gles/gl_shader.cpp
@@ -0,0 +1,86 @@
+/*
+ * gl_shader.cpp - GL shader
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "gl_shader.h"
+
+namespace XCam {
+
+GLShader::GLShader (GLuint id, GLenum type, const char *name)
+    : _shader_type (type)
+    , _shader_id (id)
+{
+    XCAM_ASSERT (name);
+    strncpy (_name, name, XCAM_GL_NAME_LENGTH - 1);
+}
+
+GLShader::~GLShader ()
+{
+    if (_shader_id) {
+        glDeleteShader (_shader_id);
+
+        GLenum error = gl_error ();
+        if (error != GL_NO_ERROR) {
+            XCAM_LOG_WARNING (
+                "GL Shader delete shader failed, error flag: %s",
+                gl_error_string (error));
+        }
+    }
+}
+
+SmartPtr<GLShader>
+GLShader::compile_shader (const GLShaderInfo &info)
+{
+    GLuint shader_id = glCreateShader (info.type);
+    GLenum error = gl_error ();
+    XCAM_FAIL_RETURN (
+        ERROR, shader_id && (error == GL_NO_ERROR), NULL,
+        "GL create shader(:%s) failed, error flag: %s",
+        XCAM_STR (info.name), gl_error_string (error));
+
+    GLint tmp_len = info.len ? info.len : strlen (info.src);
+    glShaderSource (shader_id, 1, &info.src, &tmp_len);
+    XCAM_FAIL_RETURN (
+        ERROR, (error = gl_error ()) == GL_NO_ERROR, NULL,
+        "GL create shader(:%s) failed in source loading, error flag: %s",
+        XCAM_STR (info.name), gl_error_string (error));
+
+    glCompileShader (shader_id);
+    error = gl_error ();
+
+    GLint status;
+    glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status);
+    if (status == GL_FALSE) {
+        GLint length;
+        std::vector<char> compile_log;
+        glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &length);
+        compile_log.resize (length + 1);
+        glGetShaderInfoLog (shader_id, length, &length, &compile_log[0]);
+        XCAM_LOG_ERROR (
+            "GL create sharder(:%s) compile failed, error flag: %s, log: %s",
+            XCAM_STR (info.name), gl_error_string (error), compile_log.data());
+        return NULL;
+    }
+
+    SmartPtr<GLShader> shader =
+        new GLShader (shader_id, info.type, (info.name ? info.name : "null"));
+    return shader;
+}
+
+}
diff --git a/modules/gles/gl_shader.h b/modules/gles/gl_shader.h
new file mode 100644
index 0000000..b379c44
--- /dev/null
+++ b/modules/gles/gl_shader.h
@@ -0,0 +1,78 @@
+/*
+ * gl_shader.h - GL shader
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_GL_SHADER_H
+#define XCAM_GL_SHADER_H
+
+#include <gles/gles_std.h>
+#include <list>
+#include <map>
+
+namespace XCam {
+
+XCAM_BEGIN_DECLARE
+
+typedef struct _GLShaderInfo {
+    GLenum          type;
+    const GLchar   *name;
+    const GLchar   *src;
+    GLint           len;
+} GLShaderInfo;
+
+XCAM_END_DECLARE
+
+typedef std::list<const GLShaderInfo *> GLShaderInfoList;
+
+class GLShader
+{
+public:
+    ~GLShader ();
+    static SmartPtr<GLShader> compile_shader (const GLShaderInfo &info);
+
+#if 0
+    static SmartPtr<GLShader> create_binary_shader (
+        GLenum format, const uint8_t *binary, uint32_t length, const char *name = NULL);
+#endif
+
+    GLuint get_shader_id () const {
+        return _shader_id;
+    }
+    const char *get_name () const {
+        return _name;
+    }
+    GLenum get_type () const {
+        return _shader_type;
+    }
+
+private:
+    explicit GLShader (GLuint id, GLenum type, const char *name);
+
+private:
+    XCAM_DEAD_COPY (GLShader);
+
+private:
+    GLenum        _shader_type;
+    GLuint        _shader_id;
+    char          _name [XCAM_GL_NAME_LENGTH];
+};
+
+}
+
+#endif  //XCAM_GL_SHADER_H
diff --git a/modules/gles/gl_stitcher.cpp b/modules/gles/gl_stitcher.cpp
new file mode 100644
index 0000000..ff357ce
--- /dev/null
+++ b/modules/gles/gl_stitcher.cpp
@@ -0,0 +1,894 @@
+/*
+ * gl_stitcher.cpp - GL stitcher implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "surview_fisheye_dewarp.h"
+#include "gl_video_buffer.h"
+#include "gl_geomap_handler.h"
+#include "gl_blender.h"
+#include "gl_copy_handler.h"
+#include "gl_stitcher.h"
+#include "interface/feature_match.h"
+
+#define GL_STITCHER_ALIGNMENT_X 16
+#define GL_STITCHER_ALIGNMENT_Y 4
+
+#define MAP_FACTOR_X  16
+#define MAP_FACTOR_Y  16
+
+#define DUMP_BUFFER 0
+
+namespace XCam {
+
+#if DUMP_BUFFER
+static void
+dump_buf (const SmartPtr<VideoBuffer> buf, uint32_t idx, const char *prefix)
+{
+    XCAM_ASSERT (buf.ptr ());
+    XCAM_ASSERT (prefix);
+
+    char name[256];
+    snprintf (name, 256, "%s-%d", prefix, idx);
+    dump_buf_perfix_path (buf, name);
+}
+#else
+static void
+dump_buf (const SmartPtr<VideoBuffer> buf, ...) {
+    XCAM_UNUSED (buf);
+}
+#endif
+
+namespace GLSitcherPriv {
+
+DECLARE_HANDLER_CALLBACK (CbGeoMap, GLStitcher, dewarp_done);
+DECLARE_HANDLER_CALLBACK (CbBlender, GLStitcher, blender_done);
+DECLARE_HANDLER_CALLBACK (CbCopier, GLStitcher, copier_done);
+
+struct BlenderParam
+    : GLBlender::BlenderParam
+{
+    SmartPtr<GLStitcher::StitcherParam>    stitch_param;
+    uint32_t                               idx;
+
+    BlenderParam (
+        uint32_t i,
+        const SmartPtr<VideoBuffer> &in0,
+        const SmartPtr<VideoBuffer> &in1,
+        const SmartPtr<VideoBuffer> &out)
+        : GLBlender::BlenderParam (in0, in1, out)
+        , idx (i)
+    {}
+};
+typedef std::map<void*, SmartPtr<BlenderParam>> BlenderParams;
+
+struct HandlerParam
+    : ImageHandler::Parameters
+{
+    SmartPtr<GLStitcher::StitcherParam>    stitch_param;
+    uint32_t                               idx;
+
+    HandlerParam (uint32_t i)
+        : idx (i)
+    {}
+};
+
+struct Factor {
+    float x, y;
+
+    Factor () : x (1.0f), y (1.0f) {}
+    void reset () {
+        x = 1.0f;
+        y = 1.0f;
+    }
+};
+
+struct Overlap {
+    SmartPtr<FeatureMatch>    matcher;
+    SmartPtr<GLBlender>       blender;
+    BlenderParams             param_map;
+
+    SmartPtr<BlenderParam> find_blender_param_in_map (
+        const SmartPtr<GLStitcher::StitcherParam> &key,
+        const uint32_t idx);
+};
+
+struct FisheyeDewarp {
+    SmartPtr<GLGeoMapHandler>    dewarp;
+    SmartPtr<BufferPool>         buf_pool;
+    Factor                       left_match_factor;
+    Factor                       right_match_factor;
+
+    bool set_dewarp_factor ();
+    XCamReturn set_dewarp_geo_table (
+        const SmartPtr<GLGeoMapHandler> &mapper, const CameraInfo &cam_info,
+        const Stitcher::RoundViewSlice &view_slice, const BowlDataConfig &bowl);
+};
+
+typedef std::vector<SmartPtr<GLCopyHandler>> Copiers;
+
+class StitcherImpl {
+    friend class XCam::GLStitcher;
+
+public:
+    StitcherImpl (GLStitcher *handler)
+        : _stitcher (handler)
+    {}
+
+    XCamReturn init_config (uint32_t count);
+    XCamReturn start_dewarps (const SmartPtr<GLStitcher::StitcherParam> &param);
+    XCamReturn start_blenders (
+        const SmartPtr<GLStitcher::StitcherParam> &param,
+        uint32_t idx, const SmartPtr<VideoBuffer> &buf);
+    XCamReturn start_copier (
+        const SmartPtr<GLStitcher::StitcherParam> &param,
+        uint32_t idx, const SmartPtr<VideoBuffer> &buf);
+
+    XCamReturn start_single_blender (uint32_t idx, const SmartPtr<BlenderParam> &param);
+    XCamReturn stop ();
+
+    XCamReturn fisheye_dewarp_to_table ();
+
+    XCamReturn start_feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, uint32_t idx);
+
+    const SmartPtr<GLComputeProgram> &get_sync_prog ();
+
+private:
+    SmartPtr<GLGeoMapHandler> create_geo_mapper (const Stitcher::RoundViewSlice &view_slice);
+
+    XCamReturn init_fisheye (uint32_t idx);
+    bool init_dewarp_factors (uint32_t idx);
+
+    void calc_dewarp_factors (
+        uint32_t idx, const Factor &last_left_factor, const Factor &last_right_factor,
+        Factor &cur_left, Factor &cur_right);
+
+    void init_feature_match (uint32_t idx);
+    bool get_and_reset_fm_factors (uint32_t idx, Factor &left, Factor &right);
+
+private:
+    FisheyeDewarp                 _fisheye[XCAM_STITCH_MAX_CAMERAS];
+    Overlap                       _overlaps[XCAM_STITCH_MAX_CAMERAS];
+    Copiers                       _copiers;
+
+    GLStitcher                   *_stitcher;
+    SmartPtr<GLComputeProgram>    _sync_prog;
+};
+
+const SmartPtr<GLComputeProgram> &
+StitcherImpl::get_sync_prog ()
+{
+    if (_sync_prog.ptr ())
+        return _sync_prog;
+
+    _sync_prog = GLComputeProgram::create_compute_program ("sync_program");
+    XCAM_FAIL_RETURN (
+        ERROR, _sync_prog.ptr (), _sync_prog,
+        "gl-stitcher(%s) create sync program failed",
+        XCAM_STR (_stitcher->get_name ()));
+
+    return _sync_prog;
+}
+
+bool
+StitcherImpl::get_and_reset_fm_factors (uint32_t idx, Factor &left, Factor &right)
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    XCAM_FAIL_RETURN (
+        ERROR, idx < cam_num, false,
+        "gl-stitcher(%s) invalid camera index, idx(%d) > camera_num(%d)",
+        XCAM_STR (_stitcher->get_name ()), idx, cam_num);
+
+    left = _fisheye[idx].left_match_factor;
+    right = _fisheye[idx].right_match_factor;
+
+    _fisheye[idx].left_match_factor.reset ();
+    _fisheye[idx].right_match_factor.reset ();
+
+    return true;
+}
+
+void
+StitcherImpl::calc_dewarp_factors (
+    uint32_t idx, const Factor &last_left_factor, const Factor &last_right_factor,
+    Factor &cur_left, Factor &cur_right)
+{
+    Factor match_left_factor, match_right_factor;
+    get_and_reset_fm_factors (idx, match_left_factor, match_right_factor);
+
+    cur_left.x = last_left_factor.x * match_left_factor.x;
+    cur_left.y = last_left_factor.y * match_left_factor.y;
+    cur_right.x = last_right_factor.x * match_right_factor.x;
+    cur_right.y = last_right_factor.y * match_right_factor.y;
+}
+
+bool
+StitcherImpl::init_dewarp_factors (uint32_t idx)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _fisheye[idx].dewarp.ptr (), false,
+        "gl-stitcher(%s) dewarp handler is empty",
+        XCAM_STR (_stitcher->get_name ()));
+
+    Factor last_left_factor, last_right_factor, cur_left, cur_right;
+    if (_stitcher->get_scale_mode () == ScaleSingleConst) {
+        Factor unify_factor;
+        _fisheye[idx].dewarp->get_factors (unify_factor.x, unify_factor.y);
+        if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started.
+            return true;
+        }
+        last_left_factor = last_right_factor = unify_factor;
+
+        calc_dewarp_factors (idx, last_left_factor, last_right_factor, cur_left, cur_right);
+        unify_factor.x = (cur_left.x + cur_right.x) / 2.0f;
+        unify_factor.y = (cur_left.y + cur_right.y) / 2.0f;
+
+        _fisheye[idx].dewarp->set_factors (unify_factor.x, unify_factor.y);
+    } else {
+        SmartPtr<GLDualConstGeoMapHandler> dewarp = _fisheye[idx].dewarp.dynamic_cast_ptr<GLDualConstGeoMapHandler> ();
+        XCAM_ASSERT (dewarp.ptr ());
+
+        dewarp->get_left_factors (last_left_factor.x, last_left_factor.y);
+        dewarp->get_right_factors (last_right_factor.x, last_right_factor.y);
+        if (XCAM_DOUBLE_EQUAL_AROUND (last_left_factor.x, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (last_left_factor.y, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (last_right_factor.y, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (last_right_factor.y, 0.0f)) { // not started.
+            return true;
+        }
+
+        calc_dewarp_factors (idx, last_left_factor, last_right_factor, cur_left, cur_right);
+        dewarp->set_left_factors (cur_left.x, cur_left.y);
+        dewarp->set_right_factors (cur_right.x, cur_right.y);
+    }
+
+    return true;
+}
+
+
+XCamReturn
+FisheyeDewarp::set_dewarp_geo_table (
+    const SmartPtr<GLGeoMapHandler> &mapper, const CameraInfo &cam_info,
+    const Stitcher::RoundViewSlice &view_slice, const BowlDataConfig &bowl)
+{
+    PolyFisheyeDewarp fd;
+    fd.set_intrinsic_param (cam_info.calibration.intrinsic);
+    fd.set_extrinsic_param (cam_info.calibration.extrinsic);
+
+    uint32_t table_width, table_height;
+    table_width = view_slice.width / MAP_FACTOR_X;
+    table_height = view_slice.height / MAP_FACTOR_Y;
+
+    SurViewFisheyeDewarp::MapTable map_table(table_width * table_height);
+    fd.fisheye_dewarp (
+        map_table, table_width, table_height,
+        view_slice.width, view_slice.height, bowl);
+
+    XCAM_FAIL_RETURN (
+        ERROR,
+        mapper->set_lookup_table (map_table.data (), table_width, table_height),
+        XCAM_RETURN_ERROR_UNKNOWN,
+        "set fisheye dewarp lookup table failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+SmartPtr<GLGeoMapHandler>
+StitcherImpl::create_geo_mapper (const Stitcher::RoundViewSlice &view_slice)
+{
+    XCAM_UNUSED (view_slice);
+
+    SmartPtr<GLGeoMapHandler> dewarp;
+    GeoMapScaleMode scale_mode = _stitcher->get_scale_mode ();
+    if (scale_mode == ScaleSingleConst)
+        dewarp = new GLGeoMapHandler ("sitcher_singleconst_remapper");
+    else if (scale_mode == ScaleDualConst) {
+        dewarp = new GLDualConstGeoMapHandler ("sitcher_dualconst_remapper");
+    } else {
+        XCAM_LOG_ERROR (
+            "gl-stitcher(%s) unsupported GeoMapScaleMode: %d",
+            XCAM_STR (_stitcher->get_name ()), scale_mode);
+    }
+    XCAM_ASSERT (dewarp.ptr ());
+
+    return dewarp;
+}
+
+XCamReturn
+StitcherImpl::init_fisheye (uint32_t idx)
+{
+    FisheyeDewarp &fisheye = _fisheye[idx];
+    Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (idx);
+
+    SmartPtr<ImageHandler::Callback> dewarp_cb = new CbGeoMap (_stitcher);
+    fisheye.dewarp = create_geo_mapper (view_slice);
+    fisheye.dewarp->set_callback (dewarp_cb);
+
+    VideoBufferInfo buf_info;
+    buf_info.init (
+        V4L2_PIX_FMT_NV12, view_slice.width, view_slice.height,
+        XCAM_ALIGN_UP (view_slice.width, GL_STITCHER_ALIGNMENT_X),
+        XCAM_ALIGN_UP (view_slice.height, GL_STITCHER_ALIGNMENT_Y));
+
+    SmartPtr<BufferPool> pool = new GLVideoBufferPool (buf_info);
+    XCAM_ASSERT (pool.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, pool->reserve (XCAM_GL_RESERVED_BUF_COUNT), XCAM_RETURN_ERROR_MEM,
+        "gl-stitcher(%s) reserve dewarp buffer pool failed, width:%d, height:%d",
+        XCAM_STR (_stitcher->get_name ()), buf_info.width, buf_info.height);
+    fisheye.buf_pool = pool;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void
+StitcherImpl::init_feature_match (uint32_t idx)
+{
+#if HAVE_OPENCV
+#ifndef ANDROID
+    FeatureMatchMode fm_mode = _stitcher->get_fm_mode ();
+    if (fm_mode == FMNone)
+        return ;
+    else if (fm_mode == FMDefault)
+        _overlaps[idx].matcher = FeatureMatch::create_default_feature_match ();
+    else if (fm_mode == FMCluster)
+        _overlaps[idx].matcher = FeatureMatch::create_cluster_feature_match ();
+    else if (fm_mode == FMCapi)
+        _overlaps[idx].matcher = FeatureMatch::create_capi_feature_match ();
+    else {
+        XCAM_LOG_ERROR (
+            "gl-stitcher(%s) unsupported FeatureMatchMode: %d",
+            XCAM_STR (_stitcher->get_name ()), fm_mode);
+    }
+#else
+    _overlaps[idx].matcher = FeatureMatch::create_capi_feature_match ();
+#endif
+    XCAM_ASSERT (_overlaps[idx].matcher.ptr ());
+
+    FMConfig config;
+    config.sitch_min_width = 136;
+    config.min_corners = 4;
+    config.offset_factor = 0.8f;
+    config.delta_mean_offset = 120.0f;
+    config.recur_offset_error = 8.0f;
+    config.max_adjusted_offset = 24.0f;
+    config.max_valid_offset_y = 20.0f;
+    config.max_track_error = 28.0f;
+#ifdef ANDROID
+    config.max_track_error = 3600.0f;
+#endif
+    _overlaps[idx].matcher->set_config (config);
+    _overlaps[idx].matcher->set_fm_index (idx);
+
+    const BowlDataConfig bowl = _stitcher->get_bowl_config ();
+    const Stitcher::ImageOverlapInfo &info = _stitcher->get_overlap (idx);
+    Rect left_ovlap = info.left;
+    Rect right_ovlap = info.right;
+    left_ovlap.pos_y = 0;
+    left_ovlap.height = int32_t (bowl.wall_height / (bowl.wall_height + bowl.ground_length) * left_ovlap.height);
+    right_ovlap.pos_y = 0;
+    right_ovlap.height = left_ovlap.height;
+    _overlaps[idx].matcher->set_crop_rect (left_ovlap, right_ovlap);
+#else
+    XCAM_LOG_ERROR ("gl-stitcher(%s) feature match is unsupported", XCAM_STR (_stitcher->get_name ()));
+    XCAM_ASSERT (false);
+#endif
+}
+
+XCamReturn
+StitcherImpl::init_config (uint32_t count)
+{
+    for (uint32_t i = 0; i < count; ++i) {
+        XCamReturn ret = init_fisheye (i);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "gl-stitcher(%s) init fisheye failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i);
+
+#if HAVE_OPENCV
+        init_feature_match (i);
+#endif
+
+        _overlaps[i].blender = create_gl_blender ().dynamic_cast_ptr<GLBlender>();
+        XCAM_ASSERT (_overlaps[i].blender.ptr ());
+        SmartPtr<ImageHandler::Callback> blender_cb = new CbBlender (_stitcher);
+        XCAM_ASSERT (blender_cb.ptr ());
+        _overlaps[i].blender->set_callback (blender_cb);
+        _overlaps[i].param_map.clear ();
+    }
+
+    Stitcher::CopyAreaArray areas = _stitcher->get_copy_area ();
+    uint32_t size = areas.size ();
+    for (uint32_t i = 0; i < size; ++i) {
+        XCAM_ASSERT (areas[i].in_idx < size);
+
+        SmartPtr<ImageHandler::Callback> copier_cb = new CbCopier (_stitcher);
+        XCAM_ASSERT (copier_cb.ptr ());
+        SmartPtr<GLCopyHandler> copier = new GLCopyHandler ("stitch_copy");
+        XCAM_ASSERT (copier.ptr ());
+
+        copier->enable_allocator (false);
+        copier->set_callback (copier_cb);
+        copier->set_copy_area (areas[i].in_idx, areas[i].in_area, areas[i].out_area);
+        _copiers.push_back (copier);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::fisheye_dewarp_to_table ()
+{
+    uint32_t camera_num = _stitcher->get_camera_num ();
+    for (uint32_t i = 0; i < camera_num; ++i) {
+        CameraInfo cam_info;
+        _stitcher->get_camera_info (i, cam_info);
+        Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (i);
+
+        BowlDataConfig bowl = _stitcher->get_bowl_config ();
+        bowl.angle_start = view_slice.hori_angle_start;
+        bowl.angle_end = format_angle (view_slice.hori_angle_start + view_slice.hori_angle_range);
+
+        uint32_t out_width, out_height;
+        _stitcher->get_output_size (out_width, out_height);
+
+        XCAM_ASSERT (_fisheye[i].dewarp.ptr ());
+        _fisheye[i].dewarp->set_output_size (view_slice.width, view_slice.height);
+
+        if (bowl.angle_end < bowl.angle_start)
+            bowl.angle_start -= 360.0f;
+
+        XCAM_LOG_DEBUG (
+            "gl-stitcher(%s) camera(idx:%d) info(angle start:%.2f, range:%.2f), bowl info(angle start:%.2f, end:%.2f)",
+            XCAM_STR (_stitcher->get_name ()), i,
+            view_slice.hori_angle_start, view_slice.hori_angle_range,
+            bowl.angle_start, bowl.angle_end);
+
+        XCamReturn ret = _fisheye[i].set_dewarp_geo_table (_fisheye[i].dewarp, cam_info, view_slice, bowl);
+
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "gl-stitcher(%s) set dewarp geo table failed, idx:%d", XCAM_STR (_stitcher->get_name ()), i);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_dewarps (const SmartPtr<GLStitcher::StitcherParam> &param)
+{
+    uint32_t camera_num = _stitcher->get_camera_num ();
+
+    for (uint32_t i = 0; i < camera_num; ++i) {
+        SmartPtr<VideoBuffer> out_buf = _fisheye[i].buf_pool->get_buffer ();
+        SmartPtr<HandlerParam> dewarp_params = new HandlerParam (i);
+        dewarp_params->in_buf = param->in_bufs[i];
+        dewarp_params->out_buf = out_buf;
+        dewarp_params->stitch_param = param;
+
+        init_dewarp_factors (i);
+        XCamReturn ret = _fisheye[i].dewarp->execute_buffer (dewarp_params, false);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "gl-stitcher(%s) fisheye dewarp buffer failed, idx:%d",
+            XCAM_STR (_stitcher->get_name ()), i);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_feature_match (
+    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, uint32_t idx)
+{
+#if HAVE_OPENCV
+    _overlaps[idx].matcher->reset_offsets ();
+    _overlaps[idx].matcher->feature_match (left_buf, right_buf);
+
+    Rect left_ovlap, right_ovlap;
+    _overlaps[idx].matcher->get_crop_rect (left_ovlap, right_ovlap);
+
+    float left_offsetx = _overlaps[idx].matcher->get_current_left_offset_x ();
+    Factor left_factor, right_factor;
+
+    uint32_t left_idx = idx;
+    float center_x = (float) _stitcher->get_center (left_idx).slice_center_x;
+    float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f);
+    float range = feature_center_x - center_x;
+    XCAM_ASSERT (range > 1.0f);
+    right_factor.x = (range + left_offsetx / 2.0f) / range;
+    right_factor.y = 1.0f;
+    XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f);
+
+    uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num ();
+    center_x = (float) _stitcher->get_center (right_idx).slice_center_x;
+    feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f);
+    range = center_x - feature_center_x;
+    XCAM_ASSERT (range > 1.0f);
+    left_factor.x = (range + left_offsetx / 2.0f) / range;
+    left_factor.y = 1.0f;
+    XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f);
+
+    _fisheye[left_idx].right_match_factor = right_factor;
+    _fisheye[right_idx].left_match_factor = left_factor;
+
+    return XCAM_RETURN_NO_ERROR;
+#else
+    XCAM_LOG_ERROR ("gl-stitcher(%s) feature match is unsupported", XCAM_STR (_stitcher->get_name ()));
+    return XCAM_RETURN_ERROR_PARAM;
+#endif
+}
+
+SmartPtr<BlenderParam>
+Overlap::find_blender_param_in_map (
+    const SmartPtr<GLStitcher::StitcherParam> &key, uint32_t idx)
+{
+    SmartPtr<BlenderParam> param;
+    BlenderParams::iterator i = param_map.find (key.ptr ());
+    if (i == param_map.end ()) {
+        param = new BlenderParam (idx, NULL, NULL, NULL);
+        XCAM_ASSERT (param.ptr ());
+        param->stitch_param = key;
+        param_map.insert (std::make_pair ((void*)key.ptr (), param));
+    } else {
+        param = (*i).second;
+    }
+
+    return param;
+}
+
+XCamReturn
+StitcherImpl::start_single_blender (
+    uint32_t idx, const SmartPtr<BlenderParam> &param)
+{
+    SmartPtr<GLBlender> blender = _overlaps[idx].blender;
+    const Stitcher::ImageOverlapInfo &overlap_info = _stitcher->get_overlap (idx);
+    uint32_t out_width, out_height;
+    _stitcher->get_output_size (out_width, out_height);
+
+    blender->set_output_size (out_width, out_height);
+    blender->set_merge_window (overlap_info.out_area);
+    blender->set_input_valid_area (overlap_info.left, 0);
+    blender->set_input_valid_area (overlap_info.right, 1);
+    blender->set_input_merge_area (overlap_info.left, 0);
+    blender->set_input_merge_area (overlap_info.right, 1);
+
+    return blender->execute_buffer (param, false);
+}
+
+XCamReturn
+StitcherImpl::start_blenders (
+    const SmartPtr<GLStitcher::StitcherParam> &param,
+    uint32_t idx, const SmartPtr<VideoBuffer> &buf)
+{
+    SmartPtr<BlenderParam> cur_param, prev_param;
+    const uint32_t camera_num = _stitcher->get_camera_num ();
+    uint32_t pre_idx = (idx + camera_num - 1) % camera_num;
+
+    SmartPtr<BlenderParam> param_tmp = _overlaps[idx].find_blender_param_in_map (param, idx);
+    param_tmp->in_buf = buf;
+    if (param_tmp->in_buf.ptr () && param_tmp->in1_buf.ptr ()) {
+        cur_param = param_tmp;
+        _overlaps[idx].param_map.erase (param.ptr ());
+    }
+
+    param_tmp = _overlaps[pre_idx].find_blender_param_in_map (param, pre_idx);
+    param_tmp->in1_buf = buf;
+    if (param_tmp->in_buf.ptr () && param_tmp->in1_buf.ptr ()) {
+        prev_param = param_tmp;
+        _overlaps[pre_idx].param_map.erase (param.ptr ());
+    }
+
+    if (cur_param.ptr ()) {
+        cur_param->out_buf = param->out_buf;
+        XCamReturn ret = start_single_blender (idx, cur_param);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "gl-stitcher(%s) blend overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx);
+    }
+
+    if (prev_param.ptr ()) {
+        prev_param->out_buf = param->out_buf;
+        XCamReturn ret = start_single_blender (pre_idx, prev_param);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "gl-stitcher(%s) blend overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx);
+    }
+
+#if HAVE_OPENCV
+    if (_stitcher->get_fm_mode ()) {
+        if (cur_param.ptr ()) {
+            XCamReturn ret = start_feature_match (cur_param->in_buf, cur_param->in1_buf, idx);
+            XCAM_FAIL_RETURN (
+                ERROR, xcam_ret_is_ok (ret), ret,
+                "gl-stitcher(%s) feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx);
+        }
+
+        if (prev_param.ptr ()) {
+            XCamReturn ret = start_feature_match (prev_param->in_buf, prev_param->in1_buf, pre_idx);
+            XCAM_FAIL_RETURN (
+                ERROR, xcam_ret_is_ok (ret), ret,
+                "gl-stitcher(%s) feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx);
+        }
+    }
+#endif
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_copier (
+    const SmartPtr<GLStitcher::StitcherParam> &param,
+    uint32_t idx, const SmartPtr<VideoBuffer> &buf)
+{
+    XCAM_ASSERT (param.ptr ());
+    XCAM_ASSERT (buf.ptr ());
+
+    uint32_t size = _stitcher->get_copy_area ().size ();
+    XCAM_FAIL_RETURN (
+        ERROR, idx <= size, XCAM_RETURN_ERROR_PARAM,
+        "gl-stitcher(%s) invalid idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
+
+    for (uint32_t i = 0; i < size; ++i) {
+        if(_copiers[i]->get_index () != idx)
+            continue;
+
+        SmartPtr<HandlerParam> copy_params = new HandlerParam (i);
+        copy_params->in_buf = buf;
+        copy_params->out_buf = param->out_buf;
+        copy_params->stitch_param = param;
+
+        XCamReturn ret = _copiers[i]->execute_buffer (copy_params, false);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "gl-stitcher(%s) execute copier failed, i:%d idx:%d",
+            XCAM_STR (_stitcher->get_name ()), i, idx);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::stop ()
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    for (uint32_t i = 0; i < cam_num; ++i) {
+        if (_fisheye[i].dewarp.ptr ()) {
+            _fisheye[i].dewarp->terminate ();
+            _fisheye[i].dewarp.release ();
+        }
+        if (_fisheye[i].buf_pool.ptr ()) {
+            _fisheye[i].buf_pool->stop ();
+        }
+
+        if (_overlaps[i].blender.ptr ()) {
+            _overlaps[i].blender->terminate ();
+            _overlaps[i].blender.release ();
+        }
+    }
+
+    for (Copiers::iterator i_copier = _copiers.begin (); i_copier != _copiers.end (); ++i_copier) {
+        SmartPtr<GLCopyHandler> &copier = *i_copier;
+        if (copier.ptr ()) {
+            copier->terminate ();
+            copier.release ();
+        }
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+};
+
+GLStitcher::GLStitcher (const char *name)
+    : GLImageHandler (name)
+    , Stitcher (GL_STITCHER_ALIGNMENT_X, GL_STITCHER_ALIGNMENT_X)
+{
+    SmartPtr<GLSitcherPriv::StitcherImpl> impl = new GLSitcherPriv::StitcherImpl (this);
+    XCAM_ASSERT (impl.ptr ());
+    _impl = impl;
+}
+
+GLStitcher::~GLStitcher ()
+{
+}
+
+XCamReturn
+GLStitcher::terminate ()
+{
+    _impl->stop ();
+    return GLImageHandler::terminate ();
+}
+
+XCamReturn
+GLStitcher::stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !in_bufs.empty (), XCAM_RETURN_ERROR_PARAM,
+        "gl-stitcher(%s) stitch buffer failed, input buffers is empty", XCAM_STR (get_name ()));
+
+    SmartPtr<StitcherParam> param = new StitcherParam;
+    XCAM_ASSERT (param.ptr ());
+    param->out_buf = out_buf;
+
+    uint32_t count = 0;
+    for (VideoBufferList::const_iterator iter = in_bufs.begin(); iter != in_bufs.end (); ++iter) {
+        SmartPtr<VideoBuffer> buf = *iter;
+        XCAM_ASSERT (buf.ptr ());
+        param->in_bufs[count++] = buf;
+    }
+    param->in_buf_num = count;
+
+    XCamReturn ret = execute_buffer (param, false);
+    if (!out_buf.ptr () && xcam_ret_is_ok (ret)) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+XCamReturn
+GLStitcher::configure_resource (const SmartPtr<Parameters> &param)
+{
+    XCAM_UNUSED (param);
+    XCAM_ASSERT (_impl.ptr ());
+
+    XCamReturn ret = estimate_round_slices ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) estimate round view slices failed", XCAM_STR (get_name ()));
+
+    ret = estimate_coarse_crops ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) estimate coarse crops failed", XCAM_STR (get_name ()));
+
+    ret = mark_centers ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) mark centers failed", XCAM_STR (get_name ()));
+
+    ret = estimate_overlap ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) estimake coarse overlap failed", XCAM_STR (get_name ()));
+
+    ret = update_copy_areas ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) update copy areas failed", XCAM_STR (get_name ()));
+
+    uint32_t camera_count = get_camera_num ();
+    ret = _impl->init_config (camera_count);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) initialize private config failed", XCAM_STR (get_name ()));
+
+    ret = _impl->fisheye_dewarp_to_table ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "gl-stitcher(%s) fisheye_dewarp_to_table failed", XCAM_STR (get_name ()));
+
+    VideoBufferInfo out_info;
+    uint32_t out_width, out_height;
+    get_output_size (out_width, out_height);
+    XCAM_FAIL_RETURN (
+        ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
+        "gl-stitcher(%s) output size was not set", XCAM_STR (get_name ()));
+
+    out_info.init (
+        V4L2_PIX_FMT_NV12, out_width, out_height,
+        XCAM_ALIGN_UP (out_width, GL_STITCHER_ALIGNMENT_X),
+        XCAM_ALIGN_UP (out_height, GL_STITCHER_ALIGNMENT_Y));
+    set_out_video_info (out_info);
+
+    return ret;
+}
+
+XCamReturn
+GLStitcher::start_work (const SmartPtr<Parameters> &base)
+{
+    XCAM_ASSERT (base.ptr ());
+
+    SmartPtr<StitcherParam> param = base.dynamic_cast_ptr<StitcherParam> ();
+    XCAM_FAIL_RETURN (
+        ERROR, param.ptr () && param->in_buf_num > 0 && param->in_bufs[0].ptr (), XCAM_RETURN_ERROR_PARAM,
+        "gl-stitcher(%s) start work failed, invalid parameters", XCAM_STR (get_name ()));
+
+    XCamReturn ret = _impl->start_dewarps (param);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM,
+        "gl_stitcher(%s) start dewarps failed", XCAM_STR (get_name ()));
+
+    const SmartPtr<GLComputeProgram> prog = _impl->get_sync_prog ();
+    XCAM_ASSERT (prog.ptr ());
+    ret = prog->finish ();
+
+    return ret;
+}
+
+void
+GLStitcher::dewarp_done (
+    const SmartPtr<ImageHandler> &handler,
+    const SmartPtr<ImageHandler::Parameters> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (handler);
+
+    SmartPtr<GLSitcherPriv::HandlerParam> dewarp_param = base.dynamic_cast_ptr<GLSitcherPriv::HandlerParam> ();
+    XCAM_ASSERT (dewarp_param.ptr ());
+    SmartPtr<GLStitcher::StitcherParam> param = dewarp_param->stitch_param;
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+
+    XCAM_LOG_DEBUG ("gl-stitcher(%s) camera(idx:%d) dewarp done", XCAM_STR (get_name ()), dewarp_param->idx);
+    dump_buf (dewarp_param->out_buf, dewarp_param->idx, "stitcher-dewarp");
+
+    XCamReturn ret = _impl->start_blenders (param, dewarp_param->idx, dewarp_param->out_buf);
+    if (!xcam_ret_is_ok (ret))
+        XCAM_LOG_ERROR ("start_blenders failed");
+
+    ret = _impl->start_copier (param, dewarp_param->idx, dewarp_param->out_buf);
+    if (!xcam_ret_is_ok (ret))
+        XCAM_LOG_ERROR ("start_copier failed");
+}
+
+void
+GLStitcher::blender_done (
+    const SmartPtr<ImageHandler> &handler,
+    const SmartPtr<ImageHandler::Parameters> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (handler);
+
+    SmartPtr<GLSitcherPriv::BlenderParam> blender_param = base.dynamic_cast_ptr<GLSitcherPriv::BlenderParam> ();
+    XCAM_ASSERT (blender_param.ptr ());
+    SmartPtr<GLStitcher::StitcherParam> param = blender_param->stitch_param;
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+
+    XCAM_LOG_DEBUG ("gl-stitcher(%s) overlap:%d done", XCAM_STR (handler->get_name ()), blender_param->idx);
+    dump_buf (blender_param->out_buf, blender_param->idx, "stitcher-blend");
+}
+
+void
+GLStitcher::copier_done (
+    const SmartPtr<ImageHandler> &handler,
+    const SmartPtr<ImageHandler::Parameters> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (handler);
+
+    SmartPtr<GLSitcherPriv::HandlerParam> copy_param = base.dynamic_cast_ptr<GLSitcherPriv::HandlerParam> ();
+    XCAM_ASSERT (copy_param.ptr ());
+    SmartPtr<GLStitcher::StitcherParam> param = copy_param->stitch_param;
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+
+    XCAM_LOG_DEBUG ("gl-stitcher(%s) camera(idx:%d) copy done", XCAM_STR (get_name ()), copy_param->idx);
+}
+
+SmartPtr<Stitcher>
+Stitcher::create_gl_stitcher ()
+{
+    return new GLStitcher;
+}
+
+}
diff --git a/modules/gles/gl_stitcher.h b/modules/gles/gl_stitcher.h
new file mode 100644
index 0000000..08a0406
--- /dev/null
+++ b/modules/gles/gl_stitcher.h
@@ -0,0 +1,91 @@
+/*
+ * gl_stitcher.h - GL stitcher class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_STITCHER_H
+#define XCAM_GL_STITCHER_H
+
+#include <interface/stitcher.h>
+#include <gles/gles_std.h>
+#include <gles/gl_image_handler.h>
+
+namespace XCam {
+
+namespace GLSitcherPriv {
+class StitcherImpl;
+class CbGeoMap;
+class CbBlender;
+class CbCopier;
+};
+
+class GLStitcher
+    : public GLImageHandler
+    , public Stitcher
+{
+    friend class GLSitcherPriv::StitcherImpl;
+    friend class GLSitcherPriv::CbGeoMap;
+    friend class GLSitcherPriv::CbBlender;
+    friend class GLSitcherPriv::CbCopier;
+
+public:
+    struct StitcherParam
+        : ImageHandler::Parameters
+    {
+        uint32_t in_buf_num;
+        SmartPtr<VideoBuffer> in_bufs[XCAM_STITCH_MAX_CAMERAS];
+
+        StitcherParam ()
+            : Parameters (NULL, NULL)
+            , in_buf_num (0)
+        {}
+    };
+
+public:
+    explicit GLStitcher (const char *name = "GLStitcher");
+    ~GLStitcher ();
+
+    // derived from GLImageHandler
+    virtual XCamReturn terminate ();
+
+protected:
+    // interface derive from Stitcher
+    XCamReturn stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf);
+
+    // derived from GLImageHandler
+    XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    void dewarp_done (
+        const SmartPtr<ImageHandler> &handler,
+        const SmartPtr<ImageHandler::Parameters> &param, const XCamReturn error);
+    void blender_done (
+        const SmartPtr<ImageHandler> &handler,
+        const SmartPtr<ImageHandler::Parameters> &param, const XCamReturn error);
+    void copier_done (
+        const SmartPtr<ImageHandler> &handler,
+        const SmartPtr<ImageHandler::Parameters> &param, const XCamReturn error);
+
+private:
+    SmartPtr<GLSitcherPriv::StitcherImpl>    _impl;
+};
+
+}
+#endif // XCAM_GL_STITCHER_H
\ No newline at end of file
diff --git a/modules/gles/gl_utils.cpp b/modules/gles/gl_utils.cpp
new file mode 100644
index 0000000..bafaf10
--- /dev/null
+++ b/modules/gles/gl_utils.cpp
@@ -0,0 +1,41 @@
+/*
+ * gl_utils.h - GL utilities implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_utils.h"
+
+namespace XCam {
+
+SmartPtr<GLBuffer> get_glbuffer (const SmartPtr<VideoBuffer> &buf)
+{
+    SmartPtr<GLVideoBuffer> gl_video_buf = buf.dynamic_cast_ptr<GLVideoBuffer> ();
+    XCAM_FAIL_RETURN (
+        ERROR, gl_video_buf.ptr (), NULL,
+        "convert VideoBuffer to GLVideoBuffer failed");
+
+    SmartPtr<GLBuffer> gl_buf = gl_video_buf->get_gl_buffer ();
+    XCAM_ASSERT (gl_buf.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, gl_buf.ptr (), NULL,
+        "get GLBuffer from GLVideoBuffer failed");
+
+    return gl_buf;
+}
+
+}
diff --git a/modules/gles/gl_utils.h b/modules/gles/gl_utils.h
new file mode 100644
index 0000000..84ba093
--- /dev/null
+++ b/modules/gles/gl_utils.h
@@ -0,0 +1,32 @@
+/*
+ * gl_utils.h - GL utilities class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_UTILS_H
+#define XCAM_GL_UTILS_H
+
+#include <gles/gl_video_buffer.h>
+
+namespace XCam {
+
+SmartPtr<GLBuffer> get_glbuffer (const SmartPtr<VideoBuffer> &buf);
+
+}
+
+#endif // XCAM_GL_UTILS_H
\ No newline at end of file
diff --git a/modules/gles/gl_video_buffer.cpp b/modules/gles/gl_video_buffer.cpp
new file mode 100644
index 0000000..9029e72
--- /dev/null
+++ b/modules/gles/gl_video_buffer.cpp
@@ -0,0 +1,160 @@
+/*
+ * gl_video_buffer.cpp - GL video buffer implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "gl_video_buffer.h"
+
+namespace XCam {
+
+class GLVideoBufferData
+    : public BufferData
+{
+public:
+    explicit GLVideoBufferData (SmartPtr<GLBuffer> &body);
+    ~GLVideoBufferData ();
+
+    virtual uint8_t *map ();
+    virtual bool unmap ();
+
+    SmartPtr<GLBuffer> &get_buf () {
+        return _buf;
+    }
+
+private:
+    uint8_t              *_buf_ptr;
+    SmartPtr<GLBuffer>    _buf;
+};
+
+GLVideoBufferData::GLVideoBufferData (SmartPtr<GLBuffer> &body)
+    : _buf_ptr (NULL)
+    , _buf (body)
+{
+    XCAM_ASSERT (body.ptr ());
+}
+
+GLVideoBufferData::~GLVideoBufferData ()
+{
+    unmap ();
+    _buf.release ();
+}
+
+uint8_t *
+GLVideoBufferData::map ()
+{
+    if (_buf_ptr)
+        return _buf_ptr;
+
+    uint32_t size = _buf->get_size ();
+    _buf_ptr = (uint8_t *) _buf->map_range (0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
+    XCAM_FAIL_RETURN (ERROR, _buf_ptr, NULL, "GLVideoBufferData map data failed");
+
+    return _buf_ptr;
+}
+
+bool
+GLVideoBufferData::unmap ()
+{
+    if (!_buf_ptr)
+        return true;
+
+    XCamReturn ret = _buf->unmap ();
+    XCAM_FAIL_RETURN (
+        ERROR, ret == XCAM_RETURN_NO_ERROR, false,
+        "GLVideoBufferData unmap data failed");
+
+    _buf_ptr = NULL;
+    return true;
+}
+
+GLVideoBuffer::GLVideoBuffer (const VideoBufferInfo &info, const SmartPtr<BufferData> &data)
+    : BufferProxy (info, data)
+{
+}
+
+SmartPtr<GLBuffer>
+GLVideoBuffer::get_gl_buffer ()
+{
+    SmartPtr<BufferData> data = get_buffer_data ();
+    SmartPtr<GLVideoBufferData> gl_data = data.dynamic_cast_ptr<GLVideoBufferData> ();
+    XCAM_FAIL_RETURN (
+        WARNING, gl_data.ptr (), NULL,
+        "GLVideoBuffer get_buffer_data failed with NULL");
+
+    return gl_data->get_buf ();
+}
+
+GLVideoBufferPool::GLVideoBufferPool ()
+    : _target (GL_SHADER_STORAGE_BUFFER)
+{
+}
+
+GLVideoBufferPool::GLVideoBufferPool (const VideoBufferInfo &info, GLenum target)
+    : _target (target)
+{
+    set_video_info (info);
+}
+
+GLVideoBufferPool::~GLVideoBufferPool ()
+{
+}
+
+SmartPtr<BufferData>
+GLVideoBufferPool::allocate_data (const VideoBufferInfo &info)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, info.format == V4L2_PIX_FMT_NV12, NULL,
+        "GLVideoBufferPool unsupported format:%s, try NV12",
+        xcam_fourcc_to_string (info.format));
+
+    SmartPtr<GLBuffer> buf =
+        XCam::GLBuffer::create_buffer (_target, NULL, info.size, GL_STATIC_DRAW);
+    XCAM_ASSERT (buf.ptr ());
+
+    GLBufferDesc desc;
+    desc.format = info.format;
+    desc.width = info.width;
+    desc.height = info.height;
+    desc.aligned_width = info.aligned_width;
+    desc.aligned_height = info.aligned_height;
+    desc.size = info.size;
+    desc.strides[0] = info.strides[0];
+    desc.strides[1] = info.strides[1];
+    desc.offsets[0] = info.offsets[0];
+    desc.offsets[1] = info.offsets[1];
+    desc.slice_size[0] = info.strides [0] * info.aligned_height;
+    desc.slice_size[1] = info.size - info.offsets[1];
+
+    buf->set_buffer_desc (desc);
+
+    return new GLVideoBufferData (buf);
+}
+
+SmartPtr<BufferProxy>
+GLVideoBufferPool::create_buffer_from_data (SmartPtr<BufferData> &data)
+{
+    XCAM_ASSERT (data.ptr ());
+
+    const VideoBufferInfo &info = get_video_info ();
+    SmartPtr<GLVideoBuffer> buf = new GLVideoBuffer (info, data);
+    XCAM_ASSERT (buf.ptr ());
+
+    return buf;
+}
+
+};
diff --git a/modules/gles/gl_video_buffer.h b/modules/gles/gl_video_buffer.h
new file mode 100644
index 0000000..0cc227b
--- /dev/null
+++ b/modules/gles/gl_video_buffer.h
@@ -0,0 +1,63 @@
+/*
+ * gl_video_buffer.h - GL video buffer class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_GL_VIDEO_BUFFER_H
+#define XCAM_GL_VIDEO_BUFFER_H
+
+#include <buffer_pool.h>
+#include <gles/gl_buffer.h>
+
+namespace XCam {
+
+class GLVideoBuffer
+    : public BufferProxy
+{
+    friend class GLVideoBufferPool;
+
+public:
+    virtual ~GLVideoBuffer () {}
+    SmartPtr<GLBuffer> get_gl_buffer ();
+
+protected:
+    explicit GLVideoBuffer (const VideoBufferInfo &info, const SmartPtr<BufferData> &data);
+};
+
+class GLVideoBufferPool
+    : public BufferPool
+{
+public:
+    explicit GLVideoBufferPool ();
+    explicit GLVideoBufferPool (const VideoBufferInfo &info, GLenum target = GL_SHADER_STORAGE_BUFFER);
+    virtual ~GLVideoBufferPool ();
+
+    void set_binding_target (GLenum target) {
+        _target = target;
+    }
+
+private:
+    virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &info);
+    virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data);
+
+private:
+    GLenum    _target;
+};
+
+};
+#endif // XCAM_GL_VIDEO_BUFFER_H
\ No newline at end of file
diff --git a/modules/gles/gles_std.cpp b/modules/gles/gles_std.cpp
new file mode 100644
index 0000000..03ed14a
--- /dev/null
+++ b/modules/gles/gles_std.cpp
@@ -0,0 +1,58 @@
+/*
+ * gles_std.cpp - GLES std
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "gles_std.h"
+
+namespace XCam {
+
+const char *
+gl_error_string (GLenum flag)
+{
+    static char str[XCAM_GL_NAME_LENGTH] = {'\0'};
+
+    switch (flag)
+    {
+    case GL_NO_ERROR:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "GL_NO_ERROR");
+        break;
+    case GL_INVALID_ENUM:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "GL_INVALID_ENUM");
+        break;
+    case GL_INVALID_VALUE:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "GL_INVALID_VALUE");
+        break;
+    case GL_INVALID_OPERATION:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "GL_INVALID_OPERATION");
+        break;
+    case GL_INVALID_FRAMEBUFFER_OPERATION:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "GL_INVALID_FRAMEBUFFER_OPERATION");
+        break;
+    case GL_OUT_OF_MEMORY:
+        snprintf (str, sizeof (str), "0x%04x:%s", flag, "GL_OUT_OF_MEMORY");
+        break;
+    default:
+        snprintf (str, sizeof (str), "unknown flag:0x%04x", flag);
+        XCAM_LOG_ERROR ("%s", str);
+    }
+
+    return str;
+}
+
+}
diff --git a/modules/gles/gles_std.h b/modules/gles/gles_std.h
new file mode 100644
index 0000000..bad9483
--- /dev/null
+++ b/modules/gles/gles_std.h
@@ -0,0 +1,48 @@
+/*
+ * gles_std.h - GLES std
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_GLES_STD_H
+#define XCAM_GLES_STD_H
+
+#include <xcam_std.h>
+#include <smartptr.h>
+#include <GLES3/gl3.h>
+
+#if HAVE_GLES_32
+#include <GLES3/gl32.h>
+#else
+#include <GLES3/gl31.h>
+#endif
+
+#define XCAM_GL_NAME_LENGTH 64
+#define XCAM_GL_RESERVED_BUF_COUNT 4
+
+namespace XCam {
+
+inline GLenum gl_error ()
+{
+    return glGetError ();
+}
+
+const char *gl_error_string (GLenum flag);
+
+}
+
+#endif // XCAM_GLES_STD_H
diff --git a/modules/isp/Makefile.am b/modules/isp/Makefile.am
index 9ad978c..0cee211 100644
--- a/modules/isp/Makefile.am
+++ b/modules/isp/Makefile.am
@@ -1,81 +1,70 @@
 lib_LTLIBRARIES = libxcam_isp.la
 
-XCAMISP_CXXFLAGS = $(XCAM_CXXFLAGS)
+XCAMISP_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)            \
+    $(IA_IMAGING_CFLAGS)        \
+    -I$(top_srcdir)/xcore       \
+    -I$(top_srcdir)/modules/isp \
+    $(NULL)
+
 XCAMISP_LIBS = \
+    $(IA_IMAGING_LIBS)                    \
+    $(top_builddir)/xcore/libxcam_core.la \
     $(NULL)
 
 if USE_LOCAL_ATOMISP
 XCAMISP_CXXFLAGS += \
-    -I$(top_srcdir)/ext/atomisp  \
-    $(NULL)
-endif
-
-if ENABLE_IA_AIQ
-XCAMISP_CXXFLAGS += \
-    $(IA_IMAGING_CFLAGS)  \
-    $(NULL)
-
-XCAMISP_LIBS += \
-    $(IA_IMAGING_LIBS)  \
-    $(NULL)
-endif
-
-xcam_isp_sources = \
-    aiq3a_utils.cpp             \
-    atomisp_device.cpp          \
-    isp_poll_thread.cpp         \
-    isp_image_processor.cpp     \
-    isp_controller.cpp          \
-    isp_config_translator.cpp   \
-    x3a_isp_config.cpp          \
-    sensor_descriptor.cpp       \
-    iq/x3a_analyze_tuner.cpp               \
-    iq/x3a_ciq_tuning_handler.cpp          \
-    iq/x3a_ciq_tnr_tuning_handler.cpp      \
-    iq/x3a_ciq_bnr_ee_tuning_handler.cpp   \
-    iq/x3a_ciq_wavelet_tuning_handler.cpp  \
-    x3a_statistics_queue.cpp    \
-    libtbd.c                    \
-    xcam_cpf_reader.c           \
-    $(NULL)
-
-if ENABLE_IA_AIQ
-xcam_isp_sources += \
-    aiq_handler.cpp             \
-    hybrid_analyzer.cpp         \
-    hybrid_analyzer_loader.cpp  \
-    x3a_analyzer_aiq.cpp        \
+    -I$(top_srcdir)/ext/atomisp \
     $(NULL)
 endif
 
 if HAVE_LIBDRM
 XCAMISP_CXXFLAGS += $(LIBDRM_CFLAGS)
 XCAMISP_LIBS += \
-    -ldrm_intel     \
-    $(LIBDRM_LIBS)  \
+    -ldrm_intel    \
+    $(LIBDRM_LIBS) \
     $(NULL)
 endif
 
+xcam_isp_sources = \
+    aiq3a_utils.cpp                       \
+    atomisp_device.cpp                    \
+    isp_poll_thread.cpp                   \
+    isp_image_processor.cpp               \
+    isp_controller.cpp                    \
+    isp_config_translator.cpp             \
+    x3a_isp_config.cpp                    \
+    sensor_descriptor.cpp                 \
+    iq/x3a_analyze_tuner.cpp              \
+    iq/x3a_ciq_tuning_handler.cpp         \
+    iq/x3a_ciq_tnr_tuning_handler.cpp     \
+    iq/x3a_ciq_bnr_ee_tuning_handler.cpp  \
+    iq/x3a_ciq_wavelet_tuning_handler.cpp \
+    x3a_statistics_queue.cpp              \
+    aiq_handler.cpp                       \
+    hybrid_analyzer.cpp                   \
+    hybrid_analyzer_loader.cpp            \
+    x3a_analyzer_aiq.cpp                  \
+    libtbd.c                              \
+    xcam_cpf_reader.c                     \
+    $(NULL)
+
 libxcam_isp_la_SOURCES = \
-    $(xcam_isp_sources)  \
+    $(xcam_isp_sources) \
     $(NULL)
 
 libxcam_isp_la_CXXFLAGS = \
-    $(XCAMISP_CXXFLAGS)          \
-    -I$(top_srcdir)/xcore        \
-    -I$(top_srcdir)/modules/isp  \
+    $(XCAMISP_CXXFLAGS) \
     $(NULL)
 
 libxcam_isp_la_CFLAGS = $(libxcam_isp_la_CXXFLAGS)
 
 libxcam_isp_la_LIBADD = \
-    $(top_builddir)/xcore/libxcam_core.la \
-    $(XCAMISP_LIBS)                       \
+    $(XCAMISP_LIBS) \
     $(NULL)
 
 libxcam_isp_la_LDFLAGS = \
-    $(XCAM_LT_LDFLAGS)  \
-    $(PTHREAD_LDFLAGS)  \
+    $(XCAM_LT_LDFLAGS) \
     $(NULL)
 
 libxcam_isp_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/isp/aiq_handler.cpp b/modules/isp/aiq_handler.cpp
index 3a4d89b..d186532 100644
--- a/modules/isp/aiq_handler.cpp
+++ b/modules/isp/aiq_handler.cpp
@@ -1526,8 +1526,9 @@
                 isp_param->tnr_config->threshold_y = 0;
                 isp_param->tnr_config->threshold_uv = 0;
             }
+
+            XCAM_LOG_DEBUG ("set TNR gain:%u", isp_param->tnr_config->gain);
         }
-        XCAM_LOG_DEBUG ("set TNR gain:%u", isp_param->tnr_config->gain);
     }
 
     return XCAM_RETURN_NO_ERROR;
diff --git a/modules/isp/hybrid_analyzer.cpp b/modules/isp/hybrid_analyzer.cpp
index 9e0a0f6..4a936b3 100644
--- a/modules/isp/hybrid_analyzer.cpp
+++ b/modules/isp/hybrid_analyzer.cpp
@@ -79,8 +79,9 @@
     grid_info.deci_factor_log2 = log2 (grid_info.bqs_per_grid_cell);
     grid_info.elem_bit_depth = stats_info.bit_depth;
 
-    _stats_pool = new X3aStatisticsQueue;
-    XCAM_ASSERT (_stats_pool.ptr ());
+    SmartPtr<X3aStatisticsQueue> stats_pool = new X3aStatisticsQueue;
+    XCAM_ASSERT (stats_pool.ptr ());
+    _stats_pool = stats_pool;
 
     _stats_pool->set_grid_info (grid_info);
     if (!_stats_pool->reserve (6)) {
diff --git a/modules/isp/isp_poll_thread.cpp b/modules/isp/isp_poll_thread.cpp
index 754452e..722a0b2 100644
--- a/modules/isp/isp_poll_thread.cpp
+++ b/modules/isp/isp_poll_thread.cpp
@@ -50,7 +50,9 @@
 XCamReturn
 IspPollThread::start ()
 {
-    _3a_stats_pool = new X3aStatisticsQueue;
+    SmartPtr<X3aStatsPool> stats_pool = new X3aStatisticsQueue;
+    XCAM_ASSERT (stats_pool.ptr ());
+    _3a_stats_pool = stats_pool;
 
     return PollThread::start ();
 }
diff --git a/modules/ocl/Makefile.am b/modules/ocl/Makefile.am
index dc09d6d..5d727e6 100644
--- a/modules/ocl/Makefile.am
+++ b/modules/ocl/Makefile.am
@@ -1,109 +1,99 @@
 lib_LTLIBRARIES = libxcam_ocl.la
 
-XCAMOCL_CXXFLAGS = $(XCAM_CXXFLAGS)
-XCAMOCL_LIBS = -ldl  \
-    $(NULL)
-
-XCAMOCL_CXXFLAGS += \
+XCAMOCL_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)              \
     $(LIBCL_CFLAGS)               \
     -I$(top_srcdir)/xcore         \
     -I$(top_srcdir)/modules       \
-    -I$(top_builddir)/clx_kernel  \
+    -I$(top_builddir)/shaders/clx \
     $(NULL)
 
-XCAMOCL_LIBS += \
-    $(LIBCL_LIBS)  \
+XCAMOCL_LIBS = \
+    $(LIBCL_LIBS) -ldl                    \
+    $(top_builddir)/xcore/libxcam_core.la \
     $(NULL)
 
+if HAVE_OPENCV
+XCAMOCL_CXXFLAGS += $(OPENCV_CFLAGS)
+XCAMOCL_LIBS += \
+    $(OPENCV_LIBS)                             \
+    $(top_builddir)/modules/ocv/libxcam_ocv.la \
+    $(NULL)
+endif
+
 if HAVE_LIBDRM
 XCAMOCL_CXXFLAGS += $(LIBDRM_CFLAGS)
 XCAMOCL_LIBS += \
-    -ldrm_intel     \
-    $(LIBDRM_LIBS)  \
+    -ldrm_intel    \
+    $(LIBDRM_LIBS) \
     $(NULL)
 endif
 
-if HAVE_OPENCV
-XCAMOCL_CXXFLAGS += $(OPENCV_CFLAGS)
-XCAMOCL_LIBS += $(OPENCV_LIBS)
-endif
-
 xcam_ocl_sources = \
-    cl_argument.cpp                    \
-    cl_context.cpp                     \
-    cl_device.cpp                      \
-    cl_kernel.cpp                      \
-    cl_memory.cpp                      \
-    cl_event.cpp                       \
-    cl_utils.cpp                       \
-    cl_image_handler.cpp               \
-    cl_image_processor.cpp             \
-    cl_3a_image_processor.cpp          \
-    cl_post_image_processor.cpp        \
-    cl_multi_image_handler.cpp         \
-    cl_csc_image_processor.cpp         \
-    cl_3a_stats_context.cpp            \
-    cl_demo_handler.cpp                \
-    cl_blender.cpp                     \
-    cl_pyramid_blender.cpp             \
-    cl_geo_map_handler.cpp             \
-    cl_csc_handler.cpp                 \
-    cl_tnr_handler.cpp                 \
-    cl_defog_dcp_handler.cpp           \
-    cl_bayer_pipe_handler.cpp          \
-    cl_bayer_basic_handler.cpp         \
-    cl_yuv_pipe_handler.cpp            \
-    cl_rgb_pipe_handler.cpp            \
-    cl_tonemapping_handler.cpp         \
-    cl_newtonemapping_handler.cpp      \
-    cl_fisheye_handler.cpp             \
-    cl_image_scaler.cpp                \
-    cl_image_360_stitch.cpp            \
-    cl_retinex_handler.cpp             \
-    cl_gauss_handler.cpp               \
-    cl_wavelet_denoise_handler.cpp     \
-    cl_newwavelet_denoise_handler.cpp  \
-    cl_wire_frame_handler.cpp          \
-    cl_3d_denoise_handler.cpp          \
-    cl_image_warp_handler.cpp          \
-    cl_video_stabilizer.cpp            \
-    cl_video_buffer.cpp                \
-    priority_buffer_queue.cpp          \
+    cl_argument.cpp                   \
+    cl_context.cpp                    \
+    cl_device.cpp                     \
+    cl_kernel.cpp                     \
+    cl_memory.cpp                     \
+    cl_event.cpp                      \
+    cl_utils.cpp                      \
+    cl_image_handler.cpp              \
+    cl_image_processor.cpp            \
+    cl_3a_image_processor.cpp         \
+    cl_post_image_processor.cpp       \
+    cl_multi_image_handler.cpp        \
+    cl_csc_image_processor.cpp        \
+    cl_3a_stats_context.cpp           \
+    cl_demo_handler.cpp               \
+    cl_blender.cpp                    \
+    cl_pyramid_blender.cpp            \
+    cl_geo_map_handler.cpp            \
+    cl_csc_handler.cpp                \
+    cl_tnr_handler.cpp                \
+    cl_defog_dcp_handler.cpp          \
+    cl_bayer_pipe_handler.cpp         \
+    cl_bayer_basic_handler.cpp        \
+    cl_yuv_pipe_handler.cpp           \
+    cl_rgb_pipe_handler.cpp           \
+    cl_tonemapping_handler.cpp        \
+    cl_newtonemapping_handler.cpp     \
+    cl_fisheye_handler.cpp            \
+    cl_image_scaler.cpp               \
+    cl_image_360_stitch.cpp           \
+    cl_retinex_handler.cpp            \
+    cl_gauss_handler.cpp              \
+    cl_wavelet_denoise_handler.cpp    \
+    cl_newwavelet_denoise_handler.cpp \
+    cl_wire_frame_handler.cpp         \
+    cl_3d_denoise_handler.cpp         \
+    cl_image_warp_handler.cpp         \
+    cl_video_stabilizer.cpp           \
+    cl_video_buffer.cpp               \
+    priority_buffer_queue.cpp         \
     $(NULL)
 
-if HAVE_OPENCV
-xcam_ocl_sources += cv_context.cpp
-xcam_ocl_sources += cv_base_class.cpp
-xcam_ocl_sources += cv_image_process_helper.cpp
-xcam_ocl_sources += cv_image_sharp.cpp
-xcam_ocl_sources += cv_edgetaper.cpp
-xcam_ocl_sources += cv_wiener_filter.cpp
-xcam_ocl_sources += cv_feature_match.cpp
-xcam_ocl_sources += cv_image_deblurring.cpp
-endif
-
 if HAVE_LIBDRM
-xcam_ocl_sources += intel/cl_intel_context.cpp
-xcam_ocl_sources += intel/cl_va_memory.cpp
-xcam_ocl_sources += cl_image_bo_buffer.cpp
+xcam_ocl_sources += \
+    intel/cl_intel_context.cpp \
+    intel/cl_va_memory.cpp     \
+    cl_image_bo_buffer.cpp     \
+    $(NULL)
 endif
 
 libxcam_ocl_la_SOURCES = \
-    $(xcam_ocl_sources)    \
+    $(xcam_ocl_sources) \
     $(NULL)
 
 libxcam_ocl_la_CXXFLAGS = \
-    $(XCAMOCL_CXXFLAGS)   \
+    $(XCAMOCL_CXXFLAGS) \
     $(NULL)
 
 libxcam_ocl_la_LIBADD = \
-    $(top_builddir)/xcore/libxcam_core.la \
-    $(XCAMOCL_LIBS)                       \
+    $(XCAMOCL_LIBS) \
     $(NULL)
 
 libxcam_ocl_la_LDFLAGS = \
     $(XCAM_LT_LDFLAGS) \
-    $(PTHREAD_LDFLAGS) \
     $(NULL)
 
 libxcam_oclincludedir = $(includedir)/xcam/ocl
@@ -150,26 +140,16 @@
     cl_video_buffer.h               \
     $(NULL)
 
-if HAVE_OPENCV
-nobase_libxcam_oclinclude_HEADERS += cv_context.h
-nobase_libxcam_oclinclude_HEADERS += cv_base_class.h
-nobase_libxcam_oclinclude_HEADERS += cv_image_process_helper.h
-nobase_libxcam_oclinclude_HEADERS += cv_image_sharp.h
-nobase_libxcam_oclinclude_HEADERS += cv_edgetaper.h
-nobase_libxcam_oclinclude_HEADERS += cv_wiener_filter.h
-nobase_libxcam_oclinclude_HEADERS += cv_feature_match.h
-nobase_libxcam_oclinclude_HEADERS += cv_image_deblurring.h
-endif
-
 if HAVE_LIBDRM
-nobase_libxcam_oclinclude_HEADERS += intel/cl_intel_context.h
-nobase_libxcam_oclinclude_HEADERS += intel/cl_va_memory.h
-nobase_libxcam_oclinclude_HEADERS += cl_image_bo_buffer.h
+nobase_libxcam_oclinclude_HEADERS += \
+    intel/cl_intel_context.h \
+    intel/cl_va_memory.h     \
+    cl_image_bo_buffer.h     \
+    $(NULL)
 endif
 
-noinst_HEADERS =                    \
-    cl_pyramid_blender.h            \
+noinst_HEADERS = \
+    cl_pyramid_blender.h \
     $(NULL)
 
-
 libxcam_ocl_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/ocl/cl_3a_stats_context.cpp b/modules/ocl/cl_3a_stats_context.cpp
index 4d43e6a..fe2a07c 100644
--- a/modules/ocl/cl_3a_stats_context.cpp
+++ b/modules/ocl/cl_3a_stats_context.cpp
@@ -30,7 +30,9 @@
     , _factor_shift (0)
     , _data_allocated (false)
 {
-    _stats_pool = new X3aStatsPool ();
+    SmartPtr<X3aStatsPool> pool = new X3aStatsPool ();
+    XCAM_ASSERT (pool.ptr ());
+    _stats_pool = pool;
 }
 
 CL3AStatsCalculatorContext::~CL3AStatsCalculatorContext ()
diff --git a/modules/ocl/cl_bayer_basic_handler.cpp b/modules/ocl/cl_bayer_basic_handler.cpp
index efc2536..7e33fa7 100644
--- a/modules/ocl/cl_bayer_basic_handler.cpp
+++ b/modules/ocl/cl_bayer_basic_handler.cpp
@@ -191,10 +191,13 @@
         _gamma_table[i] = (float)i / 256.0f;
     _gamma_table[XCAM_GAMMA_TABLE_SIZE] = 0.9999f;
 
-    _3a_stats_context = new CL3AStatsCalculatorContext (context);
-    XCAM_ASSERT (_3a_stats_context.ptr ());
-    _3a_stats_thread = new CLBayer3AStatsThread (this);
-    XCAM_ASSERT (_3a_stats_thread.ptr ());
+    SmartPtr<CL3AStatsCalculatorContext> stats_context = new CL3AStatsCalculatorContext (context);
+    XCAM_ASSERT (stats_context.ptr ());
+    _3a_stats_context = stats_context;
+
+    SmartPtr<CLBayer3AStatsThread> stats_thread = new CLBayer3AStatsThread (this);
+    XCAM_ASSERT (stats_thread.ptr ());
+    _3a_stats_thread = stats_thread;
 
     XCAM_OBJ_PROFILING_INIT;
 }
diff --git a/modules/ocl/cl_defog_dcp_handler.cpp b/modules/ocl/cl_defog_dcp_handler.cpp
index 7300485..eeb4d78 100644
--- a/modules/ocl/cl_defog_dcp_handler.cpp
+++ b/modules/ocl/cl_defog_dcp_handler.cpp
@@ -387,6 +387,7 @@
     return kernel;
 }
 
+#if 0
 static SmartPtr<CLMinFilterKernel>
 create_kernel_min_filter (
     const SmartPtr<CLContext> &context,
@@ -410,6 +411,7 @@
 
     return kernel;
 }
+#endif
 
 static SmartPtr<CLBiFilterKernel>
 create_kernel_bi_filter (
diff --git a/modules/ocl/cl_fisheye_handler.cpp b/modules/ocl/cl_fisheye_handler.cpp
index a7866c5..321ac78 100644
--- a/modules/ocl/cl_fisheye_handler.cpp
+++ b/modules/ocl/cl_fisheye_handler.cpp
@@ -128,7 +128,7 @@
     return XCAM_RETURN_NO_ERROR;
 }
 
-CLFisheyeHandler::CLFisheyeHandler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc)
+CLFisheyeHandler::CLFisheyeHandler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc, bool need_scale)
     : CLImageHandler (context, "CLFisheyeHandler")
     , _output_width (0)
     , _output_height (0)
@@ -137,8 +137,12 @@
     , _map_factor (DEFAULT_FISHEYE_TABLE_SCALE)
     , _use_map (use_map)
     , _need_lsc (need_lsc ? 1 : 0)
+    , _need_scale (need_scale ? 1 : 0)
     , _lsc_array_size (0)
     , _lsc_array (NULL)
+    , _stable_y_start (0.0f)
+    , _left_scale_factor (1.0f, 1.0f)
+    , _right_scale_factor (1.0f, 1.0f)
     , _surround_mode (surround_mode)
 {
     xcam_mem_clear (_gray_threshold);
@@ -203,6 +207,24 @@
     _gray_threshold[1] = max_threshold;
 }
 
+void
+CLFisheyeHandler::set_stable_y_start (float y_start)
+{
+    _stable_y_start = y_start;
+}
+
+void
+CLFisheyeHandler::set_left_scale_factor (PointFloat2 factor)
+{
+    _left_scale_factor = factor;
+}
+
+void
+CLFisheyeHandler::set_right_scale_factor (PointFloat2 factor)
+{
+    _right_scale_factor = factor;
+}
+
 XCamReturn
 CLFisheyeHandler::prepare_buffer_pool_video_info (
     const VideoBufferInfo &input,
@@ -585,16 +607,16 @@
 }
 
 SmartPtr<CLImageHandler>
-create_fisheye_handler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc)
+create_fisheye_handler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc, bool need_scale)
 {
     SmartPtr<CLFisheyeHandler> handler;
     SmartPtr<CLImageKernel> kernel;
 
-    handler = new CLFisheyeHandler (context, surround_mode, use_map, need_lsc);
+    handler = new CLFisheyeHandler (context, surround_mode, use_map, need_lsc, need_scale);
     XCAM_ASSERT (handler.ptr ());
 
     if (use_map) {
-        kernel = create_geo_map_kernel (context, handler, need_lsc);
+        kernel = create_geo_map_kernel (context, handler, need_lsc, need_scale);
     } else {
         kernel = create_fishey_gps_kernel (context, handler);
     }
diff --git a/modules/ocl/cl_fisheye_handler.h b/modules/ocl/cl_fisheye_handler.h
index be7452f..a8eb7c4 100644
--- a/modules/ocl/cl_fisheye_handler.h
+++ b/modules/ocl/cl_fisheye_handler.h
@@ -49,7 +49,7 @@
 {
     friend class CLFisheye2GPSKernel;
 public:
-    explicit CLFisheyeHandler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc);
+    explicit CLFisheyeHandler (const SmartPtr<CLContext> &context, SurroundMode surround_mode, bool use_map, bool need_lsc, bool need_scale);
     virtual ~CLFisheyeHandler();
 
     void set_output_size (uint32_t width, uint32_t height);
@@ -65,9 +65,25 @@
     void set_lsc_table (float *table, uint32_t table_size);
     void set_lsc_gray_threshold (float min_threshold, float max_threshold);
 
+    void set_stable_y_start (float y_start);
+    virtual float get_stable_y_start () {
+        return _stable_y_start;
+    }
+
+    void set_left_scale_factor (PointFloat2 factor);
+    void set_right_scale_factor (PointFloat2 factor);
+
+    virtual PointFloat2 get_left_scale_factor () {
+        return _left_scale_factor;
+    }
+    virtual PointFloat2 get_right_scale_factor () {
+        return _right_scale_factor;
+    }
+
     void set_bowl_config(const BowlDataConfig bowl_data_config) {
         _bowl_data_config = bowl_data_config;
     }
+
     const BowlDataConfig &get_bowl_config() {
         return _bowl_data_config;
     }
@@ -137,9 +153,14 @@
     float                            _map_factor;
     bool                             _use_map;
     uint32_t                         _need_lsc;
+    uint32_t                         _need_scale;
     uint32_t                         _lsc_array_size;
     float                            _gray_threshold[2];  // [min_gray_threshold, max_gray_threshold]
     float                            *_lsc_array;
+    float                            _stable_y_start;
+
+    PointFloat2                      _left_scale_factor;
+    PointFloat2                      _right_scale_factor;
 
     BowlDataConfig                   _bowl_data_config;
 
@@ -155,7 +176,7 @@
 };
 
 SmartPtr<CLImageHandler>
-create_fisheye_handler (const SmartPtr<CLContext> &context, SurroundMode surround_mode = SphereView, bool use_map = false, bool need_lsc = false);
+create_fisheye_handler (const SmartPtr<CLContext> &context, SurroundMode surround_mode = SphereView, bool use_map = false, bool need_lsc = false, bool need_scale = false);
 
 }
 
diff --git a/modules/ocl/cl_geo_map_handler.cpp b/modules/ocl/cl_geo_map_handler.cpp
index 8151425..abba53f 100644
--- a/modules/ocl/cl_geo_map_handler.cpp
+++ b/modules/ocl/cl_geo_map_handler.cpp
@@ -34,10 +34,11 @@
 #define GEO_MAP_CHANNEL 4  /* only use channel_0, channel_1 */
 
 CLGeoMapKernel::CLGeoMapKernel (
-    const SmartPtr<CLContext> &context, const SmartPtr<GeoKernelParamCallback> handler, bool need_lsc)
+    const SmartPtr<CLContext> &context, const SmartPtr<GeoKernelParamCallback> handler, bool need_lsc, bool need_scale)
     : CLImageKernel (context)
     , _handler (handler)
     , _need_lsc (need_lsc)
+    , _need_scale (need_scale)
 {
     XCAM_ASSERT (handler.ptr ());
 }
@@ -62,6 +63,16 @@
     args.push_back (new CLMemArgument (geo_image));
     args.push_back (new CLArgumentTArray<float, 2> (geo_scale_size));
 
+    if (_need_scale) {
+        PointFloat2 left_scale_factor = _handler->get_left_scale_factor ();
+        PointFloat2 right_scale_factor = _handler->get_right_scale_factor ();
+        float stable_y_start = _handler->get_stable_y_start ();
+
+        args.push_back (new CLArgumentT<PointFloat2> (left_scale_factor));
+        args.push_back (new CLArgumentT<PointFloat2> (right_scale_factor));
+        args.push_back (new CLArgumentT<float> (stable_y_start));
+    }
+
     if (_need_lsc) {
         SmartPtr<CLImage> lsc_image = _handler->get_lsc_table ();
         float *gray_threshold = _handler->get_lsc_gray_threshold ();
@@ -319,14 +330,14 @@
 
 SmartPtr<CLImageKernel>
 create_geo_map_kernel (
-    const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc)
+    const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc, bool need_scale)
 {
     SmartPtr<CLImageKernel> kernel;
-    kernel = new CLGeoMapKernel (context, param_cb, need_lsc);
+    kernel = new CLGeoMapKernel (context, param_cb, need_lsc, need_scale);
     XCAM_ASSERT (kernel.ptr ());
 
     char build_options[1024];
-    snprintf (build_options, sizeof(build_options), "-DENABLE_LSC=%d", need_lsc ? 1 : 0);
+    snprintf (build_options, sizeof(build_options), "-DENABLE_LSC=%d -DENABLE_SCALE=%d", need_lsc ? 1 : 0, need_scale ? 1 : 0);
     XCAM_FAIL_RETURN (
         ERROR, kernel->build_kernel (kernel_geo_map_info, build_options) == XCAM_RETURN_NO_ERROR,
         NULL, "build geo map kernel failed");
@@ -335,7 +346,7 @@
 }
 
 SmartPtr<CLImageHandler>
-create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc)
+create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc, bool need_scale)
 {
     SmartPtr<CLGeoMapHandler> handler;
     SmartPtr<CLImageKernel> kernel;
@@ -343,7 +354,7 @@
     handler = new CLGeoMapHandler (context);
     XCAM_ASSERT (handler.ptr ());
 
-    kernel = create_geo_map_kernel (context, handler, need_lsc);
+    kernel = create_geo_map_kernel (context, handler, need_lsc, need_scale);
     XCAM_FAIL_RETURN (
         ERROR, kernel.ptr (), NULL, "CLMapHandler build geo map kernel failed");
     handler->add_kernel (kernel);
diff --git a/modules/ocl/cl_geo_map_handler.h b/modules/ocl/cl_geo_map_handler.h
index a41ad27..4a79545 100644
--- a/modules/ocl/cl_geo_map_handler.h
+++ b/modules/ocl/cl_geo_map_handler.h
@@ -52,6 +52,10 @@
     virtual SmartPtr<CLImage> get_lsc_table () = 0;
     virtual float* get_lsc_gray_threshold() = 0;
 
+    virtual PointFloat2 get_left_scale_factor () = 0;
+    virtual PointFloat2 get_right_scale_factor () = 0;
+
+    virtual float get_stable_y_start () = 0;
 private:
     XCAM_DEAD_COPY (GeoKernelParamCallback);
 };
@@ -64,7 +68,7 @@
     explicit CLGeoMapKernel (
         const SmartPtr<CLContext> &context,
         const SmartPtr<GeoKernelParamCallback> handler,
-        bool need_lsc);
+        bool need_lsc, bool need_scale);
 
 protected:
     virtual XCamReturn prepare_arguments (CLArgList &args, CLWorkSize &work_size);
@@ -72,6 +76,7 @@
 private:
     SmartPtr<GeoKernelParamCallback>   _handler;
     bool                               _need_lsc;
+    bool                               _need_scale;
 };
 
 class CLGeoMapHandler
@@ -122,6 +127,22 @@
         return NULL;
     }
 
+    virtual PointFloat2 get_left_scale_factor () {
+        XCAM_ASSERT (false && "CLGeoMapHandler::left_scale_factor is not supported");
+        return PointFloat2 (0.0f, 0.0f);
+    }
+
+    virtual PointFloat2 get_right_scale_factor () {
+        XCAM_ASSERT (false && "CLGeoMapHandler::right_scale_factor is not supported");
+        return PointFloat2 (0.0f, 0.0f);
+    }
+
+    virtual float get_stable_y_start () {
+        XCAM_ASSERT (false && "CLGeoMapHandler::get_stable_y_start is not supported");
+        return 0.0f;
+    }
+
+
 protected:
     virtual XCamReturn prepare_buffer_pool_video_info (
         const VideoBufferInfo &input,
@@ -150,11 +171,11 @@
 
 SmartPtr<CLImageKernel>
 create_geo_map_kernel (
-    const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc);
+    const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc, bool need_scale);
 
 SmartPtr<CLImageHandler>
-create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc = false);
+create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc = false, bool need_scale = false);
 
 }
 
-#endif //XCAM_CL_GEO_MAP_HANDLER_H
\ No newline at end of file
+#endif //XCAM_CL_GEO_MAP_HANDLER_H
diff --git a/modules/ocl/cl_image_360_stitch.cpp b/modules/ocl/cl_image_360_stitch.cpp
index ae19b27..242e1b9 100644
--- a/modules/ocl/cl_image_360_stitch.cpp
+++ b/modules/ocl/cl_image_360_stitch.cpp
@@ -19,9 +19,12 @@
  */
 
 #include "cl_utils.h"
+#include "cl_device.h"
 #include "cl_image_360_stitch.h"
 #if HAVE_OPENCV
-#include "cv_feature_match.h"
+#include "ocv/cv_feature_match.h"
+#include "ocv/cv_feature_match_cluster.h"
+#include <opencv2/core/ocl.hpp>
 #endif
 
 #define XCAM_BLENDER_GLOBAL_SCALE_EXT_WIDTH 64
@@ -109,10 +112,10 @@
 }
 
 #if HAVE_OPENCV
-static CVFMConfig
-get_fm_default_config (StitchResMode res_mode)
+static FMConfig
+get_fm_sphere_config (StitchResMode res_mode)
 {
-    CVFMConfig config;
+    FMConfig config;
 
     switch (res_mode) {
     case StitchRes1080P: {
@@ -158,6 +161,22 @@
 
     return config;
 }
+
+static FMConfig
+get_fm_bowl_config ()
+{
+    FMConfig config;
+    config.sitch_min_width = 136;
+    config.min_corners = 4;
+    config.offset_factor = 0.95f;
+    config.delta_mean_offset = 120.0f;
+    config.recur_offset_error = 8.0f;
+    config.max_adjusted_offset = 24.0f;
+    config.max_valid_offset_y = 20.0f;
+    config.max_track_error = 28.0f;
+
+    return config;
+}
 #endif
 
 static StitchInfo
@@ -280,17 +299,25 @@
     , _scale_mode (scale_mode)
     , _surround_mode (surround_mode)
     , _res_mode (res_mode)
+    , _enable_fm (true)
     , _is_stitch_inited (false)
     , _fisheye_num (fisheye_num)
     , _all_in_one_img (all_in_one_img)
 {
+#if !HAVE_OPENCV
+    _enable_fm = false;
+#endif
+}
+
+void
+CLImage360Stitch::set_feature_match (bool enable)
+{
 #if HAVE_OPENCV
-    for (int i = 0; i < fisheye_num; i++) {
-        _feature_match[i] = new CVFeatureMatch ();
-        XCAM_ASSERT (_feature_match[i].ptr ());
-        _feature_match[i]->set_config (get_fm_default_config (res_mode));
-        _feature_match[i]->set_fm_index (i);
-    }
+    _enable_fm = enable;
+#else
+    if (enable)
+        XCAM_LOG_WARNING ("non-OpenCV mode, feature match is unsupported, disable feature match");
+    _enable_fm = false;
 #endif
 }
 
@@ -371,33 +398,6 @@
 }
 
 void
-CLImage360Stitch::set_feature_match_ocl (bool fm_ocl)
-{
-#if HAVE_OPENCV
-    for (int i = 0; i < _fisheye_num; i++) {
-        _feature_match[i]->set_ocl (fm_ocl);
-    }
-#else
-    XCAM_UNUSED (fm_ocl);
-    XCAM_LOG_WARNING ("non-OpenCV mode, failed to set ocl for feature match");
-#endif
-}
-
-#if HAVE_OPENCV
-void
-CLImage360Stitch::set_feature_match_config (const int idx, CVFMConfig config)
-{
-    _feature_match[idx]->set_config (config);
-}
-
-CVFMConfig
-CLImage360Stitch::get_feature_match_config (const int idx)
-{
-    return _feature_match[idx]->get_config ();
-}
-#endif
-
-void
 CLImage360Stitch::calc_fisheye_initial_info (SmartPtr<VideoBuffer> &output)
 {
     const VideoBufferInfo &out_info = output->get_video_info ();
@@ -431,23 +431,15 @@
     } else {
         _fisheye[0].height = out_info.height + _stitch_info.crop[0].top + _stitch_info.crop[0].bottom;
 
-        float view_angle[XCAM_STITCH_FISHEYE_MAX_NUM];
+        float view_angle[XCAM_STITCH_FISHEYE_MAX_NUM] = {
+            64.0f, 158.0f, 60.0f, 158.0f
+        };
 
-        view_angle[0] = 68.0f;
-        _fisheye[0].width = view_angle[0] / 360.0f * out_info.width;
-        _fisheye[0].width = XCAM_ALIGN_UP (_fisheye[0].width, 32);
-
-        view_angle[1] = 152.0f;
-        _fisheye[1].width = view_angle[1] / 360.0f * out_info.width;
-        _fisheye[1].width = XCAM_ALIGN_UP (_fisheye[1].width, 32);
-
-        view_angle[2] = 68.0f;
-        _fisheye[2].width = view_angle[2] / 360.0f * out_info.width;
-        _fisheye[2].width = XCAM_ALIGN_UP (_fisheye[2].width, 32);
-
-        view_angle[3] = 152.0f;
-        _fisheye[3].width = view_angle[3] / 360.0f * out_info.width;
-        _fisheye[3].width = XCAM_ALIGN_UP (_fisheye[3].width, 32);
+        XCAM_ASSERT (_fisheye_num <= XCAM_STITCH_FISHEYE_MAX_NUM);
+        for (int i = 0; i < _fisheye_num; i++) {
+            _fisheye[i].width = view_angle[i] / 360.0f * out_info.width;
+            _fisheye[i].width = XCAM_ALIGN_UP (_fisheye[i].width, 32);
+        }
 
         XCAM_LOG_INFO (
             "fisheye correction output size width:%d height:%d",
@@ -465,13 +457,26 @@
             bowl_data_config[i].angle_end = angle_center + view_angle[i] / 2;
         }
 
+        float wall_image_height = bowl_data_config[0].wall_height /
+                                  (float)(bowl_data_config[0].wall_height + bowl_data_config[0].ground_length) *
+                                  _fisheye[0].height;
+        float stable_y_start = (wall_image_height + _fisheye[0].height ) / 2.0f;
+
+        if (stable_y_start < 0.5f)
+            stable_y_start = 1.0f;
+
         for(int i = 0; i < _fisheye_num; i++) {
+            _fisheye[i].handler->set_stable_y_start (stable_y_start);
             _fisheye[i].handler->set_bowl_config(bowl_data_config[i]);
             _fisheye[i].handler->set_output_size (_fisheye[i].width, _fisheye[i].height);
         }
 
-        for(int i = 0; i < _fisheye_num; i++) {
-            _stitch_info.merge_width[i] = XCAM_ALIGN_UP((uint32_t)(20.0f / 360.0f * out_info.width), 32);
+        int idx_next;
+        for (int i = 0; i < _fisheye_num; i++) {
+            idx_next = (i == (_fisheye_num - 1)) ? 0 : (i + 1);
+
+            _stitch_info.merge_width[idx_next] = _fisheye[i].width / 2 + _fisheye[idx_next].width / 2 - out_info.width / _fisheye_num;
+            _stitch_info.merge_width[idx_next] = XCAM_ALIGN_UP (_stitch_info.merge_width[idx_next], 32);
         }
     }
 }
@@ -677,13 +682,14 @@
     buf_info.init (V4L2_PIX_FMT_NV12, width, height,
                    XCAM_ALIGN_UP (width, 16), XCAM_ALIGN_UP (height, 16));
 
-    buf_pool = new CLVideoBufferPool ();
-    XCAM_ASSERT (buf_pool.ptr ());
-    buf_pool->set_video_info (buf_info);
-    if (!buf_pool->reserve (6)) {
+    SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+    XCAM_ASSERT (pool.ptr ());
+    pool->set_video_info (buf_info);
+    if (!pool->reserve (6)) {
         XCAM_LOG_ERROR ("CLImage360Stitch init buffer pool failed");
         return false;
     }
+    buf_pool = pool;
 
     return true;
 }
@@ -710,12 +716,63 @@
     return XCAM_RETURN_NO_ERROR;
 }
 
+void
+CLImage360Stitch::init_opencv_ocl ()
+{
+#if HAVE_OPENCV
+    if (!cv::ocl::haveOpenCL ()) {
+        XCAM_LOG_ERROR ("OpenCV does not support OpenCL");
+        XCAM_ASSERT (false);
+    }
+
+    char *platform_name = CLDevice::instance()->get_platform_name ();
+    cl_platform_id platform_id = CLDevice::instance()->get_platform_id ();
+    cl_device_id device_id = CLDevice::instance()->get_device_id ();
+    cl_context context_id = _context->get_context_id ();
+    cv::ocl::attachContext (platform_name, platform_id, context_id, device_id);
+    cv::ocl::setUseOpenCL (false);
+#else
+    XCAM_LOG_ERROR ("non-OpenCV mode, failed to initialize opencv ocl");
+#endif
+}
+
+void
+CLImage360Stitch::init_feature_match ()
+{
+#if HAVE_OPENCV
+    bool is_sphere = (_surround_mode == SphereView);
+    const FMConfig &config = is_sphere ? get_fm_sphere_config (_res_mode) : get_fm_bowl_config ();
+
+    for (int i = 0; i < _fisheye_num; i++) {
+        if (is_sphere) {
+            _feature_match[i] = FeatureMatch::create_default_feature_match ();
+            _feature_match[i]->enable_adjust_crop_area ();
+        } else {
+            _feature_match[i] = FeatureMatch::create_cluster_feature_match ();
+        }
+        XCAM_ASSERT (_feature_match[i].ptr ());
+
+        _feature_match[i]->set_fm_index (i);
+        _feature_match[i]->set_config (config);
+    }
+#else
+    XCAM_LOG_ERROR ("non-OpenCV mode, failed to initialize feature match");
+#endif
+}
+
 XCamReturn
 CLImage360Stitch::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
 {
     XCamReturn ret = XCAM_RETURN_NO_ERROR;
-    if (!_is_stitch_inited)
+    if (!_is_stitch_inited) {
+#if HAVE_OPENCV
+        if (_enable_fm) {
+            init_opencv_ocl ();
+            init_feature_match ();
+        }
+#endif
         set_stitch_info (get_default_stitch_info (_res_mode));
+    }
 
     ret = ensure_fisheye_parameters (input, output);
     STITCH_CHECK (ret, "ensure fisheye parameters failed");
@@ -768,44 +825,106 @@
 XCamReturn
 CLImage360Stitch::execute_done (SmartPtr<VideoBuffer> &output)
 {
-#if HAVE_OPENCV
-    for (int i = 0; i < _fisheye_num; i++) {
-        if (!_feature_match[i]->is_ocl_path ()) {
-            get_context ()->finish ();
-            break;
-        }
-    }
-#endif
-
-    _scale_global_input.release ();
-    _scale_global_output.release ();
-
+    get_context ()->finish ();
     return CLMultiImageHandler::execute_done (output);
 }
 
+void
+CLImage360Stitch::update_scale_factors (uint32_t fm_idx, const Rect &crop_left, const Rect &crop_right)
+{
+#if HAVE_OPENCV
+    float left_offsetx = _feature_match[fm_idx]->get_current_left_offset_x ();
+    float left_offsety = _feature_match[fm_idx]->get_current_left_offset_y ();
+    PointFloat2 left_factor, right_factor;
+
+    uint32_t left_idx = fm_idx;
+    float center_x = (float) _fisheye[left_idx].width / 2;
+    float feature_center_x = (float)crop_left.pos_x + crop_left.width / 2.0f;
+    float range = feature_center_x - center_x;
+    XCAM_ASSERT (range > 1.0f);
+    right_factor.x = (range + left_offsetx / 2.0f) / range;
+    right_factor.y = (_fisheye[left_idx].handler->get_stable_y_start () - left_offsety / 2.0f) /
+                     _fisheye[left_idx].handler->get_stable_y_start ();
+    XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f);
+
+    uint32_t right_idx = (fm_idx + 1) % _fisheye_num;
+    center_x = (float)_fisheye[right_idx].width / 2;
+    feature_center_x = (float)crop_right.pos_x + crop_right.width / 2.0f;
+    range = center_x - feature_center_x;
+    XCAM_ASSERT (range > 1.0f);
+    left_factor.x = (range + left_offsetx / 2.0f) / range;
+    left_factor.y = (_fisheye[left_idx].handler->get_stable_y_start () + left_offsety / 2.0f) /
+                    _fisheye[left_idx].handler->get_stable_y_start ();
+    XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f);
+
+    PointFloat2 last_left_factor, last_right_factor;
+    last_left_factor = _fisheye[right_idx].handler->get_left_scale_factor ();
+    last_right_factor = _fisheye[left_idx].handler->get_right_scale_factor ();
+
+    left_factor.x *= last_left_factor.x;
+    left_factor.y *= last_left_factor.y;
+    right_factor.x *= last_right_factor.x;
+    right_factor.y *= last_right_factor.y;
+
+    _fisheye[left_idx].handler->set_right_scale_factor (right_factor);
+    _fisheye[right_idx].handler->set_left_scale_factor (left_factor);
+#else
+    XCAM_LOG_ERROR ("non-OpenCV mode, failed to update scale factors");
+#endif
+}
+
+void
+CLImage360Stitch::set_fm_buf_mem (
+    const SmartPtr<VideoBuffer> &buf_left, const SmartPtr<VideoBuffer> &buf_right, int fm_idx)
+{
+#if HAVE_OPENCV
+    SmartPtr<CVFeatureMatch> fm = _feature_match[fm_idx].dynamic_cast_ptr<CVFeatureMatch> ();
+    XCAM_ASSERT (fm.ptr ());
+
+    SmartPtr<CLBuffer> cl_buf_left = convert_to_clbuffer (_context, buf_left);
+    SmartPtr<CLBuffer> cl_buf_right = convert_to_clbuffer (_context, buf_right);
+    XCAM_ASSERT (cl_buf_left.ptr () && cl_buf_left.ptr ());
+    cl_mem mem_left = cl_buf_left->get_mem_id ();
+    cl_mem mem_right = cl_buf_right->get_mem_id ();
+
+    fm->set_cl_buf_mem (mem_left, CVFeatureMatch::BufIdLeft);
+    fm->set_cl_buf_mem (mem_right, CVFeatureMatch::BufIdRight);
+#else
+    XCAM_LOG_ERROR ("non-OpenCV mode, failed to set feature match buffer memory");
+#endif
+}
+
+#if HAVE_OPENCV
 static void
-convert_to_stitch_rect (Rect xcam_rect, Rect &stitch_rect)
+convert_to_stitch_rect (const Rect &xcam_rect, Rect &stitch_rect, SurroundMode surround_mode)
 {
     stitch_rect.pos_x = xcam_rect.pos_x;
-    stitch_rect.pos_y = xcam_rect.pos_y + xcam_rect.height / 3;
     stitch_rect.width = xcam_rect.width;
-    stitch_rect.height = xcam_rect.height / 3;
+    if (surround_mode == SphereView) {
+        stitch_rect.pos_y = xcam_rect.pos_y + xcam_rect.height / 3;
+        stitch_rect.height = xcam_rect.height / 3;
+    } else {
+        stitch_rect.pos_y = xcam_rect.pos_y + xcam_rect.height / 5;
+        stitch_rect.height = xcam_rect.height / 2;
+    }
 }
 
 static void
-convert_to_xcam_rect (Rect stitch_rect, Rect &xcam_rect)
+convert_to_xcam_rect (const Rect &stitch_rect, Rect &xcam_rect)
 {
     xcam_rect.pos_x = stitch_rect.pos_x;
     xcam_rect.width = stitch_rect.width;
 }
-
+#endif
 
 XCamReturn
 CLImage360Stitch::sub_handler_execute_done (SmartPtr<CLImageHandler> &handler)
 {
 #if HAVE_OPENCV
-    XCAM_ASSERT (handler.ptr ());
+    if (!_enable_fm)
+        return XCAM_RETURN_NO_ERROR;
 
+    XCAM_ASSERT (handler.ptr ());
     if (handler.ptr () == _fisheye[_fisheye_num - 1].handler.ptr ()) {
         int idx_next = 1;
         Rect crop_left, crop_right;
@@ -813,14 +932,25 @@
         for (int i = 0; i < _fisheye_num; i++) {
             idx_next = (i == (_fisheye_num - 1)) ? 0 : (i + 1);
 
-            convert_to_stitch_rect (_img_merge_info[i].right, crop_left);
-            convert_to_stitch_rect (_img_merge_info[idx_next].left, crop_right);
+            set_fm_buf_mem (_fisheye[i].buf, _fisheye[idx_next].buf, i);
 
-            _feature_match[i]->optical_flow_feature_match (
-                _fisheye[i].buf, _fisheye[idx_next].buf, crop_left, crop_right, _fisheye[i].width);
+            convert_to_stitch_rect (_img_merge_info[i].right, crop_left, _surround_mode);
+            convert_to_stitch_rect (_img_merge_info[idx_next].left, crop_right, _surround_mode);
+            if (_surround_mode == SphereView) {
+                _feature_match[i]->set_dst_width (_fisheye[i].width);
+                _feature_match[i]->set_crop_rect (crop_left, crop_right);
+                _feature_match[i]->feature_match (_fisheye[i].buf, _fisheye[idx_next].buf);
 
-            convert_to_xcam_rect (crop_left, _img_merge_info[i].right);
-            convert_to_xcam_rect (crop_right, _img_merge_info[idx_next].left);
+                _feature_match[i]->get_crop_rect (crop_left, crop_right);
+                convert_to_xcam_rect (crop_left, _img_merge_info[i].right);
+                convert_to_xcam_rect (crop_right, _img_merge_info[idx_next].left);
+            } else {
+                _feature_match[i]->reset_offsets ();
+                _feature_match[i]->set_crop_rect (crop_left, crop_right);
+                _feature_match[i]->feature_match (_fisheye[i].buf, _fisheye[idx_next].buf);
+
+                update_scale_factors (i, crop_left, crop_right);
+            }
         }
     }
 #else
@@ -871,8 +1001,10 @@
         context, scale_mode, surround_mode, res_mode, fisheye_num, all_in_one_img);
     XCAM_ASSERT (stitch.ptr ());
 
+    bool need_scale = (surround_mode == BowlView) ? true : false;
+
     for (int index = 0; index < fisheye_num; ++index) {
-        fisheye = create_fisheye_handler (context, surround_mode, fisheye_map, need_lsc).dynamic_cast_ptr<CLFisheyeHandler> ();
+        fisheye = create_fisheye_handler (context, surround_mode, fisheye_map, need_lsc, need_scale).dynamic_cast_ptr<CLFisheyeHandler> ();
         XCAM_FAIL_RETURN (ERROR, fisheye.ptr (), NULL, "image_360_stitch create fisheye handler failed");
         fisheye->disable_buf_pool (true);
         stitch->set_fisheye_handler (fisheye, index);
diff --git a/modules/ocl/cl_image_360_stitch.h b/modules/ocl/cl_image_360_stitch.h
index 2c6babf..c164d4b 100644
--- a/modules/ocl/cl_image_360_stitch.h
+++ b/modules/ocl/cl_image_360_stitch.h
@@ -66,6 +66,8 @@
         const SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode, SurroundMode surround_mode,
         StitchResMode res_mode, int fisheye_num, bool all_in_one_img);
 
+    void set_feature_match (bool enable);
+
     bool set_stitch_info (StitchInfo stitch_info);
     StitchInfo get_stitch_info ();
     void set_output_size (uint32_t width, uint32_t height) {
@@ -94,12 +96,6 @@
         return _scale_global_output;
     }
 
-    void set_feature_match_ocl (bool use_ocl);
-#if HAVE_OPENCV
-    void set_feature_match_config (const int idx, CVFMConfig config);
-    CVFMConfig get_feature_match_config (const int idx);
-#endif
-
 protected:
     virtual XCamReturn prepare_buffer_pool_video_info (const VideoBufferInfo &input, VideoBufferInfo &output);
     virtual XCamReturn prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output);
@@ -121,13 +117,19 @@
     void update_image_overlap ();
 
 private:
+    void init_opencv_ocl ();
+    void init_feature_match ();
+    void update_scale_factors (uint32_t fm_idx, const Rect &crop_left, const Rect &crop_right);
+    void set_fm_buf_mem (
+        const SmartPtr<VideoBuffer> &buf_left, const SmartPtr<VideoBuffer> &buf_right, int fm_idx);
+
+private:
     XCAM_DEAD_COPY (CLImage360Stitch);
 
 private:
     SmartPtr<CLContext>         _context;
     CLFisheyeParams             _fisheye[XCAM_STITCH_FISHEYE_MAX_NUM];
     SmartPtr<CLBlender>         _blender[XCAM_STITCH_FISHEYE_MAX_NUM];
-    SmartPtr<FeatureMatch>      _feature_match[XCAM_STITCH_FISHEYE_MAX_NUM];
 
     uint32_t                    _output_width;
     uint32_t                    _output_height;
@@ -142,6 +144,9 @@
     SurroundMode                _surround_mode;
     StitchResMode               _res_mode;
 
+    bool                        _enable_fm;
+    SmartPtr<FeatureMatch>      _feature_match[XCAM_STITCH_FISHEYE_MAX_NUM];
+
     bool                        _is_stitch_inited;
     int                         _fisheye_num;
     bool                        _all_in_one_img;
diff --git a/modules/ocl/cl_image_handler.cpp b/modules/ocl/cl_image_handler.cpp
index f9fc56c..2fb87ab 100644
--- a/modules/ocl/cl_image_handler.cpp
+++ b/modules/ocl/cl_image_handler.cpp
@@ -25,6 +25,7 @@
 #include "drm_bo_buffer.h"
 #endif
 #include "cl_device.h"
+#include "cl_video_buffer.h"
 #include "swapped_buffer.h"
 
 namespace XCam {
@@ -167,9 +168,9 @@
     if (_buf_pool.ptr ())
         return XCAM_RETURN_ERROR_PARAM;
 
-    SmartPtr<BufferPool> buffer_pool;
     if (_buf_pool_type == CLImageHandler::CLVideoPoolType) {
-        buffer_pool = new CLVideoBufferPool ();
+        SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+        _buf_pool = pool.ptr() ? pool : _buf_pool;
     }
 #if HAVE_LIBDRM
     else {
@@ -181,30 +182,29 @@
             "CLImageHandler(%s) failed to get drm dispay", XCAM_STR (_name));
 
         if (_buf_pool_type == CLImageHandler::DrmBoPoolType) {
-            buffer_pool = new DrmBoBufferPool (display);
+            SmartPtr<BufferPool> pool = new DrmBoBufferPool (display);
+            _buf_pool = pool.ptr() ? pool : _buf_pool;
         } else if (_buf_pool_type == CLImageHandler::CLBoPoolType) {
-            buffer_pool = new CLBoBufferPool (display, get_context ());
+            SmartPtr<BufferPool> pool = new CLBoBufferPool (display, get_context ());
+            _buf_pool = pool.ptr() ? pool : _buf_pool;
         }
     }
 #endif
     XCAM_FAIL_RETURN(
         WARNING,
-        buffer_pool.ptr (),
+        _buf_pool.ptr (),
         XCAM_RETURN_ERROR_CL,
         "CLImageHandler(%s) create buffer pool failed, pool_type:%d",
         XCAM_STR (_name), (int32_t)_buf_pool_type);
 
-    XCAM_ASSERT (buffer_pool.ptr ());
     // buffer_pool->set_swap_flags (_buf_swap_flags, _buf_swap_init_order);
-    buffer_pool->set_video_info (video_info);
-
+    _buf_pool->set_video_info (video_info);
     XCAM_FAIL_RETURN(
         WARNING,
-        buffer_pool->reserve (_buf_pool_size),
+        _buf_pool->reserve (_buf_pool_size),
         XCAM_RETURN_ERROR_CL,
         "CLImageHandler(%s) failed to init drm buffer pool", XCAM_STR (_name));
 
-    _buf_pool = buffer_pool;
     return XCAM_RETURN_NO_ERROR;
 }
 
diff --git a/modules/ocl/cl_image_handler.h b/modules/ocl/cl_image_handler.h
index 45c1b31..dd32da7 100644
--- a/modules/ocl/cl_image_handler.h
+++ b/modules/ocl/cl_image_handler.h
@@ -27,11 +27,11 @@
 #include <ocl/cl_kernel.h>
 #include <ocl/cl_argument.h>
 #include <ocl/cl_memory.h>
-#include <ocl/cl_video_buffer.h>
 
 namespace XCam {
 
 class CLImageHandler;
+class X3aResult;
 
 class CLImageKernel
     : public CLKernel
diff --git a/modules/ocl/cl_image_processor.cpp b/modules/ocl/cl_image_processor.cpp
index c0cbd98..a4c178d 100644
--- a/modules/ocl/cl_image_processor.cpp
+++ b/modules/ocl/cl_image_processor.cpp
@@ -83,11 +83,13 @@
     _context = CLDevice::instance ()->get_context ();
     XCAM_ASSERT (_context.ptr());
 
-    _handler_thread = new CLHandlerThread (this);
-    XCAM_ASSERT (_handler_thread.ptr ());
+    SmartPtr<CLHandlerThread> handler_thread = new CLHandlerThread (this);
+    XCAM_ASSERT (handler_thread.ptr ());
+    _handler_thread = handler_thread;
 
-    _done_buf_thread = new CLBufferNotifyThread (this);
-    XCAM_ASSERT (_done_buf_thread.ptr ());
+    SmartPtr<CLBufferNotifyThread> done_buf_thread = new CLBufferNotifyThread (this);
+    XCAM_ASSERT (done_buf_thread.ptr ());
+    _done_buf_thread = done_buf_thread;
 
     XCAM_LOG_DEBUG ("CLImageProcessor constructed");
     XCAM_OBJ_PROFILING_INIT;
diff --git a/modules/ocl/cl_image_scaler.cpp b/modules/ocl/cl_image_scaler.cpp
index c888b36..171ca30 100644
--- a/modules/ocl/cl_image_scaler.cpp
+++ b/modules/ocl/cl_image_scaler.cpp
@@ -219,10 +219,11 @@
 
         scaler_video_info.init (video_info.format, new_width, new_height);
 
-        _scaler_buf_pool = new CLVideoBufferPool ();
-        XCAM_ASSERT (_scaler_buf_pool.ptr ());
-        _scaler_buf_pool->set_video_info (scaler_video_info);
-        _scaler_buf_pool->reserve (6);
+        SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+        XCAM_ASSERT (pool.ptr ());
+        pool->set_video_info (scaler_video_info);
+        pool->reserve (6);
+        _scaler_buf_pool = pool;
     }
 
     output = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
diff --git a/modules/ocl/cl_kernel.cpp b/modules/ocl/cl_kernel.cpp
index fdda8ec..47574b6 100644
--- a/modules/ocl/cl_kernel.cpp
+++ b/modules/ocl/cl_kernel.cpp
@@ -34,14 +34,16 @@
 CLKernel::KernelMap CLKernel::_kernel_map;
 Mutex CLKernel::_kernel_map_mutex;
 
-static char*
+static const char*
 default_cache_path () {
-    static char path[XCAM_MAX_STR_SIZE] = {0};
-    snprintf (
-        path, XCAM_MAX_STR_SIZE - 1,
-        "%s/%s", std::getenv ("HOME"), ".xcam/");
+    static std::string path = "/tmp";
+    const char *home_dir = std::getenv ("HOME");
+    if (home_dir)
+        path.assign (home_dir, strlen (home_dir));
 
-    return path;
+    path += "/.xcam";
+
+    return path.c_str ();
 }
 
 const char* CLKernel::_kernel_cache_path = default_cache_path ();
@@ -134,15 +136,15 @@
     bool load_cache = false;
     struct timeval ts;
 
-    const char* cache_path = std::getenv ("XCAM_CL_KERNEL_CACHE_PATH");
-    if (NULL == cache_path) {
-        cache_path = _kernel_cache_path;
-    }
+    std::string cache_path = _kernel_cache_path;
+    const char *env = std::getenv ("XCAM_CL_KERNEL_CACHE_PATH");
+    if (env)
+        cache_path.assign (env, strlen (env));
 
     snprintf (
         cache_filename, XCAM_MAX_STR_SIZE - 1,
         "%s/%s",
-        cache_path, key_str);
+        cache_path.c_str (), key_str);
 
     {
         SmartLock locker (_kernel_map_mutex);
@@ -153,8 +155,8 @@
             single_kernel = new CLKernel (context, info.kernel_name);
             XCAM_ASSERT (single_kernel.ptr ());
 
-            if (access (cache_path, F_OK) == -1) {
-                mkdir (cache_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+            if (access (cache_path.c_str (), F_OK) == -1) {
+                mkdir (cache_path.c_str (), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
             }
 
             ret = cache_file.open (cache_filename, "r");
diff --git a/modules/ocl/cl_post_image_processor.cpp b/modules/ocl/cl_post_image_processor.cpp
index ebe9319..21d230b 100644
--- a/modules/ocl/cl_post_image_processor.cpp
+++ b/modules/ocl/cl_post_image_processor.cpp
@@ -59,7 +59,6 @@
     , _stitch_enable_seam (false)
     , _stitch_fisheye_map (false)
     , _stitch_lsc (false)
-    , _stitch_fm_ocl (false)
     , _stitch_scale_mode (CLBlenderScaleLocal)
     , _stitch_width (0)
     , _stitch_height (0)
@@ -411,9 +410,6 @@
         XCAM_RETURN_ERROR_CL,
         "CLPostImageProcessor create image stitch handler failed");
     _stitch->set_output_size (_stitch_width, _stitch_height);
-#if HAVE_OPENCV
-    _stitch->set_feature_match_ocl (_stitch_fm_ocl);
-#endif
     image_handler->set_pool_type (CLImageHandler::CLVideoPoolType);
     image_handler->set_pool_size (XCAM_CL_POST_IMAGE_MAX_POOL_SIZE);
     image_handler->enable_handler (_enable_stitch);
@@ -512,7 +508,7 @@
 bool
 CLPostImageProcessor::set_image_stitch (
     bool enable_stitch, bool enable_seam, CLBlenderScaleMode scale_mode, bool enable_fisheye_map,
-    bool lsc, bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode)
+    bool lsc, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode)
 {
     XCAM_ASSERT (scale_mode < CLBlenderScaleMax);
 
@@ -529,12 +525,6 @@
     _stitch_height = stitch_height;
     _stitch_res_mode = res_mode;
 
-#if HAVE_OPENCV
-    _stitch_fm_ocl = fm_ocl;
-#else
-    XCAM_UNUSED (fm_ocl);
-#endif
-
     STREAM_LOCK;
 
     return true;
diff --git a/modules/ocl/cl_post_image_processor.h b/modules/ocl/cl_post_image_processor.h
index a06e007..43e7052 100644
--- a/modules/ocl/cl_post_image_processor.h
+++ b/modules/ocl/cl_post_image_processor.h
@@ -95,7 +95,7 @@
     virtual bool set_image_warp (bool enable);
     virtual bool set_image_stitch (
         bool enable_stitch, bool enable_seam, CLBlenderScaleMode scale_mode, bool enable_fisheye_map,
-        bool lsc, bool fm_ocl, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode);
+        bool lsc, uint32_t stitch_width, uint32_t stitch_height, uint32_t res_mode);
 
 protected:
     virtual bool can_process_result (SmartPtr<X3aResult> &result);
@@ -141,7 +141,6 @@
     bool                                      _stitch_enable_seam;
     bool                                      _stitch_fisheye_map;
     bool                                      _stitch_lsc;
-    bool                                      _stitch_fm_ocl;
     CLBlenderScaleMode                        _stitch_scale_mode;
     uint32_t                                  _stitch_width;
     uint32_t                                  _stitch_height;
diff --git a/modules/ocl/cl_retinex_handler.cpp b/modules/ocl/cl_retinex_handler.cpp
index 79b5dd1..547d033 100644
--- a/modules/ocl/cl_retinex_handler.cpp
+++ b/modules/ocl/cl_retinex_handler.cpp
@@ -234,10 +234,11 @@
 
         scaler_video_info.init (video_info.format, new_width, new_height);
 
-        _scaler_buf_pool = new CLVideoBufferPool ();
-        XCAM_ASSERT (_scaler_buf_pool.ptr ());
-        _scaler_buf_pool->set_video_info (scaler_video_info);
-        _scaler_buf_pool->reserve (XCAM_RETINEX_MAX_SCALE + 1);
+        SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+        XCAM_ASSERT (pool.ptr ());
+        pool->set_video_info (scaler_video_info);
+        pool->reserve (XCAM_RETINEX_MAX_SCALE + 1);
+        _scaler_buf_pool = pool;
 
         _scaler_buf1 = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
         XCAM_ASSERT (_scaler_buf1.ptr ());
diff --git a/modules/ocl/cl_utils.cpp b/modules/ocl/cl_utils.cpp
index b8ce3a9..831850e 100644
--- a/modules/ocl/cl_utils.cpp
+++ b/modules/ocl/cl_utils.cpp
@@ -317,8 +317,8 @@
     for (int row = 0; row < height; row++) {
         for (int col = 0; col < width; col++) {
             float plane_point_coords[3];
-            plane_point_coords[0] = (center_x - col) * length_per_pixel_x * cos (PI / 2 - degree2radian (angle_center)) + plane_center_coords[0];
-            plane_point_coords[1] = (center_x - col) * length_per_pixel_x * sin (PI / 2 - degree2radian (angle_center)) + plane_center_coords[1];
+            plane_point_coords[0] = (center_x - col) * length_per_pixel_x * cos (XCAM_PI / 2 - degree2radian (angle_center)) + plane_center_coords[0];
+            plane_point_coords[1] = (center_x - col) * length_per_pixel_x * sin (XCAM_PI / 2 - degree2radian (angle_center)) + plane_center_coords[1];
             plane_point_coords[2] = (center_y - row) * length_per_pixel_y + plane_center_coords[2];
 
             float rate_xz, rate_yz;
diff --git a/modules/ocl/cl_video_buffer.cpp b/modules/ocl/cl_video_buffer.cpp
index 032dd3d..c16d665 100644
--- a/modules/ocl/cl_video_buffer.cpp
+++ b/modules/ocl/cl_video_buffer.cpp
@@ -22,6 +22,7 @@
 #include "ocl/cl_memory.h"
 #include "ocl/cl_device.h"
 #include "ocl/cl_video_buffer.h"
+#include "x3a_stats_pool.h"
 
 namespace XCam {
 
diff --git a/modules/ocl/cl_video_buffer.h b/modules/ocl/cl_video_buffer.h
index 969bff1..e44e023 100644
--- a/modules/ocl/cl_video_buffer.h
+++ b/modules/ocl/cl_video_buffer.h
@@ -25,13 +25,13 @@
 #include <safe_list.h>
 #include <xcam_mutex.h>
 #include <buffer_pool.h>
-#include <x3a_stats_pool.h>
 #include <ocl/cl_context.h>
 
 namespace XCam {
 
 class CLBuffer;
 class CLVideoBufferPool;
+class X3aStats;
 
 class CLVideoBufferData
     : public BufferData
diff --git a/modules/ocl/cv_base_class.cpp b/modules/ocl/cv_base_class.cpp
deleted file mode 100644
index 7dbecaa..0000000
--- a/modules/ocl/cv_base_class.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * cv_base_class.cpp - base class for all OpenCV related features
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Andrey Parfenov <a1994ndrey@gmail.com>
- * Author: Wind Yuan <feng.yuan@intel.com>
- */
-
-#include "cv_base_class.h"
-
-namespace XCam {
-
-CVBaseClass::CVBaseClass ()
-{
-    _cv_context = CVContext::instance ();
-    XCAM_ASSERT (_cv_context.ptr ());
-    _use_ocl = _cv_context->is_ocl_enabled ();
-}
-
-bool
-CVBaseClass::set_ocl (bool use_ocl)
-{
-    if (use_ocl && !_cv_context->is_ocl_enabled ()) {
-        return false;
-    }
-    _use_ocl = use_ocl;
-    return true;
-}
-
-bool
-CVBaseClass::convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image)
-{
-
-    VideoBufferInfo info = buffer->get_video_info ();
-    XCAM_FAIL_RETURN (WARNING, info.format == V4L2_PIX_FMT_NV12, false, "convert_to_mat only support NV12 format");
-
-    uint8_t *ptr = buffer->map ();
-    XCAM_FAIL_RETURN (WARNING, ptr, false, "convert_to_mat buffer map failed");
-
-    cv::Mat mat = cv::Mat (info.aligned_height * 3 / 2, info.width, CV_8UC1, ptr, info.strides[0]);
-    cv::cvtColor (mat, image, cv::COLOR_YUV2BGR_NV12);
-    //buffer->unmap ();
-
-    return true;
-}
-
-bool
-convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image)
-{
-    CVBaseClass cv_obj;
-    return cv_obj.convert_to_mat (buffer, image);
-}
-
-}
diff --git a/modules/ocl/cv_base_class.h b/modules/ocl/cv_base_class.h
deleted file mode 100644
index 70641c2..0000000
--- a/modules/ocl/cv_base_class.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * cv_base_class.h - base class for all OpenCV related features
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Andrey Parfenov <a1994ndrey@gmail.com>
- * Author: Wind Yuan <feng.yuan@intel.com>
- */
-
-#ifndef XCAM_CV_BASE_CLASS_H
-#define XCAM_CV_BASE_CLASS_H
-
-#include <xcam_std.h>
-#include <video_buffer.h>
-#include <ocl/cv_context.h>
-
-namespace XCam {
-
-class CVBaseClass
-{
-public:
-    explicit CVBaseClass ();
-    bool set_ocl (bool use_ocl);
-    bool is_ocl_path () {
-        return _use_ocl;
-    }
-    bool convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image);
-
-protected:
-    XCAM_DEAD_COPY (CVBaseClass);
-    SmartPtr<CVContext>  _cv_context;
-    bool                 _use_ocl;
-};
-
-extern bool
-convert_to_mat (SmartPtr<VideoBuffer> buffer, cv::Mat &image);
-
-}
-
-#endif // XCAM_CV_BASE_CLASS_H
diff --git a/modules/ocl/cv_context.cpp b/modules/ocl/cv_context.cpp
deleted file mode 100644
index babf5ef..0000000
--- a/modules/ocl/cv_context.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * cv_context.cpp - used to init_opencv_ocl once
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Andrey Parfenov <a1994ndrey@gmail.com>
- * Author: Wind Yuan <feng.yuan@intel.com>
- */
-
-#include "cv_context.h"
-#include "cl_device.h"
-#include "cl_memory.h"
-
-namespace XCam {
-
-Mutex CVContext::_init_mutex;
-SmartPtr<CVContext> CVContext::_instance;
-
-
-SmartPtr<CVContext>
-CVContext::instance ()
-{
-    SmartLock locker (_init_mutex);
-    if (_instance.ptr())
-        return _instance;
-
-    _instance = new CVContext ();
-    _instance->init_opencv_ocl ();
-    return _instance;
-}
-
-void
-CVContext::init_opencv_ocl ()
-{
-    _context = CLDevice::instance()->get_context();
-    cl_platform_id platform_id = CLDevice::instance()->get_platform_id ();
-    char *platform_name = CLDevice::instance()->get_platform_name ();
-    cl_device_id device_id = CLDevice::instance()->get_device_id ();
-    cl_context _context_id = _context->get_context_id ();
-    cv::ocl::attachContext (platform_name, platform_id, _context_id, device_id);
-    cv::ocl::setUseOpenCL (cv::ocl::haveOpenCL());
-    XCAM_LOG_DEBUG("Use OpenCL is:  %s", cv::ocl::haveOpenCL() ? "true" : "false");
-}
-
-bool
-CVContext::enable_ocl (bool flag)
-{
-    if (flag && !cv::ocl::haveOpenCL()) {
-        return false;
-    }
-    cv::ocl::setUseOpenCL (flag);
-    return true;
-}
-
-bool
-CVContext::is_ocl_enabled () const
-{
-    return cv::ocl::useOpenCL ();
-}
-
-CVContext::CVContext ()
-{
-
-}
-
-CVContext::~CVContext () {
-
-}
-
-}
diff --git a/modules/ocl/cv_context.h b/modules/ocl/cv_context.h
deleted file mode 100644
index 17363be..0000000
--- a/modules/ocl/cv_context.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * cv_context.h - used to init_opencv_ocl once
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Andrey Parfenov <a1994ndrey@gmail.com>
- * Author: Wind Yuan <feng.yuan@intel.com>
- */
-
-#ifndef XCAM_CV_CONTEXT_H
-#define XCAM_CV_CONTEXT_H
-
-#include <xcam_std.h>
-#include <xcam_obj_debug.h>
-#include <xcam_mutex.h>
-#include <ocl/cl_context.h>
-
-#include <opencv2/opencv.hpp>
-#include <opencv2/core/ocl.hpp>
-
-namespace XCam {
-
-class CVContext
-{
-public:
-    static SmartPtr<CVContext> instance ();
-
-    SmartPtr<CLContext> get_cl_context () {
-        return _context;
-    }
-    ~CVContext();
-    bool enable_ocl (bool flag);
-    bool is_ocl_enabled () const;
-
-private:
-    CVContext ();
-    void init_opencv_ocl ();
-
-    static Mutex                _init_mutex;
-    static SmartPtr<CVContext>  _instance;
-
-    SmartPtr<CLContext>         _context;
-
-    XCAM_DEAD_COPY (CVContext);
-
-};
-
-}
-
-#endif // XCAM_CV_CONTEXT_H
diff --git a/modules/ocl/cv_feature_match.cpp b/modules/ocl/cv_feature_match.cpp
deleted file mode 100644
index e4e2ea8..0000000
--- a/modules/ocl/cv_feature_match.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * cv_feature_match.cpp - optical flow feature match
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Wind Yuan <feng.yuan@intel.com>
- * Author: Yinhang Liu <yinhangx.liu@intel.com>
- */
-
-#include "cv_feature_match.h"
-#include "xcam_obj_debug.h"
-#include "image_file_handle.h"
-#include "cl_utils.h"
-
-#define XCAM_CV_FM_DEBUG 0
-#define XCAM_CV_OF_DRAW_SCALE 2
-
-namespace XCam {
-#if XCAM_CV_FM_DEBUG
-static void debug_write_image (
-    const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str);
-#endif
-
-CVFeatureMatch::CVFeatureMatch ()
-    : CVBaseClass ()
-    , FeatureMatch ()
-{
-    XCAM_ASSERT (_cv_context.ptr ());
-}
-
-bool
-CVFeatureMatch::get_crop_image (
-    const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, cv::UMat &img)
-{
-    SmartPtr<CLBuffer> cl_buffer = convert_to_clbuffer (_cv_context->get_cl_context (), buffer);
-    VideoBufferInfo info = buffer->get_video_info ();
-    cl_mem cl_mem_id = cl_buffer->get_mem_id ();
-
-    cv::UMat umat;
-    cv::ocl::convertFromBuffer (cl_mem_id, info.strides[0], info.height, info.width, CV_8U, umat);
-    if (umat.empty ()) {
-        XCAM_LOG_ERROR ("FeatureMatch(idx:%d): convert bo buffer to UMat failed", _fm_idx);
-        return false;
-    }
-
-    img = umat (cv::Rect(crop_rect.pos_x, crop_rect.pos_y, crop_rect.width, crop_rect.height));
-
-    return true;
-}
-
-void
-CVFeatureMatch::add_detected_data (
-    cv::InputArray image, cv::Ptr<cv::Feature2D> detector, std::vector<cv::Point2f> &corners)
-{
-    std::vector<cv::KeyPoint> keypoints;
-    detector->detect (image, keypoints);
-    corners.reserve (corners.size () + keypoints.size ());
-    for (size_t i = 0; i < keypoints.size (); ++i) {
-        cv::KeyPoint &kp = keypoints[i];
-        corners.push_back (kp.pt);
-    }
-}
-
-void
-CVFeatureMatch::get_valid_offsets (
-    std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
-    std::vector<uchar> &status, std::vector<float> &error,
-    std::vector<float> &offsets, float &sum, int &count,
-    cv::InputOutputArray debug_img, cv::Size &img0_size)
-{
-    count = 0;
-    sum = 0.0f;
-    for (uint32_t i = 0; i < status.size (); ++i) {
-        if (!status[i])
-            continue;
-
-#if XCAM_CV_FM_DEBUG
-        cv::Point start = cv::Point(corner0[i]) * XCAM_CV_OF_DRAW_SCALE;
-        cv::circle (debug_img, start, 4, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE);
-#endif
-        if (error[i] > _config.max_track_error)
-            continue;
-        if (fabs(corner0[i].y - corner1[i].y) >= _config.max_valid_offset_y)
-            continue;
-        if (corner1[i].x < 0.0f || corner1[i].x > img0_size.width)
-            continue;
-
-        float offset = corner1[i].x - corner0[i].x;
-        sum += offset;
-        ++count;
-        offsets.push_back (offset);
-
-#if XCAM_CV_FM_DEBUG
-        cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
-        cv::line (debug_img, start, end, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE);
-#else
-        XCAM_UNUSED (debug_img);
-        XCAM_UNUSED (img0_size);
-#endif
-    }
-}
-
-void
-CVFeatureMatch::calc_of_match (
-    cv::InputArray image0, cv::InputArray image1,
-    std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
-    std::vector<uchar> &status, std::vector<float> &error,
-    int &last_count, float &last_mean_offset, float &out_x_offset)
-{
-    cv::_InputOutputArray debug_img;
-    cv::Size img0_size = image0.size ();
-    XCAM_ASSERT (img0_size.height == image1.rows ());
-    XCAM_UNUSED (image1);
-
-#if XCAM_CV_FM_DEBUG
-    cv::Mat mat;
-    cv::UMat umat;
-    cv::Size img1_size = image1.size ();
-    cv::Size size (img0_size.width + img1_size.width, img0_size.height);
-
-    if (image0.isUMat ()) {
-        umat.create (size, image0.type ());
-        debug_img = cv::_InputOutputArray (umat);
-
-        image0.copyTo (umat (cv::Rect(0, 0, img0_size.width, img0_size.height)));
-        image1.copyTo (umat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height)));
-        umat.copyTo (debug_img);
-    } else {
-        mat.create (size, image0.type ());
-        debug_img = cv::_InputOutputArray (mat);
-
-        image0.copyTo (mat (cv::Rect(0, 0, img0_size.width, img0_size.height)));
-        image1.copyTo (mat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height)));
-        mat.copyTo (debug_img);
-    }
-
-    cv::Size scale_size = size * XCAM_CV_OF_DRAW_SCALE;
-    cv::resize (debug_img, debug_img, scale_size, 0, 0);
-#endif
-
-    std::vector<float> offsets;
-    float offset_sum = 0.0f;
-    int count = 0;
-    float mean_offset = 0.0f;
-    offsets.reserve (corner0.size ());
-    get_valid_offsets (corner0, corner1, status, error,
-                       offsets, offset_sum, count, debug_img, img0_size);
-#if XCAM_CV_FM_DEBUG
-    XCAM_LOG_INFO ("FeatureMatch(idx:%d): valid offsets:%d", _fm_idx, offsets.size ());
-    char file_name[256];
-    std::snprintf (file_name, 256, "fm_optical_flow_%d_%d.jpg", _frame_num, _fm_idx);
-    cv::imwrite (file_name, debug_img);
-#endif
-
-    bool ret = get_mean_offset (offsets, offset_sum, count, mean_offset);
-    if (ret) {
-        if (fabs (mean_offset - last_mean_offset) < _config.delta_mean_offset) {
-            out_x_offset = out_x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor);
-
-            if (fabs (out_x_offset) > _config.max_adjusted_offset)
-                out_x_offset = (out_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
-        }
-    }
-
-    last_count = count;
-    last_mean_offset = mean_offset;
-}
-
-void
-CVFeatureMatch::detect_and_match (
-    cv::InputArray img_left, cv::InputArray img_right, Rect &crop_left, Rect &crop_right,
-    int &valid_count, float &mean_offset, float &x_offset, int dst_width)
-{
-    std::vector<float> err;
-    std::vector<uchar> status;
-    std::vector<cv::Point2f> corner_left, corner_right;
-    cv::Ptr<cv::Feature2D> fast_detector;
-    cv::Size win_size = cv::Size (5, 5);
-
-    if (img_left.isUMat ())
-        win_size = cv::Size (16, 16);
-
-    fast_detector = cv::FastFeatureDetector::create (20, true);
-    add_detected_data (img_left, fast_detector, corner_left);
-
-    if (corner_left.empty ()) {
-        return;
-    }
-
-    cv::calcOpticalFlowPyrLK (
-        img_left, img_right, corner_left, corner_right, status, err, win_size, 3,
-        cv::TermCriteria (cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 10, 0.01f));
-    cv::ocl::finish();
-
-    calc_of_match (img_left, img_right, corner_left, corner_right,
-                   status, err, valid_count, mean_offset, x_offset);
-
-    adjust_stitch_area (dst_width, x_offset, crop_left, crop_right);
-
-#if XCAM_CV_FM_DEBUG
-    XCAM_LOG_INFO (
-        "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)",
-        _fm_idx, crop_left.pos_x, crop_left.width, crop_right.pos_x, crop_right.width);
-#endif
-}
-
-void
-CVFeatureMatch::optical_flow_feature_match (
-    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
-    Rect &left_crop_rect, Rect &right_crop_rect, int dst_width)
-{
-    cv::UMat left_umat, right_umat;
-    cv::Mat left_mat, right_mat;
-    cv::_InputArray left_img, right_img;
-
-    if (!get_crop_image (left_buf, left_crop_rect, left_umat)
-            || !get_crop_image (right_buf, right_crop_rect, right_umat))
-        return;
-
-    if (_use_ocl) {
-        left_img = cv::_InputArray (left_umat);
-        right_img = cv::_InputArray (right_umat);
-    } else {
-        left_mat = left_umat.getMat (cv::ACCESS_READ);
-        right_mat = right_umat.getMat (cv::ACCESS_READ);
-
-        left_img = cv::_InputArray (left_mat);
-        right_img = cv::_InputArray (right_mat);
-    }
-
-    detect_and_match (left_img, right_img, left_crop_rect, right_crop_rect,
-                      _valid_count, _mean_offset, _x_offset, dst_width);
-
-#if XCAM_CV_FM_DEBUG
-    XCAM_ASSERT (_fm_idx >= 0);
-
-    char frame_str[64] = {'\0'};
-    std::snprintf (frame_str, 64, "frame:%d", _frame_num);
-    char fm_idx_str[64] = {'\0'};
-    std::snprintf (fm_idx_str, 64, "fm_idx:%d", _fm_idx);
-
-    char img_name[256] = {'\0'};
-    std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_0.jpg", _frame_num, _fm_idx);
-    debug_write_image (left_buf, left_crop_rect, img_name, frame_str, fm_idx_str);
-
-    std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_1.jpg", _frame_num, _fm_idx);
-    debug_write_image (right_buf, right_crop_rect, img_name, frame_str, fm_idx_str);
-
-    XCAM_LOG_INFO ("FeatureMatch(idx:%d): frame number:%d done", _fm_idx, _frame_num);
-    _frame_num++;
-#endif
-}
-
-#if XCAM_CV_FM_DEBUG
-static void
-debug_write_image (
-    const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str)
-{
-    cv::Scalar color = cv::Scalar(0, 0, 255);
-    VideoBufferInfo info = buf->get_video_info ();
-
-    cv::Mat mat;
-    CVBaseClass cv_obj;
-    cv_obj.convert_to_mat (buf, mat);
-
-    cv::putText (mat, frame_str, cv::Point(rect.pos_x, 30), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false);
-    cv::putText (mat, fm_idx_str, cv::Point(rect.pos_x, 70), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false);
-
-    cv::line (mat, cv::Point(rect.pos_x, rect.pos_y), cv::Point(rect.pos_x + rect.width, rect.pos_y), color, 1);
-    cv::line (mat, cv::Point(rect.pos_x, rect.pos_y + rect.height),
-              cv::Point(rect.pos_x + rect.width, rect.pos_y + rect.height), color, 1);
-
-    cv::line (mat, cv::Point(rect.pos_x, 0), cv::Point(rect.pos_x, info.height), color, 2);
-    cv::line (mat, cv::Point(rect.pos_x + rect.width, 0), cv::Point(rect.pos_x + rect.width, info.height), color, 2);
-
-    cv::imwrite (img_name, mat);
-}
-#endif
-
-}
diff --git a/modules/ocl/cv_feature_match.h b/modules/ocl/cv_feature_match.h
deleted file mode 100644
index ed53fae..0000000
--- a/modules/ocl/cv_feature_match.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * cv_feature_match.h - optical flow feature match
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Wind Yuan <feng.yuan@intel.com>
- * Author: Yinhang Liu <yinhangx.liu@intel.com>
- */
-
-#ifndef XCAM_CV_FEATURE_MATCH_H
-#define XCAM_CV_FEATURE_MATCH_H
-
-#include <xcam_std.h>
-#include <video_buffer.h>
-#include <ocl/cv_base_class.h>
-#include <interface/feature_match.h>
-#include <interface/data_types.h>
-
-#include <ocl/cl_context.h>
-#include <ocl/cl_device.h>
-#include <ocl/cl_memory.h>
-
-namespace XCam {
-
-class CVFeatureMatch
-    : public CVBaseClass
-    , public FeatureMatch
-{
-public:
-    explicit CVFeatureMatch ();
-
-    void optical_flow_feature_match (
-        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
-        Rect &left_img_crop, Rect &right_img_crop, int dst_width);
-
-    void set_ocl (bool use_ocl) {
-        CVBaseClass::set_ocl (use_ocl);
-    }
-    bool is_ocl_path () {
-        return CVBaseClass::is_ocl_path ();
-    }
-
-protected:
-    bool get_crop_image (const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, cv::UMat &img);
-
-    void add_detected_data (cv::InputArray image, cv::Ptr<cv::Feature2D> detector, std::vector<cv::Point2f> &corners);
-    void get_valid_offsets (std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
-                            std::vector<uchar> &status, std::vector<float> &error,
-                            std::vector<float> &offsets, float &sum, int &count,
-                            cv::InputOutputArray debug_img, cv::Size &img0_size);
-
-    void calc_of_match (cv::InputArray image0, cv::InputArray image1,
-                        std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
-                        std::vector<uchar> &status, std::vector<float> &error,
-                        int &last_count, float &last_mean_offset, float &out_x_offset);
-
-    void detect_and_match (cv::InputArray img_left, cv::InputArray img_right, Rect &crop_left, Rect &crop_right,
-                           int &valid_count, float &mean_offset, float &x_offset, int dst_width);
-
-private:
-    XCAM_DEAD_COPY (CVFeatureMatch);
-
-};
-
-}
-
-#endif // XCAM_CV_FEATURE_MATCH_H
diff --git a/modules/ocv/Makefile.am b/modules/ocv/Makefile.am
new file mode 100644
index 0000000..fbbdacb
--- /dev/null
+++ b/modules/ocv/Makefile.am
@@ -0,0 +1,29 @@
+noinst_LTLIBRARIES = libxcam_ocv.la
+
+xcam_ocv_sources = \
+    cv_utils.cpp                 \
+    cv_image_process_helper.cpp  \
+    cv_image_sharp.cpp           \
+    cv_edgetaper.cpp             \
+    cv_wiener_filter.cpp         \
+    cv_image_deblurring.cpp      \
+    cv_feature_match.cpp         \
+    cv_feature_match_cluster.cpp \
+    cv_capi_feature_match.cpp    \
+    $(NULL)
+
+libxcam_ocv_la_SOURCES = \
+    $(xcam_ocv_sources) \
+    $(NULL)
+
+libxcam_ocv_la_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)        \
+    $(OPENCV_CFLAGS)        \
+    -I$(top_srcdir)/xcore   \
+    -I$(top_srcdir)/modules \
+    $(NULL)
+
+libxcam_ocv_la_LIBADD = \
+    $(OPENCV_LIBS)                        \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
\ No newline at end of file
diff --git a/modules/soft/cv_capi_feature_match.cpp b/modules/ocv/cv_capi_feature_match.cpp
similarity index 67%
rename from modules/soft/cv_capi_feature_match.cpp
rename to modules/ocv/cv_capi_feature_match.cpp
index 0e0081c..d478f3c 100644
--- a/modules/soft/cv_capi_feature_match.cpp
+++ b/modules/ocv/cv_capi_feature_match.cpp
@@ -24,19 +24,10 @@
 
 #define XCAM_CV_CAPI_FM_DEBUG 0
 
-#if XCAM_CV_CAPI_FM_DEBUG
-#include "ocl/cv_base_class.h"
-#endif
-
 namespace XCam {
-#if XCAM_CV_CAPI_FM_DEBUG
-static void
-debug_write_image (
-    const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str);
-#endif
 
 CVCapiFeatureMatch::CVCapiFeatureMatch ()
-    : FeatureMatch()
+    : FeatureMatch ()
 {
 }
 
@@ -63,8 +54,7 @@
 }
 
 void
-CVCapiFeatureMatch::add_detected_data (
-    CvArr* image, std::vector<CvPoint2D32f> &corners)
+CVCapiFeatureMatch::add_detected_data (CvArr* image, std::vector<CvPoint2D32f> &corners)
 {
     std::vector<CvPoint2D32f> keypoints;
 
@@ -127,10 +117,8 @@
 
 void
 CVCapiFeatureMatch::calc_of_match (
-    CvArr* image0, CvArr* image1,
-    std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
-    std::vector<char> &status, std::vector<float> &error,
-    int &last_count, float &last_mean_offset, float &out_x_offset)
+    CvArr* image0, CvArr* image1, std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
+    std::vector<char> &status, std::vector<float> &error)
 {
     CvMat debug_image;
     CvSize img0_size = cvSize(((CvMat*)image0)->width, ((CvMat*)image0)->height);
@@ -141,6 +129,7 @@
     float offset_sum = 0.0f;
     int count = 0;
     float mean_offset = 0.0f;
+    float last_mean_offset = _mean_offset;
     offsets.reserve (corner0.size ());
 
 #if XCAM_CV_CAPI_FM_DEBUG
@@ -165,21 +154,19 @@
     bool ret = get_mean_offset (offsets, offset_sum, count, mean_offset);
     if (ret) {
         if (fabs (mean_offset - last_mean_offset) < _config.delta_mean_offset) {
-            out_x_offset = out_x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor);
+            _x_offset = _x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor);
 
-            if (fabs (out_x_offset) > _config.max_adjusted_offset)
-                out_x_offset = (out_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
+            if (fabs (_x_offset) > _config.max_adjusted_offset)
+                _x_offset = (_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
         }
     }
 
-    last_count = count;
-    last_mean_offset = mean_offset;
+    _valid_count = count;
+    _mean_offset = mean_offset;
 }
 
 void
-CVCapiFeatureMatch::detect_and_match (
-    CvArr* img_left, CvArr* img_right, Rect &crop_left, Rect &crop_right,
-    int &valid_count, float &mean_offset, float &x_offset, int dst_width)
+CVCapiFeatureMatch::detect_and_match (CvArr* img_left, CvArr* img_right)
 {
     std::vector<float> err;
     std::vector<char> status;
@@ -211,31 +198,26 @@
     XCAM_LOG_INFO ("FeatureMatch(idx:%d): matched corners:%d", _fm_idx, count);
 #endif
 
-    calc_of_match (img_left, img_right, corner_left, corner_right,
-                   status, err, valid_count, mean_offset, x_offset);
-
-    adjust_stitch_area (dst_width, x_offset, crop_left, crop_right);
+    calc_of_match (img_left, img_right, corner_left, corner_right, status, err);
 
 #if XCAM_CV_CAPI_FM_DEBUG
-    XCAM_LOG_INFO (
-        "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)",
-        _fm_idx, crop_left.pos_x, crop_left.width, crop_right.pos_x, crop_right.width);
+    XCAM_LOG_INFO ("FeatureMatch(idx:%d): x_offset:%0.2f", _fm_idx, _x_offset);
 #endif
 }
 
 void
-CVCapiFeatureMatch::optical_flow_feature_match (
-    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
-    Rect &left_crop_rect, Rect &right_crop_rect, int dst_width)
+CVCapiFeatureMatch::feature_match (
+    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf)
 {
-    CvMat left_img, right_img;
+    XCAM_ASSERT (_left_rect.width && _left_rect.height);
+    XCAM_ASSERT (_right_rect.width && _right_rect.height);
 
-    if (!get_crop_image (left_buf, left_crop_rect, _left_crop_image, left_img)
-            || !get_crop_image (right_buf, right_crop_rect, _right_crop_image, right_img))
+    CvMat left_img, right_img;
+    if (!get_crop_image (left_buf, _left_rect, _left_crop_image, left_img)
+            || !get_crop_image (right_buf, _right_rect, _right_crop_image, right_img))
         return;
 
-    detect_and_match ((CvArr*)(&left_img), (CvArr*)(&right_img), left_crop_rect, right_crop_rect,
-                      _valid_count, _mean_offset, _x_offset, dst_width);
+    detect_and_match ((CvArr*)(&left_img), (CvArr*)(&right_img));
 
 #if XCAM_CV_CAPI_FM_DEBUG
     XCAM_ASSERT (_fm_idx >= 0);
@@ -247,10 +229,9 @@
 
     char img_name[256] = {'\0'};
     std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_0.jpg", _frame_num, _fm_idx);
-    debug_write_image (left_buf, left_crop_rect, img_name, frame_str, fm_idx_str);
-
+    write_image (left_buf, _left_rect, img_name, frame_str, fm_idx_str);
     std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_1.jpg", _frame_num, _fm_idx);
-    debug_write_image (right_buf, right_crop_rect, img_name, frame_str, fm_idx_str);
+    write_image (right_buf, _right_rect, img_name, frame_str, fm_idx_str);
 
     XCAM_LOG_INFO ("FeatureMatch(idx:%d): frame number:%d done", _fm_idx, _frame_num);
 
@@ -258,30 +239,13 @@
 #endif
 }
 
-#if XCAM_CV_CAPI_FM_DEBUG
-static void
-debug_write_image (
-    const SmartPtr<VideoBuffer> &buf, const Rect &rect, char *img_name, char *frame_str, char *fm_idx_str)
+SmartPtr<FeatureMatch>
+FeatureMatch::create_capi_feature_match ()
 {
-    cv::Scalar color = cv::Scalar(0, 0, 255);
-    VideoBufferInfo info = buf->get_video_info ();
+    SmartPtr<CVCapiFeatureMatch> matcher = new CVCapiFeatureMatch ();
+    XCAM_ASSERT (matcher.ptr ());
 
-    cv::Mat mat;
-    CVBaseClass cv_obj;
-    cv_obj.convert_to_mat (buf, mat);
-
-    cv::putText (mat, frame_str, cv::Point(rect.pos_x, 30), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false);
-    cv::putText (mat, fm_idx_str, cv::Point(rect.pos_x, 70), cv::FONT_HERSHEY_COMPLEX, 0.8f, color, 2, 8, false);
-
-    cv::line (mat, cv::Point(rect.pos_x, rect.pos_y), cv::Point(rect.pos_x + rect.width, rect.pos_y), color, 1);
-    cv::line (mat, cv::Point(rect.pos_x, rect.pos_y + rect.height),
-              cv::Point(rect.pos_x + rect.width, rect.pos_y + rect.height), color, 1);
-
-    cv::line (mat, cv::Point(rect.pos_x, 0), cv::Point(rect.pos_x, info.height), color, 2);
-    cv::line (mat, cv::Point(rect.pos_x + rect.width, 0), cv::Point(rect.pos_x + rect.width, info.height), color, 2);
-
-    cv::imwrite (img_name, mat);
+    return matcher;
 }
-#endif
 
 }
diff --git a/modules/ocv/cv_capi_feature_match.h b/modules/ocv/cv_capi_feature_match.h
new file mode 100644
index 0000000..f1f8794
--- /dev/null
+++ b/modules/ocv/cv_capi_feature_match.h
@@ -0,0 +1,74 @@
+/*
+ * cv_capi_feature_match.h - optical flow feature match
+ *
+ *  Copyright (c) 2016-2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef CV_CAPI_FEATURE_MATCH_H
+#define CV_CAPI_FEATURE_MATCH_H
+
+#include <video_buffer.h>
+#include <interface/feature_match.h>
+#include "cv_utils.h"
+
+#ifdef ANDROID
+#include <cv.h>
+#else
+#include <opencv2/imgproc/imgproc_c.h>
+#include <opencv2/video/tracking_c.h>
+#endif
+
+namespace XCam {
+
+class CVCapiFeatureMatch
+    : public FeatureMatch
+{
+public:
+    explicit CVCapiFeatureMatch ();
+
+    virtual void feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf);
+
+private:
+    bool get_crop_image (
+        const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, std::vector<char> &crop_image, CvMat &img);
+
+    void detect_and_match (CvArr* img_left, CvArr* img_right);
+    void add_detected_data (CvArr* image, std::vector<CvPoint2D32f> &corners);
+
+    void calc_of_match (
+        CvArr* image0, CvArr* image1, std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
+        std::vector<char> &status, std::vector<float> &error);
+
+    void get_valid_offsets (
+        std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
+        std::vector<char> &status, std::vector<float> &error,
+        std::vector<float> &offsets, float &sum, int &count,
+        CvArr* out_image, CvSize &img0_size);
+
+private:
+    XCAM_DEAD_COPY (CVCapiFeatureMatch);
+
+    std::vector<char>    _left_crop_image;
+    std::vector<char>    _right_crop_image;
+};
+
+}
+
+#endif // CV_CAPI_FEATURE_MATCH_H
diff --git a/modules/ocl/cv_edgetaper.cpp b/modules/ocv/cv_edgetaper.cpp
similarity index 90%
rename from modules/ocl/cv_edgetaper.cpp
rename to modules/ocv/cv_edgetaper.cpp
index ab79238..524caa7 100644
--- a/modules/ocl/cv_edgetaper.cpp
+++ b/modules/ocv/cv_edgetaper.cpp
@@ -23,13 +23,6 @@
 
 namespace XCam {
 
-
-CVEdgetaper::CVEdgetaper ()
-    : CVBaseClass ()
-{
-
-}
-
 void
 CVEdgetaper::create_weights (const cv::Mat &image, const cv::Mat &psf, cv::Mat &coefficients)
 {
@@ -37,13 +30,13 @@
     cv::Mat rows_proj_border, cols_proj_border;
     cv::Mat rows_cor, cols_cor;
     // get psf rows and cols projections
-    cv::reduce (psf, rows_proj, 1, CV_REDUCE_SUM, -1);
-    cv::reduce (psf, cols_proj, 0, CV_REDUCE_SUM, -1);
+    cv::reduce (psf, rows_proj, 1, cv::REDUCE_SUM, -1);
+    cv::reduce (psf, cols_proj, 0, cv::REDUCE_SUM, -1);
     // calculate correlation for psf projections
     cv::copyMakeBorder (rows_proj, rows_proj_border, (psf.rows - 1) / 2, (psf.rows - 1) / 2, 0, 0, cv::BORDER_CONSTANT, cv::Scalar::all (0));
     cv::copyMakeBorder (cols_proj, cols_proj_border, 0, 0,  (psf.cols - 1) / 2, (psf.cols - 1) / 2, cv::BORDER_CONSTANT, cv::Scalar::all (0));
-    cv::matchTemplate (rows_proj_border, rows_proj, rows_cor, CV_TM_CCORR);
-    cv::matchTemplate (cols_proj_border, cols_proj, cols_cor, CV_TM_CCORR);
+    cv::matchTemplate (rows_proj_border, rows_proj, rows_cor, cv::TM_CCORR);
+    cv::matchTemplate (cols_proj_border, cols_proj, cols_cor, cv::TM_CCORR);
     // make it symmetric on both sides
     cv::Mat rows_add = cv::Mat_<float>(1, 1) << rows_proj.at<float> (0, 0);
     cv::Mat cols_add = cv::Mat_<float>(1, 1) << cols_proj.at<float> (0, 0);
diff --git a/modules/ocl/cv_edgetaper.h b/modules/ocv/cv_edgetaper.h
similarity index 85%
rename from modules/ocl/cv_edgetaper.h
rename to modules/ocv/cv_edgetaper.h
index 1ead29f..641c266 100644
--- a/modules/ocl/cv_edgetaper.h
+++ b/modules/ocv/cv_edgetaper.h
@@ -22,20 +22,14 @@
 #ifndef XCAM_CV_EDGETAPER_H
 #define XCAM_CV_EDGETAPER_H
 
-#include <xcam_std.h>
-#include <ocl/cv_base_class.h>
-
-#include <opencv2/opencv.hpp>
-#include <opencv2/core/ocl.hpp>
+#include "cv_std.h"
 
 namespace XCam {
 
-
-class CVEdgetaper : public CVBaseClass
+class CVEdgetaper
 {
-
 public:
-    explicit CVEdgetaper ();
+    explicit CVEdgetaper () {}
     void edgetaper (const cv::Mat &image, const cv::Mat &psf, cv::Mat &output);
 
 private:
diff --git a/modules/ocv/cv_feature_match.cpp b/modules/ocv/cv_feature_match.cpp
new file mode 100644
index 0000000..ea04c0e
--- /dev/null
+++ b/modules/ocv/cv_feature_match.cpp
@@ -0,0 +1,325 @@
+/*
+ * cv_feature_match.cpp - optical flow feature match
+ *
+ *  Copyright (c) 2016-2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "xcam_obj_debug.h"
+#include "image_file_handle.h"
+#include "cv_feature_match.h"
+#if HAVE_LIBCL
+#include <opencv2/core/ocl.hpp>
+#endif
+
+#define XCAM_CV_FM_DEBUG 0
+#define XCAM_CV_OF_DRAW_SCALE 2
+
+namespace XCam {
+CVFeatureMatch::CVFeatureMatch ()
+    : FeatureMatch ()
+    , _dst_width (0)
+    , _need_adjust (false)
+{
+    xcam_mem_clear (_cl_buf_mem);
+}
+
+CVFeatureMatch::~CVFeatureMatch ()
+{
+    xcam_mem_clear (_cl_buf_mem);
+}
+
+
+void
+CVFeatureMatch::set_dst_width (int width)
+{
+    _dst_width = width;
+}
+
+void
+CVFeatureMatch::enable_adjust_crop_area ()
+{
+    _need_adjust = true;
+}
+
+void
+CVFeatureMatch::set_cl_buf_mem (void *mem, BufId id)
+{
+#if HAVE_LIBCL
+    XCAM_ASSERT (mem);
+    _cl_buf_mem[id] = mem;
+#else
+    XCAM_LOG_DEBUG ("non-OpenCL mode, failed to set cl buffer memory");
+#endif
+}
+
+bool
+CVFeatureMatch::get_crop_image_umat (
+    const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, cv::UMat &img, BufId id)
+{
+#if HAVE_LIBCL
+    VideoBufferInfo info = buffer->get_video_info ();
+
+    cv::UMat umat;
+    cv::ocl::convertFromBuffer (_cl_buf_mem[id], info.strides[0], info.height, info.width, CV_8U, umat);
+    if (umat.empty ()) {
+        XCAM_LOG_ERROR ("FeatureMatch(idx:%d): convert bo buffer to UMat failed", _fm_idx);
+        return false;
+    }
+
+    img = umat (cv::Rect(crop_rect.pos_x, crop_rect.pos_y, crop_rect.width, crop_rect.height));
+
+    return true;
+#else
+    XCAM_LOG_ERROR ("FeatureMatch(idx:%d): non-OpenCL mode, failed to get umat", _fm_idx);
+    return false;
+#endif
+}
+
+void
+CVFeatureMatch::add_detected_data (
+    cv::Mat image, cv::Ptr<cv::Feature2D> detector, std::vector<cv::Point2f> &corners)
+{
+    std::vector<cv::KeyPoint> keypoints;
+    detector->detect (image, keypoints);
+    corners.reserve (corners.size () + keypoints.size ());
+    for (size_t i = 0; i < keypoints.size (); ++i) {
+        cv::KeyPoint &kp = keypoints[i];
+        corners.push_back (kp.pt);
+    }
+}
+
+void
+CVFeatureMatch::get_valid_offsets (
+    std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
+    std::vector<uchar> &status, std::vector<float> &error,
+    std::vector<float> &offsets, float &sum, int &count,
+    cv::Mat debug_img, cv::Size &img0_size)
+{
+    count = 0;
+    sum = 0.0f;
+    for (uint32_t i = 0; i < status.size (); ++i) {
+        if (!status[i])
+            continue;
+
+#if XCAM_CV_FM_DEBUG
+        cv::Point start = cv::Point(corner0[i]) * XCAM_CV_OF_DRAW_SCALE;
+        cv::circle (debug_img, start, 4, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE);
+#endif
+        if (error[i] > _config.max_track_error)
+            continue;
+        if (fabs(corner0[i].y - corner1[i].y) >= _config.max_valid_offset_y)
+            continue;
+        if (corner1[i].x < 0.0f || corner1[i].x > img0_size.width)
+            continue;
+
+        float offset = corner1[i].x - corner0[i].x;
+        sum += offset;
+        ++count;
+        offsets.push_back (offset);
+
+#if XCAM_CV_FM_DEBUG
+        cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::line (debug_img, start, end, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE);
+#else
+        XCAM_UNUSED (debug_img);
+        XCAM_UNUSED (img0_size);
+#endif
+    }
+}
+
+void
+CVFeatureMatch::calc_of_match (
+    cv::Mat image0, cv::Mat image1, std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
+    std::vector<uchar> &status, std::vector<float> &error)
+{
+    cv::Mat debug_img;
+    cv::Size img0_size = image0.size ();
+    cv::Size img1_size = image1.size ();
+    XCAM_ASSERT (img0_size.height == img1_size.height);
+
+#if XCAM_CV_FM_DEBUG
+    cv::Mat mat;
+    cv::Size size (img0_size.width + img1_size.width, img0_size.height);
+
+    mat.create (size, image0.type ());
+    debug_img = cv::Mat (mat);
+
+    image0.copyTo (mat (cv::Rect(0, 0, img0_size.width, img0_size.height)));
+    image1.copyTo (mat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height)));
+    mat.copyTo (debug_img);
+
+    cv::Size scale_size = size * XCAM_CV_OF_DRAW_SCALE;
+    cv::resize (debug_img, debug_img, scale_size, 0, 0);
+#endif
+
+    std::vector<float> offsets;
+    float offset_sum = 0.0f;
+    int count = 0;
+    float mean_offset = 0.0f;
+    float last_mean_offset = _mean_offset;
+    offsets.reserve (corner0.size ());
+    get_valid_offsets (corner0, corner1, status, error,
+                       offsets, offset_sum, count, debug_img, img0_size);
+#if XCAM_CV_FM_DEBUG
+    XCAM_LOG_INFO ("FeatureMatch(idx:%d): valid offsets:%d", _fm_idx, offsets.size ());
+    char file_name[256];
+    std::snprintf (file_name, 256, "fm_optical_flow_%d_%d.jpg", _frame_num, _fm_idx);
+    cv::imwrite (file_name, debug_img);
+#endif
+
+    bool ret = get_mean_offset (offsets, offset_sum, count, mean_offset);
+    if (ret) {
+        if (fabs (mean_offset - last_mean_offset) < _config.delta_mean_offset) {
+            _x_offset = _x_offset * _config.offset_factor + mean_offset * (1.0f - _config.offset_factor);
+
+            if (fabs (_x_offset) > _config.max_adjusted_offset)
+                _x_offset = (_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
+        }
+    }
+
+    _valid_count = count;
+    _mean_offset = mean_offset;
+}
+
+void
+CVFeatureMatch::adjust_crop_area ()
+{
+    if (fabs (_x_offset) < 5.0f)
+        return;
+
+    XCAM_ASSERT (_dst_width);
+
+    int last_overlap_width = _right_rect.pos_x + _right_rect.width +
+                              (_dst_width - (_left_rect.pos_x + _left_rect.width));
+    // int final_overlap_width = _right_rect.pos_x + _right_rect.width +
+    //                           (dst_width - (_left_rect.pos_x - x_offset + _left_rect.width));
+    if ((_left_rect.pos_x - _x_offset + _left_rect.width) > _dst_width)
+        _x_offset = _dst_width - (_left_rect.pos_x + _left_rect.width);
+    int final_overlap_width = last_overlap_width + _x_offset;
+    final_overlap_width = XCAM_ALIGN_AROUND (final_overlap_width, 8);
+    XCAM_ASSERT (final_overlap_width >= _config.sitch_min_width);
+    int center = final_overlap_width / 2;
+    XCAM_ASSERT (center >= _config.sitch_min_width / 2);
+
+    _right_rect.pos_x = XCAM_ALIGN_AROUND (center - _config.sitch_min_width / 2, 8);
+    _right_rect.width = _config.sitch_min_width;
+    _left_rect.pos_x = _dst_width - final_overlap_width + _right_rect.pos_x;
+    _left_rect.width = _config.sitch_min_width;
+
+    float delta_offset = final_overlap_width - last_overlap_width;
+    _x_offset -= delta_offset;
+}
+
+void
+CVFeatureMatch::detect_and_match (cv::Mat img_left, cv::Mat img_right)
+{
+    std::vector<float> err;
+    std::vector<uchar> status;
+    std::vector<cv::Point2f> corner_left, corner_right;
+    cv::Ptr<cv::Feature2D> fast_detector;
+    cv::Size win_size = cv::Size (5, 5);
+
+    fast_detector = cv::FastFeatureDetector::create (20, true);
+    add_detected_data (img_left, fast_detector, corner_left);
+
+    if (corner_left.empty ()) {
+        return;
+    }
+
+    cv::calcOpticalFlowPyrLK (
+        img_left, img_right, corner_left, corner_right, status, err, win_size, 3,
+        cv::TermCriteria (cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 10, 0.01f));
+
+    calc_of_match (img_left, img_right, corner_left, corner_right, status, err);
+
+    if (_need_adjust)
+        adjust_crop_area ();
+
+#if XCAM_CV_FM_DEBUG
+    XCAM_LOG_INFO ("FeatureMatch(idx:%d): x_offset:%0.2f", _fm_idx, _x_offset);
+    if (_need_adjust) {
+        XCAM_LOG_INFO (
+            "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)",
+            _fm_idx, _left_rect.pos_x, _left_rect.width, _right_rect.pos_x, _right_rect.width);
+    }
+#endif
+}
+
+void
+CVFeatureMatch::feature_match (
+    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf)
+{
+    XCAM_ASSERT (_left_rect.width && _left_rect.height);
+    XCAM_ASSERT (_right_rect.width && _right_rect.height);
+
+    cv::UMat left_umat, right_umat;
+    cv::Mat left_img, right_img;
+
+    if (_cl_buf_mem[BufIdLeft] && _cl_buf_mem[BufIdRight]) {
+        if (!get_crop_image_umat (left_buf, _left_rect, left_umat, BufIdLeft)
+                || !get_crop_image_umat (right_buf, _right_rect, right_umat, BufIdRight))
+            return;
+
+        left_img = left_umat.getMat (cv::ACCESS_READ);
+        right_img = right_umat.getMat (cv::ACCESS_READ);
+    } else {
+        if (!convert_range_to_mat (left_buf, _left_rect, left_img)
+                || !convert_range_to_mat (right_buf, _right_rect, right_img))
+            return;
+    }
+
+    detect_and_match (left_img, right_img);
+
+#if XCAM_CV_FM_DEBUG
+    debug_write_image (left_buf, right_buf, _left_rect, _right_rect, _frame_num, _fm_idx);
+    _frame_num++;
+#endif
+}
+
+void
+CVFeatureMatch::debug_write_image (
+    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
+    const Rect &left_rect, const Rect &right_rect, uint32_t frame_num, int fm_idx)
+{
+    XCAM_ASSERT (fm_idx >= 0);
+
+    char frame_str[64] = {'\0'};
+    std::snprintf (frame_str, 64, "frame:%d", frame_num);
+    char fm_idx_str[64] = {'\0'};
+    std::snprintf (fm_idx_str, 64, "fm_idx:%d", fm_idx);
+
+    char img_name[256] = {'\0'};
+    std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_0.jpg", frame_num, fm_idx);
+    write_image (left_buf, left_rect, img_name, frame_str, fm_idx_str);
+
+    std::snprintf (img_name, 256, "fm_in_stitch_area_%d_%d_1.jpg", frame_num, fm_idx);
+    write_image (right_buf, right_rect, img_name, frame_str, fm_idx_str);
+
+    XCAM_LOG_INFO ("FeatureMatch(idx:%d): frame number:%d done", fm_idx, frame_num);
+}
+
+SmartPtr<FeatureMatch>
+FeatureMatch::create_default_feature_match ()
+{
+    SmartPtr<CVFeatureMatch> matcher = new CVFeatureMatch ();
+    XCAM_ASSERT (matcher.ptr ());
+
+    return matcher;
+}
+
+}
diff --git a/modules/ocv/cv_feature_match.h b/modules/ocv/cv_feature_match.h
new file mode 100644
index 0000000..5d2fbc7
--- /dev/null
+++ b/modules/ocv/cv_feature_match.h
@@ -0,0 +1,88 @@
+/*
+ * cv_feature_match.h - optical flow feature match
+ *
+ *  Copyright (c) 2016-2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_CV_FEATURE_MATCH_H
+#define XCAM_CV_FEATURE_MATCH_H
+
+#include <video_buffer.h>
+#include <interface/feature_match.h>
+#include "cv_utils.h"
+
+namespace XCam {
+
+class CVFeatureMatch
+    : public FeatureMatch
+{
+public:
+    enum BufId {
+        BufIdLeft    = 0,
+        BufIdRight,
+        BufIdMax
+    };
+
+public:
+    explicit CVFeatureMatch ();
+    virtual ~CVFeatureMatch ();
+
+    virtual void feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf);
+
+    void set_cl_buf_mem (void *mem, BufId id);
+
+protected:
+    bool get_crop_image_umat (const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect, cv::UMat &img, BufId id);
+    void add_detected_data (cv::Mat image, cv::Ptr<cv::Feature2D> detector, std::vector<cv::Point2f> &corners);
+
+    void debug_write_image (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
+        const Rect &left_rect, const Rect &right_rect, uint32_t frame_num, int fm_idx);
+
+private:
+    virtual void detect_and_match (cv::Mat img_left, cv::Mat img_right);
+    virtual void calc_of_match (
+        cv::Mat image0, cv::Mat image1, std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
+        std::vector<uchar> &status, std::vector<float> &error);
+
+    void get_valid_offsets (
+        std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
+        std::vector<uchar> &status, std::vector<float> &error,
+        std::vector<float> &offsets, float &sum, int &count,
+        cv::Mat debug_img, cv::Size &img0_size);
+
+    void adjust_crop_area ();
+
+    virtual void set_dst_width (int width);
+    virtual void enable_adjust_crop_area ();
+
+private:
+    XCAM_DEAD_COPY (CVFeatureMatch);
+
+protected:
+    void       *_cl_buf_mem[BufIdMax];
+
+private:
+    int         _dst_width;
+    bool        _need_adjust;
+};
+
+}
+
+#endif // XCAM_CV_FEATURE_MATCH_H
diff --git a/modules/ocv/cv_feature_match_cluster.cpp b/modules/ocv/cv_feature_match_cluster.cpp
new file mode 100644
index 0000000..6bc0415
--- /dev/null
+++ b/modules/ocv/cv_feature_match_cluster.cpp
@@ -0,0 +1,316 @@
+/*
+ * cv_feature_match_cluster.cpp - optical flow feature match selected by clustering
+ *
+ *  Copyright (c) 2016-2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wu Junkai <junkai.wu@intel.com>
+ */
+
+#include "xcam_obj_debug.h"
+#include "image_file_handle.h"
+#include "cv_feature_match_cluster.h"
+
+#define XCAM_CV_FM_DEBUG 0
+#define XCAM_CV_OF_DRAW_SCALE 2
+
+namespace XCam {
+CVFeatureMatchCluster::CVFeatureMatchCluster ()
+    : CVFeatureMatch ()
+{
+}
+
+bool
+CVFeatureMatchCluster::calc_mean_offset (
+    std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
+    std::vector<uchar> &status, std::vector<float> &error,
+    float &mean_offset_x, float &mean_offset_y,
+    cv::Mat debug_img, cv::Size &img0_size, cv::Size &img1_size)
+{
+    std::vector<std::vector<uint32_t>> clusters;
+    std::vector<std::vector<cv::Point2f>> clusters_offsets;
+    std::vector<uint32_t> valid_seeds (status.size ());
+    std::vector<uint32_t> valid_corners (status.size ());
+
+    for (uint32_t i = 0; i < status.size (); ++i) {
+        if (!status[i] || (error[i] > _config.max_track_error) || corner1[i].x < 0.0f || corner1[i].x > img0_size.width) {
+            valid_corners[i] = 0;
+            valid_seeds[i] = 0;
+        } else {
+            valid_corners[i] = 1;
+            valid_seeds[i] = 1;
+        }
+    }
+
+    float seed_x_offset = 0.0f;
+    float seed_y_offset = 0.0f;
+
+    std::vector<uint32_t> cluster (1);
+    std::vector<cv::Point2f> cluster_offset (1);
+
+    float thres = 8.0f;
+    while (cluster.size() > 0) {
+        cluster.clear ();
+        cluster_offset.clear ();
+
+        for (uint32_t i = 0; i < status.size (); ++i) {
+            if (valid_seeds[i]) {
+                seed_x_offset = corner1[i].x - corner0[i].x;
+                seed_y_offset = corner1[i].y - corner0[i].y;
+                cluster.push_back (i);
+                cluster_offset.push_back (cv::Point2f(seed_x_offset, seed_y_offset));
+                valid_corners[i] = 0;
+                valid_seeds[i] = 0;
+                break;
+            }
+        }
+
+        if (cluster.size() > 0) {
+            for (uint32_t i = 0; i < status.size (); ++i) {
+                if (!valid_corners[i])
+                    continue;
+
+                float x_offset = corner1[i].x - corner0[i].x;
+                float y_offset = corner1[i].y - corner0[i].y;
+
+                if (fabs (x_offset - seed_x_offset) > thres || fabs (y_offset - seed_y_offset) > thres / 2.0f)
+                    continue;
+
+                cluster.push_back (i);
+                cluster_offset.push_back (cv::Point2f(x_offset, y_offset));
+                valid_seeds[i] = 0;
+            }
+
+            clusters.push_back (cluster);
+            clusters_offsets.push_back (cluster_offset);
+        }
+    }
+
+    if (clusters_offsets.size () == 0)
+        return false;
+
+    uint32_t max_size = 0;
+    uint32_t max_index = 0;
+
+    for (uint32_t i = 0; i < clusters.size (); ++i) {
+        if (clusters[i].size () > max_size) {
+            max_size = clusters[i].size ();
+            max_index = i;
+        }
+    }
+
+    if (clusters_offsets[max_index].size () < (uint32_t)_config.min_corners)
+        return false;
+
+    float sum_x = 0.0f;
+    float sum_y = 0.0f;
+    for (uint32_t i = 0; i < clusters_offsets[max_index].size (); ++i) {
+        sum_x += clusters_offsets[max_index][i].x;
+        sum_y += clusters_offsets[max_index][i].y;
+    }
+
+    mean_offset_x = sum_x / clusters_offsets[max_index].size ();
+    mean_offset_y = sum_y / clusters_offsets[max_index].size ();
+
+#if XCAM_CV_FM_DEBUG
+    for (uint32_t i = 0; i < status.size (); ++i) {
+        if(!status[i])
+            continue;
+
+        cv::Point start = cv::Point(corner0[i]) * XCAM_CV_OF_DRAW_SCALE;
+        cv::circle (debug_img, start, 4, cv::Scalar(0), XCAM_CV_OF_DRAW_SCALE);
+        cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::line (debug_img, start, end, cv::Scalar(0), XCAM_CV_OF_DRAW_SCALE);
+    }
+
+    for (uint32_t i = 0; i < status.size (); ++i) {
+        if (!status[i])
+            continue;
+
+        cv::Point start = cv::Point(corner0[i]) * XCAM_CV_OF_DRAW_SCALE;
+        cv::circle (debug_img, start, 4, cv::Scalar(0), XCAM_CV_OF_DRAW_SCALE);
+        if (error[i] > _config.max_track_error)
+            continue;
+        if (fabs(corner0[i].y - corner1[i].y) >= _config.max_valid_offset_y)
+            continue;
+        if (corner1[i].x < 0.0f || corner1[i].x > img0_size.width)
+            continue;
+
+        cv::Point end = (cv::Point(corner1[i]) + cv::Point (img0_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::line (debug_img, start, end, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE);
+    }
+
+    for (uint32_t i = 0; i < status.size (); ++i) {
+        if(!status[i])
+            continue;
+
+        cv::Point start = (cv::Point(corner0[i]) + cv::Point (img0_size.width + img1_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::circle (debug_img, start, 4, cv::Scalar(0), XCAM_CV_OF_DRAW_SCALE);
+        cv::Point end = (cv::Point(corner1[i]) + cv::Point (2 * img0_size.width + img1_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::line (debug_img, start, end, cv::Scalar(0), XCAM_CV_OF_DRAW_SCALE);
+    }
+
+    if (clusters.size () != 0)
+        cluster = clusters[max_index];
+    for (uint32_t i = 0; i < cluster.size (); ++i) {
+        cv::Point start = (cv::Point(corner0[cluster[i]]) + cv::Point(img0_size.width + img1_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::circle (debug_img, start, 4, cv::Scalar(0), XCAM_CV_OF_DRAW_SCALE);
+        cv::Point end = (cv::Point(corner1[cluster[i]]) + cv::Point (2 * img0_size.width + img1_size.width, 0)) * XCAM_CV_OF_DRAW_SCALE;
+        cv::line (debug_img, start, end, cv::Scalar(255), XCAM_CV_OF_DRAW_SCALE);
+    }
+
+#endif
+
+    XCAM_UNUSED (debug_img);
+    XCAM_UNUSED (img0_size);
+    XCAM_UNUSED (img1_size);
+
+    clusters.clear ();
+    clusters_offsets.clear ();
+
+    return true;
+}
+
+void
+CVFeatureMatchCluster::calc_of_match (
+    cv::Mat image0, cv::Mat image1, std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1,
+    std::vector<uchar> &status, std::vector<float> &error)
+{
+    cv::Mat debug_img;
+    cv::Size img0_size = image0.size ();
+    cv::Size img1_size = image1.size ();
+    XCAM_ASSERT (img0_size.height == img1_size.height);
+
+#if XCAM_CV_FM_DEBUG
+    cv::Mat mat;
+    cv::Size size ((img0_size.width + img1_size.width) * 2, img0_size.height);
+
+    mat.create (size, image0.type ());
+    debug_img = cv::Mat (mat);
+
+    image0.copyTo (mat (cv::Rect(0, 0, img0_size.width, img0_size.height)));
+    image1.copyTo (mat (cv::Rect(img0_size.width, 0, img1_size.width, img1_size.height)));
+    image0.copyTo (mat (cv::Rect(img0_size.width + img1_size.width, 0, img0_size.width, img0_size.height)));
+    image1.copyTo (mat (cv::Rect(2 * img0_size.width + img1_size.width, 0, img1_size.width, img1_size.height)));
+
+    mat.copyTo (debug_img);
+
+    cv::Size scale_size = size * XCAM_CV_OF_DRAW_SCALE;
+    cv::resize (debug_img, debug_img, scale_size, 0, 0);
+#endif
+
+    float mean_offset_x = 0.0f;
+    float mean_offset_y = 0.0f;
+    float last_mean_offset_x = _mean_offset;
+    float last_mean_offset_y = _mean_offset_y;
+    bool ret = calc_mean_offset (corner0, corner1, status, error, mean_offset_x, mean_offset_y,
+                                 debug_img, img0_size, img1_size);
+
+#if XCAM_CV_FM_DEBUG
+    char file_name[256];
+    std::snprintf (file_name, 256, "fm_optical_flow_%d_%d.jpg", _frame_num, _fm_idx);
+    cv::imwrite (file_name, debug_img);
+#endif
+
+    if (ret) {
+        if (fabs (mean_offset_x - last_mean_offset_x) < _config.delta_mean_offset) {
+            _x_offset = _x_offset * _config.offset_factor + mean_offset_x * (1.0f - _config.offset_factor);
+
+            if (fabs (_x_offset) > _config.max_adjusted_offset)
+                _x_offset = (_x_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
+        }
+
+        if (fabs (mean_offset_y - last_mean_offset_y) < _config.delta_mean_offset) {
+            _y_offset = _y_offset * _config.offset_factor + mean_offset_y * (1.0f - _config.offset_factor);
+
+            if (fabs (_y_offset) > _config.max_adjusted_offset)
+                _y_offset = (_y_offset > 0.0f) ? _config.max_adjusted_offset : (-_config.max_adjusted_offset);
+        }
+    }
+
+    _mean_offset = mean_offset_x;
+    _mean_offset_y = mean_offset_y;
+}
+
+void
+CVFeatureMatchCluster::detect_and_match (cv::Mat img_left, cv::Mat img_right)
+{
+    std::vector<float> err;
+    std::vector<uchar> status;
+    std::vector<cv::Point2f> corner_left, corner_right;
+    cv::Ptr<cv::Feature2D> fast_detector;
+    cv::Size win_size = cv::Size (21, 21);
+
+    fast_detector = cv::FastFeatureDetector::create (20, true);
+    add_detected_data (img_left, fast_detector, corner_left);
+
+    if (corner_left.empty ()) {
+        return;
+    }
+
+    cv::calcOpticalFlowPyrLK (
+        img_left, img_right, corner_left, corner_right, status, err, win_size, 3,
+        cv::TermCriteria (cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 30, 0.01f));
+
+    calc_of_match (img_left, img_right, corner_left, corner_right, status, err);
+
+#if XCAM_CV_FM_DEBUG
+    XCAM_LOG_INFO ("x_offset:%0.2f", _x_offset);
+    XCAM_LOG_INFO (
+        "FeatureMatch(idx:%d): stiching area: left_area(pos_x:%d, width:%d), right_area(pos_x:%d, width:%d)",
+        _fm_idx, _left_rect.pos_x, _left_rect.width, _right_rect.pos_x, _right_rect.width);
+#endif
+}
+
+void
+CVFeatureMatchCluster::feature_match (
+    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf)
+{
+    XCAM_ASSERT (_left_rect.width && _left_rect.height);
+    XCAM_ASSERT (_right_rect.width && _right_rect.height);
+
+    cv::UMat left_umat, right_umat;
+    cv::Mat left_img, right_img;
+
+    if (_cl_buf_mem[BufIdLeft] && _cl_buf_mem[BufIdRight]) {
+        if (!get_crop_image_umat (left_buf, _left_rect, left_umat, BufIdLeft)
+                || !get_crop_image_umat (right_buf, _right_rect, right_umat, BufIdRight))
+            return;
+
+        left_img = left_umat.getMat (cv::ACCESS_READ);
+        right_img = right_umat.getMat (cv::ACCESS_READ);
+    } else {
+        if (!convert_range_to_mat (left_buf, _left_rect, left_img)
+                || !convert_range_to_mat (right_buf, _right_rect, right_img))
+            return;
+    }
+
+    detect_and_match (left_img, right_img);
+
+#if XCAM_CV_FM_DEBUG
+    debug_write_image (left_buf, right_buf, _left_rect, _right_rect, _frame_num, _fm_idx);
+    _frame_num++;
+#endif
+}
+
+SmartPtr<FeatureMatch>
+FeatureMatch::create_cluster_feature_match ()
+{
+    SmartPtr<CVFeatureMatchCluster> matcher = new CVFeatureMatchCluster ();
+    XCAM_ASSERT (matcher.ptr ());
+
+    return matcher;
+}
+
+}
diff --git a/modules/ocv/cv_feature_match_cluster.h b/modules/ocv/cv_feature_match_cluster.h
new file mode 100644
index 0000000..1b1fcdb
--- /dev/null
+++ b/modules/ocv/cv_feature_match_cluster.h
@@ -0,0 +1,55 @@
+/*
+ * cv_feature_match_cluster.h - optical flow feature match selected by clustering
+ *
+ *  Copyright (c) 2016-2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wu Junkai <junkai.Wu@intel.com>
+ */
+
+#ifndef XCAM_CV_FEATURE_MATCH_CLUSTER_H
+#define XCAM_CV_FEATURE_MATCH_CLUSTER_H
+
+#include "cv_feature_match.h"
+
+namespace XCam {
+
+class CVFeatureMatchCluster
+    : public CVFeatureMatch
+{
+public:
+    explicit CVFeatureMatchCluster ();
+
+    virtual void feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf);
+
+private:
+    virtual void detect_and_match (cv::Mat img_left, cv::Mat img_right);
+    virtual void calc_of_match (
+        cv::Mat image0, cv::Mat image1, std::vector<cv::Point2f> &corner0,
+        std::vector<cv::Point2f> &corner1, std::vector<uchar> &status, std::vector<float> &error);
+
+    bool calc_mean_offset (
+        std::vector<cv::Point2f> &corner0, std::vector<cv::Point2f> &corner1, std::vector<uchar> &status,
+        std::vector<float> &error, float &mean_offset_x, float &mean_offset_y,
+        cv::Mat debug_img, cv::Size &img0_size, cv::Size &img1_size);
+
+private:
+    XCAM_DEAD_COPY (CVFeatureMatchCluster);
+
+};
+
+}
+
+#endif // XCAM_CV_FEATURE_MATCH_CLUSTER_H
diff --git a/modules/ocl/cv_image_deblurring.cpp b/modules/ocv/cv_image_deblurring.cpp
similarity index 97%
rename from modules/ocl/cv_image_deblurring.cpp
rename to modules/ocv/cv_image_deblurring.cpp
index 730eb42..4c4dbf0 100644
--- a/modules/ocl/cv_image_deblurring.cpp
+++ b/modules/ocv/cv_image_deblurring.cpp
@@ -23,9 +23,7 @@
 
 namespace XCam {
 
-
 CVImageDeblurring::CVImageDeblurring ()
-    : CVBaseClass ()
 {
     _helper = new CVImageProcessHelper ();
     _sharp = new CVImageSharp ();
@@ -155,7 +153,7 @@
 CVImageDeblurring::blind_deblurring (const cv::Mat &blurred, cv::Mat &deblurred, cv::Mat &kernel, int kernel_size, float noise_power, bool use_edgetaper)
 {
     cv::Mat gray_blurred;
-    cv::cvtColor (blurred, gray_blurred, CV_BGR2GRAY);
+    cv::cvtColor (blurred, gray_blurred, cv::COLOR_BGR2GRAY);
     if (noise_power < 0)
     {
         cv::Mat median_blurred;
@@ -196,7 +194,7 @@
     }
     cv::merge (deblurred_rgb, result_deblurred);
     result_deblurred.convertTo (result_deblurred, CV_8UC3);
-    fastNlMeansDenoisingColored (result_deblurred, deblurred, 3, 3, 7, 21);
+    cv::fastNlMeansDenoisingColored (result_deblurred, deblurred, 3, 3, 7, 21);
     kernel = result_kernel.clone ();
 }
 
diff --git a/modules/ocl/cv_image_deblurring.h b/modules/ocv/cv_image_deblurring.h
similarity index 88%
rename from modules/ocl/cv_image_deblurring.h
rename to modules/ocv/cv_image_deblurring.h
index afac22c..cd28786 100644
--- a/modules/ocl/cv_image_deblurring.h
+++ b/modules/ocv/cv_image_deblurring.h
@@ -22,13 +22,12 @@
 #ifndef XCAM_CV_FEATURE_DEBLURRING_H
 #define XCAM_CV_FEATURE_DEBLURRING_H
 
-#include <xcam_std.h>
 #include <video_buffer.h>
-#include <ocl/cv_base_class.h>
-#include <ocl/cv_image_process_helper.h>
-#include <ocl/cv_image_sharp.h>
-#include <ocl/cv_edgetaper.h>
-#include <ocl/cv_wiener_filter.h>
+#include "cv_std.h"
+#include "cv_image_process_helper.h"
+#include "cv_image_sharp.h"
+#include "cv_edgetaper.h"
+#include "cv_wiener_filter.h"
 
 namespace XCam {
 
@@ -41,9 +40,8 @@
     }
 };
 
-class CVImageDeblurring : public CVBaseClass
+class CVImageDeblurring
 {
-
 public:
     explicit CVImageDeblurring ();
     void set_config (CVIDConfig config);
diff --git a/modules/ocl/cv_image_process_helper.cpp b/modules/ocv/cv_image_process_helper.cpp
similarity index 97%
rename from modules/ocl/cv_image_process_helper.cpp
rename to modules/ocv/cv_image_process_helper.cpp
index 0d08289..33377a9 100644
--- a/modules/ocl/cv_image_process_helper.cpp
+++ b/modules/ocv/cv_image_process_helper.cpp
@@ -23,13 +23,6 @@
 
 namespace XCam {
 
-
-CVImageProcessHelper::CVImageProcessHelper ()
-    : CVBaseClass ()
-{
-
-}
-
 cv::Mat
 CVImageProcessHelper::erosion (const cv::Mat &image, int erosion_size, int erosion_type)
 {
diff --git a/modules/ocl/cv_image_process_helper.h b/modules/ocv/cv_image_process_helper.h
similarity index 91%
rename from modules/ocl/cv_image_process_helper.h
rename to modules/ocv/cv_image_process_helper.h
index 137ff6b..cb1cf8a 100644
--- a/modules/ocl/cv_image_process_helper.h
+++ b/modules/ocv/cv_image_process_helper.h
@@ -22,18 +22,15 @@
 #ifndef XCAM_CV_IMAGE_PROCESS_HELPER_H
 #define XCAM_CV_IMAGE_PROCESS_HELPER_H
 
-#include <xcam_std.h>
 #include <video_buffer.h>
-#include <ocl/cv_base_class.h>
+#include "cv_std.h"
 
 namespace XCam {
 
-
-class CVImageProcessHelper : public CVBaseClass
+class CVImageProcessHelper
 {
-
 public:
-    explicit CVImageProcessHelper ();
+    explicit CVImageProcessHelper () {}
 
     void compute_dft (const cv::Mat &image, cv::Mat &result);
     void compute_idft (cv::Mat *input, cv::Mat &result);
diff --git a/modules/ocl/cv_image_sharp.cpp b/modules/ocv/cv_image_sharp.cpp
similarity index 96%
rename from modules/ocl/cv_image_sharp.cpp
rename to modules/ocv/cv_image_sharp.cpp
index 0a309af..2bf0076 100644
--- a/modules/ocl/cv_image_sharp.cpp
+++ b/modules/ocv/cv_image_sharp.cpp
@@ -23,13 +23,6 @@
 
 namespace XCam {
 
-
-CVImageSharp::CVImageSharp ()
-    : CVBaseClass ()
-{
-
-}
-
 cv::Mat
 CVImageSharp::sharp_image_gray (const cv::Mat &image, float sigmar)
 {
diff --git a/modules/ocl/cv_image_sharp.h b/modules/ocv/cv_image_sharp.h
similarity index 89%
rename from modules/ocl/cv_image_sharp.h
rename to modules/ocv/cv_image_sharp.h
index 74e0ce4..7a68e23 100644
--- a/modules/ocl/cv_image_sharp.h
+++ b/modules/ocv/cv_image_sharp.h
@@ -22,17 +22,15 @@
 #ifndef XCAM_CV_IMAGE_SHARP_H
 #define XCAM_CV_IMAGE_SHARP_H
 
-#include <xcam_std.h>
 #include <video_buffer.h>
-#include <ocl/cv_base_class.h>
+#include "cv_std.h"
 
 namespace XCam {
 
-class CVImageSharp : public CVBaseClass
+class CVImageSharp
 {
-
 public:
-    explicit CVImageSharp ();
+    explicit CVImageSharp () {}
 
     float measure_sharp (const cv::Mat &image);
     cv::Mat sharp_image_gray (const cv::Mat &image, float sigmar);
diff --git a/modules/ocv/cv_std.h b/modules/ocv/cv_std.h
new file mode 100644
index 0000000..eba4861
--- /dev/null
+++ b/modules/ocv/cv_std.h
@@ -0,0 +1,27 @@
+/*
+ * cv_std.h - OpenCV std
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_CV_STD_H
+#define XCAM_CV_STD_H
+
+#include <xcam_std.h>
+#include <opencv2/opencv.hpp>
+
+#endif // XCAM_CV_STD_H
diff --git a/modules/ocv/cv_utils.cpp b/modules/ocv/cv_utils.cpp
new file mode 100644
index 0000000..ab70679
--- /dev/null
+++ b/modules/ocv/cv_utils.cpp
@@ -0,0 +1,97 @@
+/*
+ * cv_utils.cpp - OpenCV Utilities
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "cv_utils.h"
+
+const static cv::Scalar color = cv::Scalar (0, 0, 255);
+const static int fontFace = cv::FONT_HERSHEY_COMPLEX;
+
+namespace XCam {
+
+bool convert_to_mat (const SmartPtr<VideoBuffer> &buffer, cv::Mat &img)
+{
+    VideoBufferInfo info = buffer->get_video_info ();
+    XCAM_FAIL_RETURN (ERROR, info.format == V4L2_PIX_FMT_NV12, false, "convert_to_mat only support NV12 format");
+
+    uint8_t *mem = buffer->map ();
+    XCAM_FAIL_RETURN (ERROR, mem, false, "convert_to_mat buffer map failed");
+
+    cv::Mat mat = cv::Mat (info.aligned_height * 3 / 2, info.width, CV_8UC1, mem, info.strides[0]);
+    cv::cvtColor (mat, img, cv::COLOR_YUV2BGR_NV12);
+    buffer->unmap ();
+
+    return true;
+}
+
+bool convert_range_to_mat (const SmartPtr<VideoBuffer> &buffer, const Rect &range, cv::Mat &img)
+{
+    VideoBufferInfo info = buffer->get_video_info ();
+
+    uint8_t *mem = buffer->map ();
+    XCAM_FAIL_RETURN (ERROR, mem, false, "convert_range_to_mat buffer map failed");
+
+    uint8_t *start = mem + range.pos_y * info.strides[0] + range.pos_x;
+    img = cv::Mat (range.height, range.width, CV_8UC1, start, info.strides[0]);
+    // buffer->unmap ();
+
+    return true;
+}
+
+void write_image (
+    const SmartPtr<VideoBuffer> &buf, const char *img_name, const char *frame_str, const char *idx_str)
+{
+    XCAM_ASSERT (img_name);
+
+    cv::Mat mat;
+    convert_to_mat (buf, mat);
+
+    if(frame_str)
+        cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false);
+    if(idx_str)
+        cv::putText (mat, idx_str, cv::Point(20, 110), fontFace, 2.0, color, 2, 8, false);
+
+    cv::imwrite (img_name, mat);
+}
+
+void write_image (
+    const SmartPtr<VideoBuffer> &buf, const Rect &draw_rect,
+    const char *img_name, const char *frame_str, const char *idx_str)
+{
+    XCAM_ASSERT (img_name && frame_str && idx_str);
+
+    cv::Mat mat;
+    convert_to_mat (buf, mat);
+
+    const Rect &rect = draw_rect;
+    cv::putText (mat, frame_str, cv::Point(rect.pos_x, 30), fontFace, 0.8f, color, 2, 8, false);
+    cv::putText (mat, idx_str, cv::Point(rect.pos_x, 70), fontFace, 0.8f, color, 2, 8, false);
+
+    cv::line (mat, cv::Point(rect.pos_x, rect.pos_y), cv::Point(rect.pos_x + rect.width, rect.pos_y), color, 1);
+    cv::line (mat, cv::Point(rect.pos_x, rect.pos_y + rect.height),
+              cv::Point(rect.pos_x + rect.width, rect.pos_y + rect.height), color, 1);
+
+    VideoBufferInfo info = buf->get_video_info ();
+    cv::line (mat, cv::Point(rect.pos_x, 0), cv::Point(rect.pos_x, info.height), color, 2);
+    cv::line (mat, cv::Point(rect.pos_x + rect.width, 0), cv::Point(rect.pos_x + rect.width, info.height), color, 2);
+
+    cv::imwrite (img_name, mat);
+}
+
+}
diff --git a/modules/ocv/cv_utils.h b/modules/ocv/cv_utils.h
new file mode 100644
index 0000000..8b36b90
--- /dev/null
+++ b/modules/ocv/cv_utils.h
@@ -0,0 +1,41 @@
+/*
+ * cv_utils.h - OpenCV Utilities
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_CV_UTILS_H
+#define XCAM_CV_UTILS_H
+
+#include <interface/data_types.h>
+#include <video_buffer.h>
+#include "cv_std.h"
+
+namespace XCam {
+
+    bool convert_to_mat (const SmartPtr<VideoBuffer> &buffer, cv::Mat &img);
+    bool convert_range_to_mat (const SmartPtr<VideoBuffer> &buffer, const Rect &range, cv::Mat &img);
+
+    void write_image (
+        const SmartPtr<VideoBuffer> &buf, const char *img_name, const char *frame_str, const char *idx_str);
+    void write_image (
+        const SmartPtr<VideoBuffer> &buf, const Rect &draw_rect,
+        const char *img_name, const char *frame_str, const char *idx_str);
+
+}
+
+#endif // XCAM_CV_UTILS_H
diff --git a/modules/ocl/cv_wiener_filter.cpp b/modules/ocv/cv_wiener_filter.cpp
similarity index 98%
rename from modules/ocl/cv_wiener_filter.cpp
rename to modules/ocv/cv_wiener_filter.cpp
index ff96e5c..cf33649 100644
--- a/modules/ocl/cv_wiener_filter.cpp
+++ b/modules/ocv/cv_wiener_filter.cpp
@@ -23,9 +23,7 @@
 
 namespace XCam {
 
-
 CVWienerFilter::CVWienerFilter ()
-    : CVBaseClass ()
 {
     _helpers = new CVImageProcessHelper ();
 }
diff --git a/modules/ocl/cv_wiener_filter.h b/modules/ocv/cv_wiener_filter.h
similarity index 89%
rename from modules/ocl/cv_wiener_filter.h
rename to modules/ocv/cv_wiener_filter.h
index fa70812..3720c35 100644
--- a/modules/ocl/cv_wiener_filter.h
+++ b/modules/ocv/cv_wiener_filter.h
@@ -22,16 +22,14 @@
 #ifndef XCAM_CV_WIENER_FILTER_H
 #define XCAM_CV_WIENER_FILTER_H
 
-#include <xcam_std.h>
 #include <video_buffer.h>
-#include <ocl/cv_base_class.h>
-#include <ocl/cv_image_process_helper.h>
+#include "cv_std.h"
+#include "cv_image_process_helper.h"
 
 namespace XCam {
 
-class CVWienerFilter : public CVBaseClass
+class CVWienerFilter
 {
-
 public:
     explicit CVWienerFilter ();
 
diff --git a/modules/render/Makefile.am b/modules/render/Makefile.am
new file mode 100644
index 0000000..2870eaf
--- /dev/null
+++ b/modules/render/Makefile.am
@@ -0,0 +1,52 @@
+lib_LTLIBRARIES = libxcam_render.la
+
+XCAM_RENDER_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)        \
+    $(LIBOSG_CFLAGS)        \
+    -I$(top_srcdir)/xcore   \
+    -I$(top_srcdir)/modules \
+    $(NULL)
+
+XCAM_RENDER_LIBS = \
+    -losgGA        \
+    -losgDB        \
+    -losgUtil      \
+    -losgFX        \
+    -losgText      \
+    -losgViewer    \
+    -losg          \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
+
+xcam_render_sources = \
+    render_osg_camera_manipulator.cpp \
+    render_osg_model.cpp              \
+    render_osg_viewer.cpp             \
+    $(NULL)
+
+libxcam_render_la_SOURCES = \
+    $(xcam_render_sources) \
+    $(NULL)
+
+libxcam_render_la_CXXFLAGS = \
+    $(XCAM_RENDER_CXXFLAGS) \
+    $(NULL)
+
+libxcam_render_la_LIBADD = \
+    $(XCAM_RENDER_LIBS) \
+    $(NULL)
+
+libxcam_render_la_LDFLAGS = \
+    $(XCAM_LT_LDFLAGS) \
+    $(NULL)
+
+libxcam_renderincludedir = $(includedir)/xcam/render
+
+nobase_libxcam_renderinclude_HEADERS = \
+    render_osg_camera_manipulator.h \
+    render_osg_model.h              \
+    render_osg_viewer.h             \
+    render_osg_shader.h             \
+    $(NULL)
+
+libxcam_render_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/render/render_osg_camera_manipulator.cpp b/modules/render/render_osg_camera_manipulator.cpp
new file mode 100644
index 0000000..ec59fb9
--- /dev/null
+++ b/modules/render/render_osg_camera_manipulator.cpp
@@ -0,0 +1,172 @@
+/*
+ * render_osg_camera_manipulator.cpp - supports 3D interactive manipulators
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "render_osg_camera_manipulator.h"
+
+namespace XCam {
+
+RenderOsgCameraManipulator::RenderOsgCameraManipulator ()
+    : osgGA::StandardManipulator::StandardManipulator ()
+    , mAngle (osg::PI)
+    , mLookAtOffset (0.0f)
+    , mMaxLookAtOffset (osg::PI_4)
+    , mLength (4.0f)
+    , mWidth (3.0f)
+    , mHeight (1.6f)
+    , mMaxHeight (4.0f)
+    , mMinHeight (0.6)
+    , mEyePosScale (1.0f)
+    , mUp (osg::Vec3d(0.0f, 0.0f, 1.0f))
+{
+    setAllowThrow (false);
+    setAutoComputeHomePosition (false);
+}
+
+RenderOsgCameraManipulator::~RenderOsgCameraManipulator ()
+{
+}
+
+osg::Matrixd
+RenderOsgCameraManipulator::getInverseMatrix () const
+{
+    osg::Vec3d eyePos;
+    getEyePosition (eyePos);
+    osg::Vec3d lookAtPos;
+    getLookAtPosition (lookAtPos);
+    return osg::Matrixd::lookAt (eyePos, lookAtPos, mUp);
+}
+
+osg::Matrixd
+RenderOsgCameraManipulator::getMatrix () const
+{
+    osg::Matrixd matrix = getInverseMatrix ();
+    return osg::Matrixd::inverse (matrix);
+}
+
+void
+RenderOsgCameraManipulator::home (double /*currentTime*/)
+{
+    mAngle = osg::PI;
+    mLookAtOffset = 0.0f;
+    mEyePosScale = 1.0f;
+}
+
+void
+RenderOsgCameraManipulator::rotate (float deltaAngle)
+{
+    if (deltaAngle > 0.) {
+        if (mLookAtOffset < mMaxLookAtOffset) {
+            mLookAtOffset = std::min (mLookAtOffset + deltaAngle, mMaxLookAtOffset);
+        } else {
+            mAngle += deltaAngle;
+        }
+    } else {
+        if (mLookAtOffset > -mMaxLookAtOffset) {
+            mLookAtOffset = std::max (mLookAtOffset + deltaAngle, -mMaxLookAtOffset);
+        } else {
+            mAngle += deltaAngle;
+        }
+    }
+    if (mAngle > 2 * osg::PI) {
+        mAngle -= 2 * osg::PI;
+    } else if (mAngle < 0.0f) {
+        mAngle += 2 * osg::PI;
+    }
+}
+
+void
+RenderOsgCameraManipulator::modifyHeight (float delta)
+{
+    if (delta > 0.0) {
+        mHeight = std::min (mHeight + delta, mMaxHeight);
+    } else {
+        mHeight = std::max (mHeight + delta, mMinHeight);
+    }
+}
+
+void
+RenderOsgCameraManipulator::getEyePosition (osg::Vec3d &eyePos) const
+{
+    float indentFactor = 1.0f - (0.1f * ((mHeight - mMinHeight) / (mMaxHeight - mMinHeight)));
+    eyePos[0] = cos (mAngle) * mLength * indentFactor;
+    eyePos[1] = sin (mAngle) * mWidth * indentFactor;
+    eyePos[2] = mHeight;
+    eyePos *= mEyePosScale;
+}
+
+void
+RenderOsgCameraManipulator::getLookAtPosition (osg::Vec3d &lookAtPos) const
+{
+    float lookAtAngle = mAngle + mLookAtOffset;
+    lookAtPos[0] = cos (lookAtAngle) * mLength * 0.5f;
+    lookAtPos[1] = sin (lookAtAngle) * mWidth * 0.5f;
+    lookAtPos[2] = mHeight * 0.25f;
+}
+
+bool
+RenderOsgCameraManipulator::handleKeyDown (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
+{
+    (void)us;
+    bool eventHandled = false;
+    int key = ea.getKey ();
+    if (key == osgGA::GUIEventAdapter::KEY_Space) {
+        home (ea.getTime ());
+
+        eventHandled = true;
+    } else if (key == osgGA::GUIEventAdapter::KEY_Left) {
+        rotate (-0.1);
+        eventHandled = true;
+    } else if (key == osgGA::GUIEventAdapter::KEY_Right) {
+        rotate (0.1);
+        eventHandled = true;
+    }
+
+    return eventHandled;
+}
+
+bool
+RenderOsgCameraManipulator::handleMouseWheel (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
+{
+    (void)us;
+    bool eventHandled = false;
+    osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion();
+
+    if (sm == osgGA::GUIEventAdapter::SCROLL_DOWN || sm == osgGA::GUIEventAdapter::SCROLL_RIGHT) {
+        rotate (0.1);
+        eventHandled = true;
+    } else if (sm == osgGA::GUIEventAdapter::SCROLL_UP || sm == osgGA::GUIEventAdapter::SCROLL_LEFT) {
+        rotate (-0.1);
+        eventHandled = true;
+    }
+
+    return eventHandled;
+}
+
+bool
+RenderOsgCameraManipulator::performMovementLeftMouseButton (const double eventTimeDelta, const double dx, const double dy)
+{
+    (void)eventTimeDelta;
+
+    rotate (-2.0 * dx);
+    modifyHeight (-dy);
+    return true;
+}
+
+} // namespace XCam
diff --git a/modules/render/render_osg_camera_manipulator.h b/modules/render/render_osg_camera_manipulator.h
new file mode 100644
index 0000000..0653039
--- /dev/null
+++ b/modules/render/render_osg_camera_manipulator.h
@@ -0,0 +1,123 @@
+/*
+ * render_osg_camera_manipulator.h -  supports 3D interactive manipulators
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_CAMERA_MANIPULATOR_H
+#define XCAM_OSG_CAMERA_MANIPULATOR_H
+
+#include <osgGA/StandardManipulator>
+
+namespace XCam {
+
+class RenderOsgCameraManipulator
+    : public osgGA::StandardManipulator
+{
+public:
+
+    explicit RenderOsgCameraManipulator ();
+
+    virtual ~RenderOsgCameraManipulator ();
+
+    virtual void setByMatrix (const osg::Matrixd &matrix)
+    {
+        (void)matrix;
+    }
+
+    virtual void setByInverseMatrix (const osg::Matrixd &matrix)
+    {
+        (void)matrix;
+    }
+
+    virtual osg::Matrixd getMatrix () const;
+
+    virtual osg::Matrixd getInverseMatrix () const;
+
+    virtual void home (double currentTime);
+
+    virtual void setTransformation (const osg::Vec3d &eye, const osg::Quat &rotation)
+    {
+        (void)eye;
+        (void)rotation;
+    }
+
+    virtual void setTransformation (const osg::Vec3d &eye, const osg::Vec3d &center, const osg::Vec3d &up)
+    {
+        (void)eye;
+        (void)center;
+        (void)up;
+    }
+
+    virtual void getTransformation (osg::Vec3d &eye, osg::Quat &rotation) const
+    {
+        (void)eye;
+        (void)rotation;
+    }
+
+    virtual void getTransformation (osg::Vec3d &eye, osg::Vec3d &center, osg::Vec3d &up) const
+    {
+        (void)eye;
+        (void)center;
+        (void)up;
+    }
+
+    void setInitialValues (float angle, float length, float width, float height)
+    {
+        mAngle = angle;
+        mLength = length;
+        mWidth = width;
+        mHeight = height;
+        mMinHeight = height / 2.0f;
+
+        mUp = osg::Vec3d(0.0f, 0.0f, 1.0f);
+    }
+
+private:
+    RenderOsgCameraManipulator (RenderOsgCameraManipulator const &other);
+
+    RenderOsgCameraManipulator &operator= (RenderOsgCameraManipulator const &other);
+
+    virtual bool handleKeyDown (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us);
+
+    virtual bool handleMouseWheel (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us);
+
+    virtual bool performMovementLeftMouseButton (const double eventTimeDelta, const double dx, const double dy);
+
+    void rotate (float deltaAngle);
+
+    void modifyHeight (float delta);
+
+    void getEyePosition (osg::Vec3d &eye) const;
+
+    void getLookAtPosition (osg::Vec3d &center) const;
+
+    float mAngle;
+    float mLookAtOffset;
+    float mMaxLookAtOffset;
+    float mLength;
+    float mWidth;
+    float mHeight;
+    float mMaxHeight;
+    float mMinHeight;
+    float mEyePosScale;
+    osg::Vec3d mUp;
+};
+
+} // namespace XCam
+
+#endif // XCAM_OSG_CAMERA_MANIPULATOR_H
diff --git a/modules/render/render_osg_model.cpp b/modules/render/render_osg_model.cpp
new file mode 100644
index 0000000..4062fed
--- /dev/null
+++ b/modules/render/render_osg_model.cpp
@@ -0,0 +1,342 @@
+/*
+ * render_osg_model.cpp -  represents renderable things by model
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "render_osg_model.h"
+
+#include <iostream>
+#include <string>
+
+#include <osg/MatrixTransform>
+#include <osg/Texture2D>
+#include <osgDB/ReadFile>
+
+namespace XCam {
+
+RenderOsgModel::RenderOsgModel (const char *name, uint32_t width, uint32_t height)
+    : _name (NULL)
+    , _model (NULL)
+    , _geode (NULL)
+    , _program (NULL)
+    , _texture (NULL)
+{
+    XCAM_LOG_DEBUG ("RenderOsgModel width(%d), height(%d) ", width, height);
+    XCAM_ASSERT (name);
+    if (name)
+        _name = strndup (name, XCAM_MAX_STR_SIZE);
+
+    _model = new osg::Group ();
+    _geode = new osg::Geode ();
+
+    _texture = create_texture (width, height);
+    if (_texture.get ()) {
+        add_texture (_texture);
+    }
+}
+
+RenderOsgModel::RenderOsgModel (const char *name, bool from_file)
+    : _name (NULL)
+    , _model (NULL)
+    , _geode (NULL)
+    , _program (NULL)
+    , _texture (NULL)
+{
+    XCAM_LOG_DEBUG ("RenderOsgModel model name (%s) ", name);
+    XCAM_ASSERT (name);
+    if (name)
+        _name = strndup (name, XCAM_MAX_STR_SIZE);
+
+    _model = new osg::Group ();
+    _geode = new osg::Geode ();
+
+    if (from_file && NULL != _geode.get ()) {
+        osg::ref_ptr<osg::Node> node = create_model_from_file (name);
+        _geode->addChild (node);
+    }
+}
+
+RenderOsgModel::~RenderOsgModel ()
+{
+    if (_name)
+        xcam_free (_name);
+}
+
+osg::Node*
+RenderOsgModel::create_model_from_file (const char *name)
+{
+    XCAM_LOG_DEBUG ("Invailide node name %s", name);
+    if (name == NULL) {
+        return NULL;
+    }
+
+    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile (name);
+    if (NULL == node.get ()) {
+        XCAM_LOG_ERROR ("Read node file FAILD!!! node name %s", name);
+    }
+
+    return node.release();
+}
+
+void
+RenderOsgModel::append_model (SmartPtr<RenderOsgModel> &child_model)
+{
+    osg::ref_ptr<osg::Group> model = get_model ();
+
+    if (NULL == model.get () || NULL == child_model.ptr ()) {
+        XCAM_LOG_ERROR ("Append child model ERROR!! NULL model  !!");
+        return;
+    }
+
+    model->addChild (child_model->get_model ());
+}
+
+void
+RenderOsgModel::append_geode (SmartPtr<RenderOsgModel> &child_model)
+{
+    osg::ref_ptr<osg::Group> model = get_model ();
+
+    if (NULL == model.get () || NULL == child_model.ptr ()) {
+        XCAM_LOG_ERROR ("Append child geode ERROR!! NULL model  !!");
+        return;
+    }
+
+    model->addChild (child_model->get_geode ());
+}
+
+XCamReturn
+RenderOsgModel::setup_shader_program (
+    const char *name,
+    osg::Shader::Type type,
+    const char *source_text)
+{
+    XCAM_LOG_DEBUG ("setup shader program name(%s), type(%d)", name, type);
+    XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+    if (NULL == _program.get ()) {
+        _program = new osg::Program ();
+        _program->setName (name);
+    }
+
+    _program->addShader (new osg::Shader (type, source_text));
+
+    _model->getOrCreateStateSet ()->setAttributeAndModes (_program, osg::StateAttribute::ON);
+    _model->getOrCreateStateSet ()->setMode (GL_DEPTH_TEST, osg::StateAttribute::ON);
+
+    return result;
+}
+
+XCamReturn
+RenderOsgModel::setup_vertex_model (
+    BowlModel::VertexMap &vertices,
+    BowlModel::PointMap &points,
+    BowlModel::IndexVector &indices,
+    float a,
+    float b,
+    float c)
+{
+    XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+    osg::ref_ptr<osg::Group> model = get_model ();
+    osg::ref_ptr<osg::Geode> geode = get_geode ();
+    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry ();
+
+    geode->addDrawable (geometry);
+    geometry->setUseVertexBufferObjects (true);
+
+    osg::ref_ptr<osg::Vec3Array> vertex_array = new osg::Vec3Array ();
+    osg::ref_ptr<osg::Vec2Array> tex_coord_array = new osg::Vec2Array ();
+    osg::ref_ptr<osg::DrawElementsUInt> index_array = new osg::DrawElementsUInt (GL_TRIANGLE_STRIP, 0);
+
+    osg::ref_ptr<osg::Vec3Array> normal_array = new osg::Vec3Array ();
+    osg::ref_ptr<osg::Vec4Array> color_array = new osg::Vec4Array ();
+
+    normal_array->push_back (osg::Vec3 (0, -1, 0));
+    geometry->setNormalArray (normal_array);
+    geometry->setNormalBinding (osg::Geometry::BIND_OVERALL);
+
+    color_array->push_back (osg::Vec4 (1.0, 0.0, 0.0, 1.0));
+    geometry->setColorArray (color_array);
+    geometry->setColorBinding (osg::Geometry::BIND_OVERALL);
+
+    for (uint32_t idx = 0; idx < vertices.size (); idx++) {
+        vertex_array->push_back (
+            osg::Vec3f (vertices[idx].x * a,
+                        vertices[idx].y * b,
+                        vertices[idx].z * c));
+    }
+
+    for (uint32_t idx = 0; idx < points.size (); idx++) {
+        tex_coord_array->push_back (osg::Vec2f (points[idx].x, points[idx].y));
+    }
+
+    for (uint32_t idx = 0; idx < indices.size (); idx++) {
+        index_array->push_back (indices[idx]);
+    }
+
+    geometry->setVertexArray (vertex_array.get ());
+
+    if (points.size () > 0) {
+        geometry->setTexCoordArray (0, tex_coord_array.get ());
+    }
+
+    if (indices.size () > 0) {
+        geometry->addPrimitiveSet (index_array.get ());
+    } else {
+        geometry->addPrimitiveSet (new osg::DrawArrays (GL_TRIANGLE_FAN, 0, 4));
+    }
+
+    model->addChild (geode);
+
+    return result;
+}
+
+XCamReturn
+RenderOsgModel::setup_model_matrix (
+    float translation_x,
+    float translation_y,
+    float translation_z,
+    float rotation_x,
+    float rotation_y,
+    float rotation_z,
+    float rotation_degrees)
+{
+    XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+    osg::ref_ptr<osg::Group> model = get_model ();
+    osg::ref_ptr<osg::Geode> geode = get_geode ();
+
+    const osg::Vec3f axis(rotation_x, rotation_y, rotation_z);
+    osg::ref_ptr<osg::MatrixTransform> mat = new osg::MatrixTransform ();
+    mat->setMatrix (osg::Matrix::scale (osg::Vec3 (1.0, 1.0, 1.0)) *
+                    osg::Matrix::rotate ((rotation_degrees / 180.f) * osg::PI_2, axis) *
+                    osg::Matrix::translate (osg::Vec3 (translation_x, translation_y, translation_z)));
+
+    mat->addChild (geode);
+    model->addChild (mat);
+
+    return result;
+}
+
+XCamReturn
+RenderOsgModel::update_texture (SmartPtr<VideoBuffer> &buffer)
+{
+    XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+    XCAM_LOG_DEBUG ("RenderOsgModel::update_texture ");
+
+    if (NULL == _texture.get ()) {
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    {
+        SmartLock locker (_mutex);
+
+        VideoBufferInfo info = buffer->get_video_info ();
+        uint32_t image_width = info.width;
+        uint32_t image_height = info.height;
+
+        osg::ref_ptr<osg::Image> image_y = new osg::Image ();
+        osg::ref_ptr<osg::Image> image_uv = new osg::Image ();
+
+        uint8_t* image_buffer = buffer->map ();
+        if (NULL == image_buffer) {
+            XCAM_LOG_ERROR ("buffer map return NULL!!");
+            result = XCAM_RETURN_ERROR_MEM;
+        } else {
+            uint8_t* src_y = image_buffer;
+            uint8_t* src_uv = image_buffer + image_width * image_height;
+
+            image_y->setImage (image_width, image_height, 1,
+                               GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+                               src_y, osg::Image::NO_DELETE);
+
+            image_uv->setImage (image_width / 2, image_height / 2, 1,
+                                GL_LUMINANCE, GL_RG, GL_UNSIGNED_BYTE,
+                                src_uv, osg::Image::NO_DELETE);
+
+            _texture->_texture_y->setImage (image_y);
+            _texture->_texture_uv->setImage (image_uv);
+        }
+        //buffer->unmap ();
+    }
+
+    return result;
+}
+
+NV12Texture*
+RenderOsgModel::create_texture (uint32_t width, uint32_t height)
+{
+    osg::ref_ptr<NV12Texture> nv12 = new NV12Texture (width, height);
+
+    nv12->_texture_y = new osg::Texture2D ();
+    nv12->_texture_y->setImage (new osg::Image ());
+
+    nv12->_texture_y->setInternalFormat (GL_LUMINANCE);
+    nv12->_texture_y->setResizeNonPowerOfTwoHint (false);
+    nv12->_texture_y->setNumMipmapLevels (0);
+    nv12->_texture_y->setFilter (osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
+    nv12->_texture_y->setFilter (osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
+    nv12->_texture_y->setWrap (osg::Texture::WRAP_S, osg::Texture::CLAMP);
+    nv12->_texture_y->setWrap (osg::Texture::WRAP_T, osg::Texture::CLAMP);
+
+    nv12->_texture_y->setTextureWidth (width);
+    nv12->_texture_y->setTextureHeight (height);
+
+    nv12->_texture_uv = new osg::Texture2D ();
+    nv12->_texture_uv->setImage (new osg::Image ());
+
+    nv12->_texture_uv->setInternalFormat (GL_RG);
+    nv12->_texture_uv->setResizeNonPowerOfTwoHint (false);
+    nv12->_texture_uv->setNumMipmapLevels (0);
+    nv12->_texture_uv->setFilter (osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
+    nv12->_texture_uv->setFilter (osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
+    nv12->_texture_uv->setWrap (osg::Texture::WRAP_S, osg::Texture::CLAMP);
+    nv12->_texture_uv->setWrap (osg::Texture::WRAP_T, osg::Texture::CLAMP);
+
+    nv12->_texture_uv->setTextureWidth (width / 2);
+    nv12->_texture_uv->setTextureHeight (height / 2);
+
+    return nv12.release ();
+}
+
+XCamReturn
+RenderOsgModel::add_texture (osg::ref_ptr<NV12Texture> &texture)
+{
+    XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+    osg::ref_ptr<osg::Group> model = get_model ();
+
+    if (NULL == model.get () || NULL == _texture.get ()) {
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    model->getOrCreateStateSet()->setTextureAttribute(0, texture->_texture_y.get ());
+    texture->_uniform_y = new osg::Uniform (osg::Uniform::SAMPLER_2D, "textureY");
+    texture->_uniform_y->set (0);
+    model->getOrCreateStateSet ()->addUniform (texture->_uniform_y.get ());
+
+    model->getOrCreateStateSet ()->setTextureAttribute (1, texture->_texture_uv.get ());
+    texture->_uniform_uv = new osg::Uniform (osg::Uniform::SAMPLER_2D, "textureUV");
+    texture->_uniform_uv->set (1);
+    model->getOrCreateStateSet ()->addUniform (texture->_uniform_uv.get ());
+
+    return result;
+}
+
+} // namespace XCam
diff --git a/modules/render/render_osg_model.h b/modules/render/render_osg_model.h
new file mode 100644
index 0000000..eaf6302
--- /dev/null
+++ b/modules/render/render_osg_model.h
@@ -0,0 +1,125 @@
+/*
+ * render_osg_model.h -  represents renderable things by object
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_RENDER_MODEL_H
+#define XCAM_OSG_RENDER_MODEL_H
+
+#include <osg/Texture2D>
+#include <osg/Group>
+
+#include <interface/data_types.h>
+#include <interface/stitcher.h>
+#include <xcam_mutex.h>
+
+namespace XCam {
+
+class NV12Texture : public osg::Referenced
+{
+public:
+    explicit NV12Texture (uint32_t width, uint32_t height)
+    {
+        _image_width = width;
+        _image_height = height;
+    }
+
+public:
+    uint32_t _image_width;
+    uint32_t _image_height;
+
+    osg::ref_ptr<osg::Texture2D> _texture_y;
+    osg::ref_ptr<osg::Texture2D> _texture_uv;
+
+    osg::ref_ptr<osg::Uniform> _uniform_y;
+    osg::ref_ptr<osg::Uniform> _uniform_uv;
+};
+
+class RenderOsgModel {
+public:
+
+    explicit RenderOsgModel (const char *name, uint32_t width, uint32_t height);
+    explicit RenderOsgModel (const char *name, bool from_file = true);
+
+    virtual ~RenderOsgModel ();
+
+    const char *get_name () const {
+        return _name;
+    }
+
+    osg::Node* create_model_from_file (const char *name);
+
+    osg::Group* get_model () const {
+        return _model;
+    }
+
+    void append_model (SmartPtr<RenderOsgModel> &model);
+
+    void append_geode (SmartPtr<RenderOsgModel> &model);
+
+
+    osg::Geode* get_geode () const {
+        return _geode;
+    }
+
+    XCamReturn setup_shader_program (
+        const char *name,
+        osg::Shader::Type type,
+        const char *source_text);
+
+    XCamReturn setup_vertex_model (
+        BowlModel::VertexMap &vertices,
+        BowlModel::PointMap &points,
+        BowlModel::IndexVector &indices,
+        float a = 1.0f,
+        float b = 1.0f,
+        float c = 1.0f);
+
+    XCamReturn setup_model_matrix (
+        float translation_x,
+        float translation_y,
+        float translation_z,
+        float rotation_x,
+        float rotation_y,
+        float rotation_z,
+        float rotation_degrees);
+
+    XCamReturn update_texture (SmartPtr<VideoBuffer> &buffer);
+
+private:
+
+    XCAM_DEAD_COPY (RenderOsgModel);
+
+    NV12Texture* create_texture (uint32_t width, uint32_t height);
+    XCamReturn add_texture (osg::ref_ptr<NV12Texture> &texture);
+
+private:
+
+    char *_name;
+
+    osg::ref_ptr<osg::Group> _model;
+    osg::ref_ptr<osg::Geode> _geode;
+    osg::ref_ptr<osg::Program> _program;
+    osg::ref_ptr<NV12Texture> _texture;
+
+    Mutex _mutex;
+};
+
+} // namespace XCam
+
+#endif // XCAM_OSG_RENDER_MODEL_H
diff --git a/modules/render/render_osg_shader.h b/modules/render/render_osg_shader.h
new file mode 100644
index 0000000..b2dd52e
--- /dev/null
+++ b/modules/render/render_osg_shader.h
@@ -0,0 +1,93 @@
+/*
+ * render_osg_shader.h -  common gl shaders
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_SHADER_H
+#define XCAM_OSG_SHADER_H
+
+namespace XCam {
+
+static const char VtxShaderProjectNV12Texture[] = ""
+        "precision highp float;                                        \n"
+        "attribute vec4 osg_Vertex;                                    \n"
+        "attribute vec2 osg_MultiTexCoord0;                            \n"
+        "attribute vec4 osg_Color;                                     \n"
+        "uniform mat4 osg_ModelViewProjectionMatrix;                   \n"
+        "uniform mat4 osg_ModelViewMatrix;                             \n"
+        "uniform mat4 osg_ViewMatrixInverse;                           \n"
+        "varying vec2 texcoord;                                        \n"
+        "varying vec4 color;                                           \n"
+        "void main(void)                                               \n"
+        "{                                                             \n"
+        "    texcoord = osg_MultiTexCoord0;                            \n"
+        "    gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
+        "    color = osg_Color;                                        \n"
+        "}                                                             \n";
+
+static const char FrgShaderProjectNV12Texture[] = ""
+        "precision highp float;                                                      \n"
+        "uniform sampler2D textureY;                                                 \n"
+        "uniform sampler2D textureUV;                                                \n"
+        "varying vec2 texcoord;                                                      \n"
+        "varying vec4 color;                                                         \n"
+        "vec4 getRGBColorNV12(sampler2D u_textureY, sampler2D u_textureUV, vec2 tex) \n"
+        "{                                                                           \n"
+        "    vec4 resultcolor = vec4 (0.0, 0.0, 0.0, 1.0);                           \n"
+        "    float y, u, v;                                                          \n"
+        "    y = texture2D(u_textureY, vec2(tex.s, tex.t)).r;                        \n"
+        "    vec2 colorUV = texture2D(u_textureUV, vec2(tex.s, tex.t)).rg;            \n"
+        "    u = colorUV.x-0.5;                                                      \n"
+        "    v = colorUV.y-0.5;                                                      \n"
+        "    y = 1.1643*(y-0.0625);                                                  \n"
+        "    resultcolor.r = (y+1.5958*(v));                                         \n"
+        "    resultcolor.g = (y-0.39173*(u)-0.81290*(v));                            \n"
+        "    resultcolor.b = (y+2.017*(u));                                          \n"
+        "    resultcolor.a = 1.0;                                                    \n"
+        "    return resultcolor;                                                     \n"
+        "}                                                                           \n"
+        "void main()                                                                 \n"
+        "{                                                                           \n"
+        "    vec4 textureColor = getRGBColorNV12(textureY, textureUV, texcoord);     \n"
+        "    gl_FragColor =  textureColor;                                           \n"
+        "}                                                                           \n";
+
+const char VtxShaderSimpleTexture[] = ""
+                                      "precision highp float;                                        \n"
+                                      "attribute vec4 osg_Vertex;                                    \n"
+                                      "attribute vec4 osg_Color;                                     \n"
+                                      "uniform mat4 osg_ModelViewProjectionMatrix;                   \n"
+                                      "varying vec4 color;                                           \n"
+                                      "void main(void)                                               \n"
+                                      "{                                                             \n"
+                                      "    gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex; \n"
+                                      "    color = osg_Color;                                        \n"
+                                      "}                                                             \n";
+
+const char FrgShaderSimpleTexture[] = ""
+                                      "precision highp float;            \n"
+                                      "varying vec4 color;               \n"
+                                      "void main()                       \n"
+                                      "{                                 \n"
+                                      "    gl_FragColor = color;         \n"
+                                      "}                                 \n";
+
+
+} // namespace XCam
+
+#endif // XCAM_OSG_SHADER_H
diff --git a/modules/render/render_osg_viewer.cpp b/modules/render/render_osg_viewer.cpp
new file mode 100644
index 0000000..ff0f394
--- /dev/null
+++ b/modules/render/render_osg_viewer.cpp
@@ -0,0 +1,137 @@
+/*
+ * render_osg_viewer.cpp -  renders a single view on to a single scene
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "render_osg_viewer.h"
+#include "render_osg_model.h"
+#include "render_osg_camera_manipulator.h"
+
+#include <string>
+
+namespace XCam {
+
+RenderOsgViewer::RenderOsgViewer ()
+    : Thread ("RenderOsgViewerThread")
+    , _viewer (NULL)
+    , _model_groups (NULL)
+    , _initialized (false)
+{
+    _viewer = new osgViewer::Viewer ();
+
+    if (!_initialized) {
+        initialize ();
+    }
+}
+
+RenderOsgViewer::~RenderOsgViewer ()
+{
+    _viewer->setDone (true);
+}
+
+XCamReturn
+RenderOsgViewer::initialize ()
+{
+    XCamReturn result = XCAM_RETURN_NO_ERROR;
+
+    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
+    uint32_t win_width = 1920;
+    uint32_t win_height = 1080;
+    if (wsi) {
+        wsi->getScreenResolution (osg::GraphicsContext::ScreenIdentifier (0), win_width, win_height);
+    }
+
+    _viewer->setThreadingModel (osgViewer::Viewer::SingleThreaded);
+
+    _viewer->setLightingMode (osg::View::SKY_LIGHT);
+    _viewer->getLight()->setAmbient (osg::Vec4f(0.f, 0.f, 0.f, 1.f));
+    _viewer->getLight()->setDiffuse (osg::Vec4d(0.4f, 0.4f, 0.4f, 1.f));
+    _viewer->getLight()->setSpecular (osg::Vec4d(0.5f, 0.5f, 0.5f, 1.f));
+
+    osg::ref_ptr<osgViewer::StatsHandler> stats_handler = new osgViewer::StatsHandler ();
+    _viewer->addEventHandler (stats_handler);
+
+    _viewer->setUpViewInWindow (0, 0, win_width, win_height);
+
+    osg::ref_ptr<RenderOsgCameraManipulator> vp_manipulator = new RenderOsgCameraManipulator ();
+    vp_manipulator->setInitialValues (osg::PI, 6.0f, 4.0f, 2.6f);
+    _viewer->setCameraManipulator (vp_manipulator);
+    _viewer->getCamera ()->setClearMask (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    _viewer->getCamera ()->setComputeNearFarMode (osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
+    _viewer->getCamera ()->setClearColor (osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+    _viewer->getCamera ()->setViewport (0, 0, win_width, win_height);
+
+    _initialized = true;
+
+    return result;
+}
+
+void
+RenderOsgViewer::start_render ()
+{
+    Thread::start ();
+}
+
+void
+RenderOsgViewer::stop_render ()
+{
+    Thread::stop ();
+}
+
+bool
+RenderOsgViewer::loop ()
+{
+    if (!_viewer->done ())
+    {
+        _viewer->frame ();
+    }
+
+    return true;
+}
+
+void
+RenderOsgViewer::set_camera_manipulator (osg::ref_ptr<osgGA::StandardManipulator> &manipulator)
+{
+    _viewer->setCameraManipulator (manipulator);
+}
+
+void
+RenderOsgViewer::add_model (SmartPtr<RenderOsgModel> &model)
+{
+    if (!model.ptr ()) {
+        return;
+    }
+
+    if (!_model_groups.ptr ()) {
+        _model_groups = model;
+    } else {
+        _model_groups->append_model (model);
+    }
+}
+
+void
+RenderOsgViewer::validate_model_groups ()
+{
+    if (!_model_groups.ptr ()) {
+        return;
+    }
+    _viewer->setSceneData (_model_groups->get_model ());
+}
+
+} // namespace XCam
+
diff --git a/modules/render/render_osg_viewer.h b/modules/render/render_osg_viewer.h
new file mode 100644
index 0000000..335c562
--- /dev/null
+++ b/modules/render/render_osg_viewer.h
@@ -0,0 +1,73 @@
+/*
+ * render_osg_viewer.h -  renders a single view on to a single scene
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#ifndef XCAM_OSG_RENDER_VIEWER_H
+#define XCAM_OSG_RENDER_VIEWER_H
+
+#include <osgViewer/Viewer>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgGA/StandardManipulator>
+
+#include <interface/data_types.h>
+#include <interface/stitcher.h>
+#include <xcam_mutex.h>
+#include <xcam_thread.h>
+
+namespace XCam {
+
+class RenderOsgModel;
+
+class RenderOsgViewer
+    : public Thread
+{
+public:
+
+    explicit RenderOsgViewer ();
+
+    virtual ~RenderOsgViewer ();
+
+    osgViewer::Viewer *get_viewer () {
+        return _viewer;
+    }
+
+    void set_camera_manipulator (osg::ref_ptr<osgGA::StandardManipulator> &manipulator);
+
+    void add_model (SmartPtr<RenderOsgModel> &model);
+    void validate_model_groups ();
+
+    void start_render ();
+    void stop_render ();
+
+protected:
+    virtual bool loop ();
+
+private:
+    XCAM_DEAD_COPY (RenderOsgViewer);
+    XCamReturn initialize ();
+
+private:
+    osg::ref_ptr<osgViewer::Viewer> _viewer;
+    SmartPtr<RenderOsgModel> _model_groups;
+    bool _initialized;
+};
+
+} // namespace XCam
+
+#endif // XCAM_OSG_RENDER_VIEWER_H
diff --git a/modules/soft/Makefile.am b/modules/soft/Makefile.am
index b1cd92b..83b2721 100644
--- a/modules/soft/Makefile.am
+++ b/modules/soft/Makefile.am
@@ -1,75 +1,63 @@
 lib_LTLIBRARIES = libxcam_soft.la
 
-XCAMSOFT_CXXFLAGS =               \
-    $(LIBCL_CFLAGS)               \
-    -I$(top_srcdir)/xcore         \
-    -I$(top_srcdir)/modules       \
+XCAMSOFT_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)        \
+    -I$(top_srcdir)/xcore   \
+    -I$(top_srcdir)/modules \
     $(NULL)
 
-XCAMSOFT_LIBS =
-
-xcam_soft_sources =                  \
-    soft_handler.cpp                 \
-    soft_video_buf_allocator.cpp     \
-    soft_worker.cpp                  \
-    soft_blender_tasks_priv.cpp      \
-    soft_blender.cpp                 \
-    soft_geo_mapper.cpp              \
-    soft_geo_tasks_priv.cpp          \
-    soft_copy_task.cpp               \
-    soft_stitcher.cpp                \
-   $(NULL)
+XCAMSOFT_LIBS = \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
 
 if HAVE_OPENCV
-XCAMSOFT_CXXFLAGS += $(OPENCV_CFLAGS)
-
-XCAMSOFT_LIBS += $(OPENCV_LIBS)
-
-xcam_soft_sources +=                 \
-    cv_capi_feature_match.cpp        \
-   $(NULL)
-
+XCAMSOFT_LIBS += $(top_builddir)/modules/ocv/libxcam_ocv.la
 endif
 
-libxcam_soft_la_SOURCES =   \
-    $(xcam_soft_sources)    \
+xcam_soft_sources = \
+    soft_handler.cpp             \
+    soft_video_buf_allocator.cpp \
+    soft_worker.cpp              \
+    soft_blender_tasks_priv.cpp  \
+    soft_blender.cpp             \
+    soft_geo_mapper.cpp          \
+    soft_geo_tasks_priv.cpp      \
+    soft_copy_task.cpp           \
+    soft_stitcher.cpp            \
+   $(NULL)
+
+libxcam_soft_la_SOURCES = \
+    $(xcam_soft_sources) \
     $(NULL)
 
-libxcam_soft_la_CXXFLAGS =  \
-    $(XCAMSOFT_CXXFLAGS)    \
-    $(XCAM_CXXFLAGS)        \
+libxcam_soft_la_CXXFLAGS = \
+    $(XCAMSOFT_CXXFLAGS) \
     $(NULL)
 
-libxcam_soft_la_LIBADD =                  \
-    $(top_builddir)/xcore/libxcam_core.la \
-    $(XCAMSOFT_LIBS)                      \
+libxcam_soft_la_LIBADD = \
+    $(XCAMSOFT_LIBS) \
     $(NULL)
 
-libxcam_soft_la_LDFLAGS =   \
-    $(XCAM_LT_LDFLAGS)      \
-    $(PTHREAD_LDFLAGS)      \
+libxcam_soft_la_LDFLAGS = \
+    $(XCAM_LT_LDFLAGS) \
     $(NULL)
 
 libxcam_softincludedir = $(includedir)/xcam/soft
 
-nobase_libxcam_softinclude_HEADERS =   \
-    soft_handler.h                     \
-    soft_video_buf_allocator.h         \
-    soft_worker.h                      \
-    soft_image.h                       \
-    soft_blender.h                     \
-    soft_geo_mapper.h                  \
-    soft_copy_task.h                   \
-    soft_stitcher.h                    \
+nobase_libxcam_softinclude_HEADERS = \
+    soft_handler.h             \
+    soft_video_buf_allocator.h \
+    soft_worker.h              \
+    soft_image.h               \
+    soft_blender.h             \
+    soft_geo_mapper.h          \
+    soft_copy_task.h           \
+    soft_stitcher.h            \
     $(NULL)
 
-noinst_HEADERS =                       \
-    soft_blender_tasks_priv.h          \
-    soft_geo_tasks_priv.h              \
+noinst_HEADERS = \
+    soft_blender_tasks_priv.h \
+    soft_geo_tasks_priv.h     \
     $(NULL)
 
-if HAVE_OPENCV
-noinst_HEADERS += cv_capi_feature_match.h
-endif
-
 libxcam_soft_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/soft/cv_capi_feature_match.h b/modules/soft/cv_capi_feature_match.h
deleted file mode 100644
index 67a9d4f..0000000
--- a/modules/soft/cv_capi_feature_match.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * cv_capi_feature_match.h - optical flow feature match
- *
- *  Copyright (c) 2016-2017 Intel Corporation
- *
- * 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.
- *
- * Author: Wind Yuan <feng.yuan@intel.com>
- * Author: Yinhang Liu <yinhangx.liu@intel.com>
- * Author: Zong Wei <wei.zong@intel.com>
- */
-
-#ifndef CV_CAPI_FEATURE_MATCH_H
-#define CV_CAPI_FEATURE_MATCH_H
-
-#include <xcam_std.h>
-#include <video_buffer.h>
-#include <interface/feature_match.h>
-
-#ifdef ANDROID
-#include <cv.h>
-#else
-#include <opencv2/opencv.hpp>
-#endif
-
-namespace XCam {
-
-class CVCapiFeatureMatch
-    : public FeatureMatch
-{
-public:
-    explicit CVCapiFeatureMatch ();
-
-    void optical_flow_feature_match (
-        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
-        Rect &left_img_crop, Rect &right_img_crop, int dst_width);
-
-    void set_ocl (bool use_ocl) {
-        XCAM_UNUSED (use_ocl);
-    }
-    bool is_ocl_path () {
-        return false;
-    }
-
-protected:
-    bool get_crop_image (const SmartPtr<VideoBuffer> &buffer, const Rect &crop_rect,
-                         std::vector<char> &crop_image, CvMat &img);
-
-    void add_detected_data (CvArr* image, std::vector<CvPoint2D32f> &corners);
-    void get_valid_offsets (std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
-                            std::vector<char> &status, std::vector<float> &error,
-                            std::vector<float> &offsets, float &sum, int &count,
-                            CvArr* out_image, CvSize &img0_size);
-
-    void calc_of_match (CvArr* image0, CvArr* image1,
-                        std::vector<CvPoint2D32f> &corner0, std::vector<CvPoint2D32f> &corner1,
-                        std::vector<char> &status, std::vector<float> &error,
-                        int &last_count, float &last_mean_offset, float &out_x_offset);
-
-    void detect_and_match (CvArr* img_left, CvArr* img_right, Rect &crop_left, Rect &crop_right,
-                           int &valid_count, float &mean_offset, float &x_offset, int dst_width);
-
-private:
-    XCAM_DEAD_COPY (CVCapiFeatureMatch);
-
-    std::vector<char> _left_crop_image;
-    std::vector<char> _right_crop_image;
-};
-
-}
-
-#endif // CV_CAPI_FEATURE_MATCH_H
diff --git a/modules/soft/soft_blender.cpp b/modules/soft/soft_blender.cpp
index 7e0c678..056ad37 100644
--- a/modules/soft/soft_blender.cpp
+++ b/modules/soft/soft_blender.cpp
@@ -83,9 +83,11 @@
 
 public:
     BlenderPrivConfig (SoftBlender *blender, uint32_t level)
-        : pyr_levels (level)
+        : pyr_levels (level - 1)
         , _blender (blender)
-    {}
+    {
+        XCAM_ASSERT (level >= 2 && level <= XCAM_SOFT_PYRAMID_MAX_LEVEL);
+    }
 
     XCamReturn init_first_masks (uint32_t width, uint32_t height);
     XCamReturn scale_down_masks (uint32_t level, uint32_t width, uint32_t height);
@@ -171,8 +173,10 @@
     : SoftHandler (name)
     , Blender (SOFT_BLENDER_ALIGNMENT_X, SOFT_BLENDER_ALIGNMENT_Y)
 {
-    _priv_config = new SoftBlenderPriv::BlenderPrivConfig (this, XCAM_SOFT_PYRAMID_DEFAULT_LEVEL);
-    XCAM_ASSERT (_priv_config.ptr ());
+    SmartPtr<SoftBlenderPriv::BlenderPrivConfig> config =
+        new SoftBlenderPriv::BlenderPrivConfig (this, XCAM_SOFT_PYRAMID_DEFAULT_LEVEL);
+    XCAM_ASSERT (config.ptr ());
+    _priv_config = config;
 }
 
 SoftBlender::~SoftBlender ()
@@ -682,7 +686,9 @@
     XCAM_ASSERT (merge_size.width % SOFT_BLENDER_ALIGNMENT_X == 0);
 
     overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
-    _priv_config->first_lap_pool = new SoftVideoBufAllocator (overlap_info);
+    SmartPtr<BufferPool> first_lap_pool = new SoftVideoBufAllocator (overlap_info);
+    XCAM_ASSERT (first_lap_pool.ptr ());
+    _priv_config->first_lap_pool = first_lap_pool;
     XCAM_FAIL_RETURN (
         ERROR, _priv_config->first_lap_pool->reserve (LAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
         "blender:%s reserve lap buffer pool(w:%d,h:%d) failed",
@@ -703,8 +709,9 @@
         merge_size.height = XCAM_ALIGN_UP ((merge_size.height + 1) / 2, SOFT_BLENDER_ALIGNMENT_Y);
         overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
 
-        _priv_config->pyr_layer[i].overlap_pool = new SoftVideoBufAllocator (overlap_info);
-        XCAM_ASSERT (_priv_config->pyr_layer[i].overlap_pool.ptr ());
+        SmartPtr<BufferPool> pool = new SoftVideoBufAllocator (overlap_info);
+        XCAM_ASSERT (pool.ptr ());
+        _priv_config->pyr_layer[i].overlap_pool = pool;
         XCAM_FAIL_RETURN (
             ERROR, _priv_config->pyr_layer[i].overlap_pool->reserve (OVERLAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
             "blender:%s reserve buffer pool(w:%d,h:%d) failed",
diff --git a/modules/soft/soft_blender.h b/modules/soft/soft_blender.h
index b83511b..f6466f9 100644
--- a/modules/soft/soft_blender.h
+++ b/modules/soft/soft_blender.h
@@ -26,7 +26,7 @@
 #include <soft/soft_handler.h>
 
 #define XCAM_SOFT_PYRAMID_MAX_LEVEL 4
-#define XCAM_SOFT_PYRAMID_DEFAULT_LEVEL 3
+#define XCAM_SOFT_PYRAMID_DEFAULT_LEVEL 2
 
 namespace XCam {
 
diff --git a/modules/soft/soft_blender_tasks_priv.h b/modules/soft/soft_blender_tasks_priv.h
index a2f2ed8..b754df3 100644
--- a/modules/soft/soft_blender_tasks_priv.h
+++ b/modules/soft/soft_blender_tasks_priv.h
@@ -66,7 +66,7 @@
         out[4] += in[4] * coef;
         out[5] += in[5] * coef;
         out[6] += in[6] * coef;
-        out[7] += in[7] * coef;
+        //out[7] += in[7] * coef;
     }
 
     template<typename T>
diff --git a/modules/soft/soft_geo_mapper.cpp b/modules/soft/soft_geo_mapper.cpp
index 478b025..5dac5b7 100644
--- a/modules/soft/soft_geo_mapper.cpp
+++ b/modules/soft/soft_geo_mapper.cpp
@@ -27,6 +27,8 @@
 namespace XCam {
 
 DECLARE_WORK_CALLBACK (CbGeoMapTask, SoftGeoMapper, remap_task_done);
+DECLARE_WORK_CALLBACK (CbGeoMapDualConstTask, SoftDualConstGeoMapper, remap_task_done);
+DECLARE_WORK_CALLBACK (CbGeoMapDualCurveTask, SoftDualCurveGeoMapper, remap_task_done);
 
 SoftGeoMapper::SoftGeoMapper (const char *name)
     : SoftHandler (name)
@@ -60,6 +62,7 @@
             ret[j].y = line [j].y;
         }
     }
+
     return true;
 }
 
@@ -73,6 +76,7 @@
     if (xcam_ret_is_ok (ret) && !out_buf.ptr ()) {
         out_buf = param->out_buf;
     }
+
     return ret;
 }
 
@@ -87,16 +91,9 @@
     const VideoBufferInfo &in_info = param->in_buf->get_video_info ();
     XCAM_FAIL_RETURN (
         ERROR, in_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
-        "SoftGeoMapper(:%s) only support format(NV12) but input format is %s",
+        "SoftGeoMapper(%s) only support format(NV12) but input format is %s",
         XCAM_STR(get_name ()), xcam_fourcc_to_string (in_info.format));
 
-    Float2 factors;
-    get_factors (factors.x, factors.y);
-    if (XCAM_DOUBLE_EQUAL_AROUND (factors.x, 0.0f) ||
-            XCAM_DOUBLE_EQUAL_AROUND (factors.y, 0.0f)) {
-        auto_calculate_factors (_lookup_table->get_width (), _lookup_table->get_height ());
-    }
-
     uint32_t width, height;
     get_output_size (width, height);
     VideoBufferInfo out_info;
@@ -106,13 +103,51 @@
         XCAM_ALIGN_UP (height, XCAM_GEO_MAP_ALIGNMENT_Y));
     set_out_video_info (out_info);
 
+    init_factors ();
+
     XCAM_ASSERT (!_map_task.ptr ());
-    _map_task = new XCamSoftTasks::GeoMapTask (new CbGeoMapTask(this));
-    XCAM_ASSERT (_map_task.ptr ());
+    _map_task = create_remap_task ();
 
     return XCAM_RETURN_NO_ERROR;
 }
 
+void
+SoftGeoMapper::set_work_size (
+    uint32_t thread_x, uint32_t thread_y,
+    uint32_t luma_width, uint32_t luma_height)
+{
+    WorkSize work_unit = _map_task->get_work_uint ();
+    WorkSize global_size (
+        xcam_ceil (luma_width, work_unit.value[0]) / work_unit.value[0],
+        xcam_ceil (luma_height, work_unit.value[1]) / work_unit.value[1]);
+    WorkSize local_size (
+        xcam_ceil(global_size.value[0], thread_x) / thread_x ,
+        xcam_ceil(global_size.value[1], thread_y) / thread_y);
+
+    _map_task->set_local_size (local_size);
+    _map_task->set_global_size (global_size);
+}
+
+bool
+SoftGeoMapper::init_factors ()
+{
+    Float2 factors;
+    get_factors (factors.x, factors.y);
+    if (!XCAM_DOUBLE_EQUAL_AROUND (factors.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factors.y, 0.0f))
+        return true;
+
+    return auto_calculate_factors (_lookup_table->get_width (), _lookup_table->get_height ());
+}
+
+SmartPtr<XCamSoftTasks::GeoMapTask>
+SoftGeoMapper::create_remap_task ()
+{
+    SmartPtr<XCamSoftTasks::GeoMapTask> map_task = new XCamSoftTasks::GeoMapTask (new CbGeoMapTask (this));
+    XCAM_ASSERT (map_task.ptr ());
+
+    return map_task;
+}
+
 XCamReturn
 SoftGeoMapper::start_remap_task (const SmartPtr<ImageHandler::Parameters> &param)
 {
@@ -131,17 +166,7 @@
     args->lookup_table = _lookup_table;
     args->factors = factors;
 
-    uint32_t thread_x = 2, thread_y = 2;
-    WorkSize work_unit = _map_task->get_work_uint ();
-    WorkSize global_size (
-        xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0],
-        xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]);
-    WorkSize local_size (
-        xcam_ceil(global_size.value[0], thread_x) / thread_x ,
-        xcam_ceil(global_size.value[1], thread_y) / thread_y);
-
-    _map_task->set_local_size (local_size);
-    _map_task->set_global_size (global_size);
+    set_work_size (2, 2, args->out_luma->get_width (), args->out_luma->get_height ());
 
     param->in_buf.release ();
     return _map_task->work (args);
@@ -157,7 +182,7 @@
     ret = start_remap_task (param);
     XCAM_FAIL_RETURN (
         ERROR, xcam_ret_is_ok (ret), ret,
-        "geo_mapper:%s start_work failed on idx0", XCAM_STR (get_name ()));
+        "SoftGeoMapper(%s) start_work failed on idx0", XCAM_STR (get_name ()));
 
     param->in_buf.release ();
 
@@ -180,10 +205,11 @@
 {
     XCAM_UNUSED (worker);
     XCAM_ASSERT (worker.ptr () == _map_task.ptr ());
+
     SmartPtr<XCamSoftTasks::GeoMapTask::Args> args = base.dynamic_cast_ptr<XCamSoftTasks::GeoMapTask::Args> ();
     XCAM_ASSERT (args.ptr ());
-    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
 
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
     if (!check_work_continue (param, error))
         return;
 
@@ -194,6 +220,7 @@
 {
     SmartPtr<SoftHandler> mapper = new SoftGeoMapper ();
     XCAM_ASSERT (mapper.ptr ());
+
     return mapper;
 }
 
@@ -204,4 +231,216 @@
     return handler.dynamic_cast_ptr<GeoMapper> ();
 }
 
+SoftDualConstGeoMapper::SoftDualConstGeoMapper (const char *name)
+    : SoftGeoMapper (name)
+    , _left_factor_x (0.0f)
+    , _left_factor_y (0.0f)
+    , _right_factor_x (0.0f)
+    , _right_factor_y (0.0f)
+{
+}
+
+SoftDualConstGeoMapper::~SoftDualConstGeoMapper ()
+{
+}
+
+bool
+SoftDualConstGeoMapper::set_left_factors (float x, float y)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f), false,
+        "SoftGeoMapper(%s) set factors failed. (x:%.3f, h:%.3f)", XCAM_STR(get_name ()), x, y);
+    _left_factor_x = x;
+    _left_factor_y = y;
+
+    return true;
+}
+
+bool
+SoftDualConstGeoMapper::set_right_factors (float x, float y)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f), false,
+        "SoftGeoMapper(%s) set factors failed. (x:%.3f, h:%.3f)", XCAM_STR(get_name ()), x, y);
+    _right_factor_x = x;
+    _right_factor_y = y;
+
+    return true;
+}
+
+bool
+SoftDualConstGeoMapper::auto_calculate_factors (uint32_t lut_w, uint32_t lut_h)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, lut_w > 1 && lut_w > 1, false,
+        "SoftGeoMapper(%s) auto calculate factors failed. lookuptable size need > 1. but set with (w:%d, h:%d)",
+        XCAM_STR(get_name ()), lut_w, lut_h);
+
+    uint32_t width, height;
+    get_output_size (width, height);
+    XCAM_FAIL_RETURN (
+        ERROR, width > 1 && height > 1, false,
+        "SoftGeoMapper(%s) auto calculate factors failed. output size was not set. (w:%d, h:%d)",
+        XCAM_STR(get_name ()), width, height);
+
+    _left_factor_x = (width - 1.0f) / (lut_w - 1.0f);
+    _left_factor_y = (height - 1.0f) / (lut_h - 1.0f);
+
+    _right_factor_x = _left_factor_x;
+    _right_factor_y = _left_factor_y;
+
+    return true;
+}
+
+bool
+SoftDualConstGeoMapper::init_factors ()
+{
+    Float2 left_factors, right_factors;
+    get_left_factors (left_factors.x, left_factors.y);
+    get_right_factors (right_factors.x, right_factors.y);
+    if (!XCAM_DOUBLE_EQUAL_AROUND (left_factors.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (left_factors.y, 0.0f) &&
+            !XCAM_DOUBLE_EQUAL_AROUND (right_factors.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (right_factors.y, 0.0f))
+        return true;
+
+    SmartPtr<Float2Image> lookup_table = get_lookup_table ();
+    XCAM_ASSERT (lookup_table.ptr ());
+
+    return auto_calculate_factors (lookup_table->get_width (), lookup_table->get_height ());
+}
+
+SmartPtr<XCamSoftTasks::GeoMapTask>
+SoftDualConstGeoMapper::create_remap_task ()
+{
+    SmartPtr<XCamSoftTasks::GeoMapTask> map_task =
+        new XCamSoftTasks::GeoMapDualConstTask (new CbGeoMapDualConstTask (this));
+    XCAM_ASSERT (map_task.ptr ());
+
+    return map_task;
+}
+
+XCamReturn
+SoftDualConstGeoMapper::prepare_arguments (
+    const SmartPtr<Worker::Arguments> &base,
+    const SmartPtr<ImageHandler::Parameters> &param)
+{
+    SmartPtr<Float2Image> lookup_table = get_lookup_table ();
+    XCAM_ASSERT (lookup_table.ptr ());
+
+    SmartPtr<VideoBuffer> in_buf = param->in_buf, out_buf = param->out_buf;
+    SmartPtr<XCamSoftTasks::GeoMapDualConstTask::Args> args =
+        base.dynamic_cast_ptr<XCamSoftTasks::GeoMapDualConstTask::Args> ();
+    XCAM_ASSERT (args.ptr ());
+
+    Float2 factors;
+    get_left_factors (factors.x, factors.y);
+    args->left_factor = factors;
+    get_right_factors (factors.x, factors.y);
+    args->right_factor = factors;
+    args->in_luma = new UcharImage (in_buf, 0);
+    args->in_uv = new Uchar2Image (in_buf, 1);
+    args->out_luma = new UcharImage (out_buf, 0);
+    args->out_uv = new Uchar2Image (out_buf, 1);
+    args->lookup_table = lookup_table;
+
+    set_work_size (2, 2, args->out_luma->get_width (), args->out_luma->get_height ());
+
+    param->in_buf.release ();
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+SoftDualConstGeoMapper::start_remap_task (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    SmartPtr<XCamSoftTasks::GeoMapTask> map_task = get_map_task ();
+    XCAM_ASSERT (map_task.ptr ());
+
+    SmartPtr<XCamSoftTasks::GeoMapDualConstTask::Args> args =
+        new XCamSoftTasks::GeoMapDualConstTask::Args (param);
+    XCAM_ASSERT (args.ptr ());
+
+    prepare_arguments (args, param);
+
+    return map_task->work (args);
+}
+
+void
+SoftDualConstGeoMapper::remap_task_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_ASSERT (worker.ptr () == get_map_task().ptr ());
+
+    SmartPtr<XCamSoftTasks::GeoMapDualConstTask::Args> args =
+        base.dynamic_cast_ptr<XCamSoftTasks::GeoMapDualConstTask::Args> ();
+    XCAM_ASSERT (args.ptr ());
+
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    if (!check_work_continue (param, error))
+        return;
+
+    work_well_done (param, error);
+}
+
+SoftDualCurveGeoMapper::SoftDualCurveGeoMapper (const char *name)
+    : SoftDualConstGeoMapper (name)
+    , _scaled_height (0.0f)
+{
+}
+
+SoftDualCurveGeoMapper::~SoftDualCurveGeoMapper ()
+{
+}
+
+SmartPtr<XCamSoftTasks::GeoMapTask>
+SoftDualCurveGeoMapper::create_remap_task ()
+{
+    SmartPtr<XCamSoftTasks::GeoMapDualCurveTask> map_task =
+        new XCamSoftTasks::GeoMapDualCurveTask (new CbGeoMapDualCurveTask (this));
+    XCAM_ASSERT (map_task.ptr ());
+
+    map_task->set_scaled_height (_scaled_height);
+
+    float factor_x, factor_y;
+    get_left_factors (factor_x, factor_y);
+    map_task->set_left_std_factor (factor_x, factor_y);
+
+    get_right_factors (factor_x, factor_y);
+    map_task->set_right_std_factor (factor_x, factor_y);
+
+    return map_task;
+}
+
+XCamReturn
+SoftDualCurveGeoMapper::start_remap_task (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    SmartPtr<XCamSoftTasks::GeoMapTask> map_task = get_map_task ();
+    XCAM_ASSERT (map_task.ptr ());
+
+    SmartPtr<XCamSoftTasks::GeoMapDualCurveTask::Args> args =
+        new XCamSoftTasks::GeoMapDualCurveTask::Args (param);
+    XCAM_ASSERT (args.ptr ());
+
+    prepare_arguments (args, param);
+
+    return map_task->work (args);
+}
+
+void
+SoftDualCurveGeoMapper::remap_task_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (worker);
+    XCAM_ASSERT (worker.ptr () == get_map_task().ptr ());
+
+    SmartPtr<XCamSoftTasks::GeoMapDualCurveTask::Args> args =
+        base.dynamic_cast_ptr<XCamSoftTasks::GeoMapDualCurveTask::Args> ();
+    XCAM_ASSERT (args.ptr ());
+
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    if (!check_work_continue (param, error))
+        return;
+
+    work_well_done (param, error);
+}
+
 }
diff --git a/modules/soft/soft_geo_mapper.h b/modules/soft/soft_geo_mapper.h
index c0370d3..ef88f9f 100644
--- a/modules/soft/soft_geo_mapper.h
+++ b/modules/soft/soft_geo_mapper.h
@@ -30,13 +30,15 @@
 
 namespace XCamSoftTasks {
 class GeoMapTask;
+class GeoMapDualConstTask;
+class GeoMapDualCurveTask;
 };
 
 class SoftGeoMapper
     : public SoftHandler, public GeoMapper
 {
 public:
-    SoftGeoMapper (const char *name = "SoftGeoMap");
+    SoftGeoMapper (const char *name = "SoftGeoMapper");
     ~SoftGeoMapper ();
 
     bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height);
@@ -57,8 +59,18 @@
     XCamReturn configure_resource (const SmartPtr<Parameters> &param);
     XCamReturn start_work (const SmartPtr<Parameters> &param);
 
-private:
-    XCamReturn start_remap_task (const SmartPtr<ImageHandler::Parameters> &param);
+    void set_work_size (uint32_t thread_x, uint32_t thread_y, uint32_t luma_width, uint32_t luma_height);
+    SmartPtr<XCamSoftTasks::GeoMapTask> &get_map_task () {
+        return _map_task;
+    }
+    SmartPtr<Float2Image> &get_lookup_table () {
+        return _lookup_table;
+    }
+
+protected:
+    virtual bool init_factors ();
+    virtual SmartPtr<XCamSoftTasks::GeoMapTask> create_remap_task ();
+    virtual XCamReturn start_remap_task (const SmartPtr<ImageHandler::Parameters> &param);
 
 private:
     SmartPtr<XCamSoftTasks::GeoMapTask>   _map_task;
@@ -66,6 +78,64 @@
 };
 
 extern SmartPtr<SoftHandler> create_soft_geo_mapper ();
-}
 
+class SoftDualConstGeoMapper
+    : public SoftGeoMapper
+{
+public:
+    SoftDualConstGeoMapper (const char *name = "SoftDualConstGeoMapper");
+    ~SoftDualConstGeoMapper ();
+
+    bool set_left_factors (float x, float y);
+    void get_left_factors (float &x, float &y) {
+        x = _left_factor_x;
+        y = _left_factor_y;
+    }
+    bool set_right_factors (float x, float y);
+    void get_right_factors (float &x, float &y) {
+        x = _right_factor_x;
+        y = _right_factor_y;
+    }
+
+    virtual void remap_task_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error);
+
+protected:
+    XCamReturn prepare_arguments (const SmartPtr<Worker::Arguments> &args,
+        const SmartPtr<ImageHandler::Parameters> &param);
+    virtual bool auto_calculate_factors (uint32_t lut_w, uint32_t lut_h);
+
+protected:
+    virtual bool init_factors ();
+    virtual SmartPtr<XCamSoftTasks::GeoMapTask> create_remap_task ();
+    virtual XCamReturn start_remap_task (const SmartPtr<ImageHandler::Parameters> &param);
+
+private:
+    float        _left_factor_x, _left_factor_y;
+    float        _right_factor_x, _right_factor_y;
+};
+
+class SoftDualCurveGeoMapper
+    : public SoftDualConstGeoMapper
+{
+public:
+    SoftDualCurveGeoMapper (const char *name = "SoftDualCurveGeoMapper");
+    ~SoftDualCurveGeoMapper ();
+
+    void set_scaled_height (float scaled_height) {
+        _scaled_height = scaled_height;
+    }
+
+    virtual void remap_task_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &args, const XCamReturn error);
+
+private:
+    virtual SmartPtr<XCamSoftTasks::GeoMapTask> create_remap_task ();
+    virtual XCamReturn start_remap_task (const SmartPtr<ImageHandler::Parameters> &param);
+
+private:
+    float        _scaled_height;
+};
+
+}
 #endif //XCAM_SOFT_GEO_MAP_H
diff --git a/modules/soft/soft_geo_tasks_priv.cpp b/modules/soft/soft_geo_tasks_priv.cpp
index 8079352..59e8845 100644
--- a/modules/soft/soft_geo_tasks_priv.cpp
+++ b/modules/soft/soft_geo_tasks_priv.cpp
@@ -24,6 +24,100 @@
 
 namespace XCamSoftTasks {
 
+enum BoundState {
+    BoundInternal = 0,
+    BoundCritical,
+    BoundExternal
+};
+
+inline void check_bound (const uint32_t &img_w, const uint32_t &img_h, Float2 *in_pos,
+    const uint32_t &max_idx, BoundState &bound)
+{
+    if (in_pos[0].x >= 0.0f && in_pos[max_idx].x >= 0.0f && in_pos[0].x < img_w && in_pos[max_idx].x < img_w &&
+            in_pos[0].y >= 0.0f && in_pos[max_idx].y >= 0.0f && in_pos[0].y < img_h && in_pos[max_idx].y < img_h)
+        bound = BoundInternal;
+    else if ((in_pos[0].x < 0.0f && in_pos[max_idx].x < 0.0f) || (in_pos[0].x >= img_w && in_pos[max_idx].x >= img_w) ||
+             (in_pos[0].y < 0.0f && in_pos[max_idx].y < 0.0f) || (in_pos[0].y >= img_h && in_pos[max_idx].y >= img_h))
+        bound = BoundExternal;
+    else
+        bound = BoundCritical;
+}
+
+template <typename TypeT>
+inline void calc_critical_pixels (const uint32_t &img_w, const uint32_t &img_h, Float2 *in_pos,
+    const uint32_t &max_idx, const TypeT &zero_byte, TypeT *luma)
+{
+    for (uint32_t idx = 0; idx < max_idx; ++idx) {
+        if (in_pos[idx].x < 0.0f || in_pos[idx].x >= img_w || in_pos[idx].y < 0.0f || in_pos[idx].y >= img_h)
+            luma[idx] = zero_byte;
+    }
+}
+
+static void map_image (
+    const UcharImage *in_luma, const Uchar2Image *in_uv,
+    UcharImage *out_luma, Uchar2Image *out_uv, const Float2Image *lut,
+    const uint32_t &luma_w, const uint32_t &luma_h, const uint32_t &uv_w, const uint32_t &uv_h,
+    const uint32_t &x_idx, const uint32_t &y_idx, const uint32_t &out_x, const uint32_t &out_y,
+    const Float2 &first, const Float2 &step, const Uchar *zero_luma_byte, const Uchar2 *zero_uv_byte)
+{
+    Float2 lut_pos[8] = {
+        first, Float2(first.x + step.x, first.y),
+        Float2(first.x + step.x * 2, first.y), Float2(first.x + step.x * 3, first.y),
+        Float2(first.x + step.x * 4, first.y), Float2(first.x + step.x * 5, first.y),
+        Float2(first.x + step.x * 6, first.y), Float2(first.x + step.x * 7, first.y)
+    };
+
+    //1st-line luma
+    Float2 in_pos[8];
+    float  luma_value[8];
+    Uchar  luma_uc[8];
+    BoundState bound = BoundInternal;
+    lut->read_interpolate_array<Float2, 8> (lut_pos, in_pos);
+    check_bound (luma_w, luma_h, in_pos, 7, bound);
+    if (bound == BoundExternal)
+        out_luma->write_array_no_check<8> (out_x, out_y, zero_luma_byte);
+    else {
+        in_luma->read_interpolate_array<float, 8> (in_pos, luma_value);
+        convert_to_uchar_N<float, 8> (luma_value, luma_uc);
+        if (bound == BoundCritical)
+            calc_critical_pixels (luma_w, luma_h, in_pos, 8, zero_luma_byte[0], luma_uc);
+        out_luma->write_array_no_check<8> (out_x, out_y, luma_uc);
+    }
+
+    //4x1 UV
+    Float2 uv_value[4];
+    Uchar2 uv_uc[4];
+    in_pos[0] /= 2.0f;
+    in_pos[1] = in_pos[2] / 2.0f;
+    in_pos[2] = in_pos[4] / 2.0f;
+    in_pos[3] = in_pos[6] / 2.0f;
+    check_bound (uv_w, uv_h, in_pos, 3, bound);
+    if (bound == BoundExternal)
+        out_uv->write_array_no_check<4> (x_idx * 4, y_idx, zero_uv_byte);
+    else {
+        in_uv->read_interpolate_array<Float2, 4> (in_pos, uv_value);
+        convert_to_uchar2_N<Float2, 4> (uv_value, uv_uc);
+        if (bound == BoundCritical)
+            calc_critical_pixels (uv_w, uv_h, in_pos, 4, zero_uv_byte[0], uv_uc);
+        out_uv->write_array_no_check<4> (x_idx * 4, y_idx, uv_uc);
+    }
+
+    //2nd-line luma
+    lut_pos[0].y = lut_pos[1].y = lut_pos[2].y = lut_pos[3].y = lut_pos[4].y = lut_pos[5].y =
+                                  lut_pos[6].y = lut_pos[7].y = first.y + step.y;
+    lut->read_interpolate_array<Float2, 8> (lut_pos, in_pos);
+    check_bound (luma_w, luma_h, in_pos, 7, bound);
+    if (bound == BoundExternal)
+        out_luma->write_array_no_check<8> (out_x, out_y + 1, zero_luma_byte);
+    else {
+        in_luma->read_interpolate_array<float, 8> (in_pos, luma_value);
+        convert_to_uchar_N<float, 8> (luma_value, luma_uc);
+        if (bound == BoundCritical)
+            calc_critical_pixels (luma_w, luma_h, in_pos, 8, zero_luma_byte[0], luma_uc);
+        out_luma->write_array_no_check<8> (out_x, out_y + 1, luma_uc);
+    }
+}
+
 XCamReturn
 GeoMapTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range)
 {
@@ -31,6 +125,7 @@
     static const Uchar2 zero_uv_byte[4] = {{128, 128}, {128, 128}, {128, 128}, {128, 128}};
     SmartPtr<GeoMapTask::Args> args = base.dynamic_cast_ptr<GeoMapTask::Args> ();
     XCAM_ASSERT (args.ptr ());
+
     UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr ();
     Uchar2Image *in_uv = args->in_uv.ptr (), *out_uv = args->out_uv.ptr ();
     Float2Image *lut = args->lookup_table.ptr ();
@@ -39,78 +134,246 @@
     XCAM_ASSERT (lut);
 
     Float2 factors = args->factors;
-    XCAM_ASSERT (
-        !XCAM_DOUBLE_EQUAL_AROUND (factors.x, 0.0f) &&
-        !XCAM_DOUBLE_EQUAL_AROUND (factors.y, 0.0f));
+    XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (factors.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factors.y, 0.0f));
+
+    Float2 step = Float2(1.0f, 1.0f) / factors;
 
     Float2 out_center ((out_luma->get_width () - 1.0f ) / 2.0f, (out_luma->get_height () - 1.0f ) / 2.0f);
     Float2 lut_center ((lut->get_width () - 1.0f) / 2.0f, (lut->get_height () - 1.0f) / 2.0f);
-    float x_step = 1.0f / factors.x;
-    float y_step = 1.0f / factors.y;
 
-#undef OUT_BOUND
-#define OUT_BOUND(image, first, last) \
-        (in_pos[first].x >= image->get_width ()) ||   \
-        (in_pos[first].y >= image->get_height ()) ||  \
-        (in_pos[last].x <= 0.0f) || (in_pos[last].y <= 0.0f)
+    uint32_t luma_w = in_luma->get_width ();
+    uint32_t luma_h = in_luma->get_height ();
+    uint32_t uv_w = in_uv->get_width ();
+    uint32_t uv_h = in_uv->get_height ();
 
     for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y)
         for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x)
         {
-            // calculate 8x2 luma, center aligned
-            Float2 in_pos[8];
-            float  luma_value[8];
-            Uchar  luma_uc[8];
             uint32_t out_x = x * 8, out_y = y * 2;
 
-            //1st-line luma
+            // calculate 8x2 luma, center aligned
             Float2 out_pos (out_x, out_y);
             out_pos -= out_center;
             Float2 first = out_pos / factors;
             first += lut_center;
-            Float2 lut_pos[8] = {
-                first, Float2(first.x + x_step, first.y),
-                Float2(first.x + x_step * 2, first.y), Float2(first.x + x_step * 3, first.y),
-                Float2(first.x + x_step * 4, first.y), Float2(first.x + x_step * 5, first.y),
-                Float2(first.x + x_step * 6, first.y), Float2(first.x + x_step * 7, first.y)
-            };
-            lut->read_interpolate_array<Float2, 8> (lut_pos, in_pos);
-            in_luma->read_interpolate_array<float, 8> (in_pos, luma_value);
-            convert_to_uchar_N<float, 8> (luma_value, luma_uc);
-            if (OUT_BOUND (in_luma, 0, 7))
-                out_luma->write_array_no_check<8> (out_x, out_y, zero_luma_byte);
-            else
-                out_luma->write_array_no_check<8> (out_x, out_y, luma_uc);
 
-            //4x1 UV
-            Float2  uv_value[4];
-            Uchar2  uv_uc[4];
-            in_pos[0] /= 2.0f;
-            in_pos[1] = in_pos[2] / 2.0f;
-            in_pos[2] = in_pos[4] / 2.0f;
-            in_pos[3] = in_pos[6] / 2.0f;
-            in_uv->read_interpolate_array<Float2, 4> (in_pos, uv_value);
-            convert_to_uchar2_N<Float2, 4> (uv_value, uv_uc);
-            if (OUT_BOUND (in_uv, 0, 3))
-                out_uv->write_array_no_check<4> (x * 4, y, zero_uv_byte);
-            else
-                out_uv->write_array_no_check<4> (x * 4, y, uv_uc);
-
-            //2nd-line luma
-            lut_pos[0].y = lut_pos[1].y = lut_pos[2].y = lut_pos[3].y = lut_pos[4].y = lut_pos[5].y =
-                                              lut_pos[6].y = lut_pos[7].y = first.y + y_step;
-            lut->read_interpolate_array<Float2, 8> (lut_pos, in_pos);
-            in_luma->read_interpolate_array<float, 8> (in_pos, luma_value);
-            convert_to_uchar_N<float, 8> (luma_value, luma_uc);
-            if (OUT_BOUND (in_luma, 0, 7))
-                out_luma->write_array_no_check<8> (out_x, out_y + 1, zero_luma_byte);
-            else
-                out_luma->write_array_no_check<8> (out_x, out_y + 1, luma_uc);
+            map_image (in_luma, in_uv, out_luma, out_uv, lut, luma_w, luma_h, uv_w, uv_h,
+                       x, y, out_x, out_y, first, step, zero_luma_byte, zero_uv_byte);
         }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+GeoMapDualConstTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range)
+{
+    static const Uchar zero_luma_byte[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+    static const Uchar2 zero_uv_byte[4] = {{128, 128}, {128, 128}, {128, 128}, {128, 128}};
+    SmartPtr<GeoMapDualConstTask::Args> args = base.dynamic_cast_ptr<GeoMapDualConstTask::Args> ();
+    XCAM_ASSERT (args.ptr ());
+
+    UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr ();
+    Uchar2Image *in_uv = args->in_uv.ptr (), *out_uv = args->out_uv.ptr ();
+    Float2Image *lut = args->lookup_table.ptr ();
+    XCAM_ASSERT (in_luma && in_uv);
+    XCAM_ASSERT (out_luma && out_uv);
+    XCAM_ASSERT (lut);
+
+    Float2 left_factor = args->left_factor;
+    Float2 right_factor = args->right_factor;
+    XCAM_ASSERT (
+        !XCAM_DOUBLE_EQUAL_AROUND (left_factor.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (left_factor.y, 0.0f) &&
+        !XCAM_DOUBLE_EQUAL_AROUND (right_factor.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (right_factor.y, 0.0f));
+
+    Float2 left_step = Float2(1.0f, 1.0f) / left_factor;
+    Float2 right_step = Float2(1.0f, 1.0f) / right_factor;
+
+    Float2 out_center ((out_luma->get_width () - 1.0f ) / 2.0f, (out_luma->get_height () - 1.0f ) / 2.0f);
+    Float2 lut_center ((lut->get_width () - 1.0f) / 2.0f, (lut->get_height () - 1.0f) / 2.0f);
+
+    uint32_t luma_w = in_luma->get_width ();
+    uint32_t luma_h = in_luma->get_height ();
+    uint32_t uv_w = in_uv->get_width ();
+    uint32_t uv_h = in_uv->get_height ();
+
+    for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y)
+        for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x)
+        {
+            uint32_t out_x = x * 8, out_y = y * 2;
+            Float2 &factor = (out_x + 4 < out_center.x) ? left_factor : right_factor;
+            Float2 &step = (out_x + 4 < out_center.x) ? left_step : right_step;
+
+            // calculate 8x2 luma, center aligned
+            Float2 out_pos (out_x, out_y);
+            out_pos -= out_center;
+            Float2 first = out_pos / factor;
+            first += lut_center;
+
+            map_image (in_luma, in_uv, out_luma, out_uv, lut, luma_w, luma_h, uv_w, uv_h,
+                       x, y, out_x, out_y, first, step, zero_luma_byte, zero_uv_byte);
+        }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+GeoMapDualCurveTask::GeoMapDualCurveTask (const SmartPtr<Worker::Callback> &cb)
+    : GeoMapDualConstTask (cb)
+    , _scaled_height (0.0f)
+    , _left_std_factor (0.0f, 0.0f)
+    , _right_std_factor (0.0f, 0.0f)
+    , _left_factors (NULL)
+    , _right_factors (NULL)
+    , _left_steps (NULL)
+    , _right_steps (NULL)
+{
+    set_work_uint (8, 2);
+}
+
+GeoMapDualCurveTask::~GeoMapDualCurveTask () {
+    if (_left_factors) {
+        delete [] _left_factors;
+        _left_factors = NULL;
+    }
+    if (_right_factors) {
+        delete [] _right_factors;
+        _right_factors = NULL;
+    }
+    if (_left_steps) {
+        delete [] _left_steps;
+        _left_steps = NULL;
+    }
+    if (_right_steps) {
+        delete [] _right_steps;
+        _right_steps = NULL;
+    }
+}
+
+void
+GeoMapDualCurveTask::set_left_std_factor (float x, float y) {
+    XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f));
+
+    _left_std_factor.x = x;
+    _left_std_factor.y = y;
+}
+
+void
+GeoMapDualCurveTask::set_right_std_factor (float x, float y) {
+    XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (y, 0.0f));
+
+    _right_std_factor.x = x;
+    _right_std_factor.y = y;
+}
+
+static void calc_cur_row_factor (
+    const uint32_t &y, const uint32_t &ym,
+    const Float2 &std_factor, const float &scaled_height,
+    const Float2 &factor, Float2 &cur_row_factor)
+{
+    float a, b, c;
+    a = (std_factor.x - factor.x) / ((scaled_height - ym) * (scaled_height - ym));
+    b = -2 * a * ym;
+    c = std_factor.x - a * scaled_height * scaled_height - b * scaled_height;
+    cur_row_factor.x = (y >= scaled_height) ? std_factor.x : ((y < ym) ? factor.x : (a * y * y + b * y + c));
+
+    cur_row_factor.y = factor.y;
+}
+
+void
+GeoMapDualCurveTask::set_factors (SmartPtr<GeoMapDualCurveTask::Args> args, uint32_t size) {
+    if (_left_factors == NULL) {
+        _left_factors = new Float2[size];
+        XCAM_ASSERT (_left_factors);
+    }
+    if (_right_factors == NULL) {
+        _right_factors = new Float2[size];
+        XCAM_ASSERT (_right_factors);
+    }
+
+    float ym = _scaled_height * 0.5f;
+    for (uint32_t y = 0; y < size; ++y) {
+        calc_cur_row_factor (y, ym, _left_std_factor, _scaled_height, args->left_factor, _left_factors[y]);
+        calc_cur_row_factor (y, ym, _right_std_factor, _scaled_height, args->right_factor, _right_factors[y]);
+    }
+}
+
+bool
+GeoMapDualCurveTask::set_steps (uint32_t size) {
+    if (_left_steps == NULL) {
+        _left_steps =  new Float2[size];
+        XCAM_ASSERT (_left_steps);
+    }
+    if (_right_steps == NULL) {
+        _right_steps =  new Float2[size];
+        XCAM_ASSERT (_right_steps);
+    }
+
+    for (uint32_t y = 0; y < size; ++y) {
+        XCAM_FAIL_RETURN (
+            ERROR,
+            !XCAM_DOUBLE_EQUAL_AROUND (_left_factors[y].x, 0.0f) &&
+            !XCAM_DOUBLE_EQUAL_AROUND (_left_factors[y].y, 0.0f) &&
+            !XCAM_DOUBLE_EQUAL_AROUND (_right_factors[y].x, 0.0f) &&
+            !XCAM_DOUBLE_EQUAL_AROUND (_right_factors[y].y, 0.0f),
+            false,
+            "GeoMapDualCurveTask invalid factor(row:%d): left_factor(x:%f, y:%f) right_factor(x:%f, y:%f)",
+            y, _left_factors[y].x, _left_factors[y].y, _right_factors[y].x, _right_factors[y].y);
+
+        _left_steps[y] = Float2(1.0f, 1.0f) / _left_factors[y];
+        _right_steps[y] = Float2(1.0f, 1.0f) / _right_factors[y];
+    }
+
+    return true;
+}
+
+XCamReturn
+GeoMapDualCurveTask::work_range (const SmartPtr<Arguments> &base, const WorkRange &range)
+{
+    static const Uchar zero_luma_byte[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+    static const Uchar2 zero_uv_byte[4] = {{128, 128}, {128, 128}, {128, 128}, {128, 128}};
+    SmartPtr<GeoMapDualCurveTask::Args> args = base.dynamic_cast_ptr<GeoMapDualCurveTask::Args> ();
+    XCAM_ASSERT (args.ptr ());
+    XCAM_ASSERT (
+        !XCAM_DOUBLE_EQUAL_AROUND (args->left_factor.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (args->left_factor.y, 0.0f) &&
+        !XCAM_DOUBLE_EQUAL_AROUND (args->right_factor.x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (args->right_factor.y, 0.0f));
+
+    UcharImage *in_luma = args->in_luma.ptr (), *out_luma = args->out_luma.ptr ();
+    Uchar2Image *in_uv = args->in_uv.ptr (), *out_uv = args->out_uv.ptr ();
+    Float2Image *lut = args->lookup_table.ptr ();
+    XCAM_ASSERT (in_luma && in_uv);
+    XCAM_ASSERT (out_luma && out_uv);
+    XCAM_ASSERT (lut);
+
+    set_factors (args, out_luma->get_height ());
+    set_steps (out_luma->get_height ());
+
+    Float2 out_center ((out_luma->get_width () - 1.0f ) / 2.0f, (out_luma->get_height () - 1.0f ) / 2.0f);
+    Float2 lut_center ((lut->get_width () - 1.0f) / 2.0f, (lut->get_height () - 1.0f) / 2.0f);
+
+    uint32_t luma_w = in_luma->get_width ();
+    uint32_t luma_h = in_luma->get_height ();
+    uint32_t uv_w = in_uv->get_width ();
+    uint32_t uv_h = in_uv->get_height ();
+
+    for (uint32_t y = range.pos[1]; y < range.pos[1] + range.pos_len[1]; ++y)
+        for (uint32_t x = range.pos[0]; x < range.pos[0] + range.pos_len[0]; ++x)
+        {
+            uint32_t out_x = x * 8, out_y = y * 2;
+            Float2 &factor = (out_x + 4 < out_center.x) ? _left_factors[out_y] : _right_factors[out_y];
+            Float2 &step = (out_x + 4 < out_center.x) ? _left_steps[out_y] : _right_steps[out_y];
+
+            // calculate 8x2 luma, center aligned
+            Float2 out_pos (out_x, out_y);
+            out_pos -= out_center;
+            Float2 first = out_pos / factor;
+            first += lut_center;
+
+            map_image (in_luma, in_uv, out_luma, out_uv, lut, luma_w, luma_h, uv_w, uv_h,
+                       x, y, out_x, out_y, first, step, zero_luma_byte, zero_uv_byte);
+        }
+
     return XCAM_RETURN_NO_ERROR;
 }
 
 }
 
 }
-
diff --git a/modules/soft/soft_geo_tasks_priv.h b/modules/soft/soft_geo_tasks_priv.h
index 36514b2..e1dc4d3 100644
--- a/modules/soft/soft_geo_tasks_priv.h
+++ b/modules/soft/soft_geo_tasks_priv.h
@@ -18,6 +18,9 @@
  * Author: Wind Yuan <feng.yuan@intel.com>
  */
 
+#ifndef XCAM_SOFT_GEO_TASKS_PRIV_H
+#define XCAM_SOFT_GEO_TASKS_PRIV_H
+
 #include <xcam_std.h>
 #include <soft/soft_worker.h>
 #include <soft/soft_image.h>
@@ -54,6 +57,73 @@
     virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range);
 };
 
+class GeoMapDualConstTask
+    : public GeoMapTask
+{
+public:
+    struct Args : GeoMapTask::Args {
+        Float2    left_factor;
+        Float2    right_factor;
+
+        Args (
+            const SmartPtr<ImageHandler::Parameters> &param)
+            : GeoMapTask::Args (param)
+        {}
+    };
+
+public:
+    explicit GeoMapDualConstTask (const SmartPtr<Worker::Callback> &cb)
+        : GeoMapTask (cb)
+    {
+        set_work_uint (8, 2);
+    }
+
+private:
+    virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range);
+};
+
+class GeoMapDualCurveTask
+    : public GeoMapDualConstTask
+{
+public:
+    struct Args : GeoMapDualConstTask::Args {
+        Args (
+            const SmartPtr<ImageHandler::Parameters> &param)
+            : GeoMapDualConstTask::Args (param)
+        {}
+    };
+
+public:
+    explicit GeoMapDualCurveTask (const SmartPtr<Worker::Callback> &cb);
+    ~GeoMapDualCurveTask ();
+
+    void set_scaled_height (float scaled_height) {
+        XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (scaled_height, 0.0f));
+        _scaled_height = scaled_height;
+    }
+
+    void set_left_std_factor (float x, float y);
+    void set_right_std_factor (float x, float y);
+
+private:
+    void set_factors (SmartPtr<GeoMapDualCurveTask::Args> args, uint32_t size);
+    bool set_steps (uint32_t size);
+
+    virtual XCamReturn work_range (const SmartPtr<Arguments> &args, const WorkRange &range);
+
+    XCAM_DEAD_COPY (GeoMapDualCurveTask);
+
+private:
+    float        _scaled_height;
+    Float2       _left_std_factor;
+    Float2       _right_std_factor;
+    Float2       *_left_factors;
+    Float2       *_right_factors;
+    Float2       *_left_steps;
+    Float2       *_right_steps;
+};
+
 }
 
 }
+#endif // XCAM_SOFT_GEO_TASKS_PRIV_H
diff --git a/modules/soft/soft_handler.cpp b/modules/soft/soft_handler.cpp
index 6a81472..984fa66 100644
--- a/modules/soft/soft_handler.cpp
+++ b/modules/soft/soft_handler.cpp
@@ -82,8 +82,6 @@
 
 SoftHandler::SoftHandler (const char* name)
     : ImageHandler (name)
-    , _need_configure (true)
-    , _enable_allocator (true)
     , _wip_buf_count (0)
 {
 }
@@ -99,47 +97,29 @@
     return true;
 }
 
-bool
-SoftHandler::set_out_video_info (const VideoBufferInfo &info)
+SmartPtr<BufferPool>
+SoftHandler::create_allocator ()
 {
-    XCAM_ASSERT (info.width && info.height && info.format);
-    _out_video_info = info;
-    return true;
-}
-
-bool
-SoftHandler::enable_allocator (bool enable)
-{
-    _enable_allocator = enable;
-    return true;
+    return new SoftVideoBufAllocator;
 }
 
 XCamReturn
-SoftHandler::confirm_configured ()
+SoftHandler::configure_rest ()
 {
     XCamReturn ret = XCAM_RETURN_NO_ERROR;
 
     XCAM_ASSERT (_need_configure);
-    if (_enable_allocator) {
-        XCAM_FAIL_RETURN (
-            ERROR, _out_video_info.is_valid (), XCAM_RETURN_ERROR_PARAM,
-            "soft_hander(%s) configure resource failed before reserver buffer since out video info was not set",
-            XCAM_STR (get_name ()));
-
-        set_allocator (new SoftVideoBufAllocator);
-        ret = reserve_buffers (_out_video_info, DEFAULT_SOFT_BUF_COUNT);
-        XCAM_FAIL_RETURN (
-            ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
-            "soft_hander(%s) configure resource failed in reserving buffers", XCAM_STR (get_name ()));
-    }
+    ret = ImageHandler::configure_rest ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "soft_hander(%s) configure reset failed on ImageHandler::configure_rest", XCAM_STR (get_name ()));
 
     if (_threads.ptr () && !_threads->is_running ()) {
         ret = _threads->start ();
         XCAM_FAIL_RETURN (
-            ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
-            "soft_hander(%s) configure resource failed when starting threads", XCAM_STR (get_name ()));
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "soft_hander(%s) configure reset failed when starting threads", XCAM_STR (get_name ()));
     }
-    _need_configure = false;
 
     return ret;
 }
@@ -148,7 +128,6 @@
 SoftHandler::execute_buffer (const SmartPtr<ImageHandler::Parameters> &param, bool sync)
 {
     XCamReturn ret = XCAM_RETURN_NO_ERROR;
-    SmartPtr<SyncMeta> sync_meta;
 
     XCAM_FAIL_RETURN (
         ERROR, param.ptr (), XCAM_RETURN_ERROR_PARAM,
@@ -161,10 +140,12 @@
             WARNING, xcam_ret_is_ok (ret), ret,
             "soft_hander(%s) configure resource failed", XCAM_STR (get_name ()));
 
-        ret = confirm_configured ();
+        ret = configure_rest ();
         XCAM_FAIL_RETURN (
             WARNING, xcam_ret_is_ok (ret), ret,
             "soft_hander(%s) confirm configure failed", XCAM_STR (get_name ()));
+
+        _need_configure = false;
     }
 
     if (!param->out_buf.ptr () && _enable_allocator) {
@@ -176,7 +157,7 @@
     }
 
     XCAM_ASSERT (!param->find_meta<SyncMeta> ().ptr ());
-    sync_meta = new SyncMeta ();
+    SmartPtr<SyncMeta> sync_meta = new SyncMeta ();
     XCAM_ASSERT (sync_meta.ptr ());
     param->add_meta (sync_meta);
 
diff --git a/modules/soft/soft_handler.h b/modules/soft/soft_handler.h
index e2041bf..460762a 100644
--- a/modules/soft/soft_handler.h
+++ b/modules/soft/soft_handler.h
@@ -57,8 +57,6 @@
     ~SoftHandler ();
 
     bool set_threads (const SmartPtr<ThreadPool> &pool);
-    bool set_out_video_info (const VideoBufferInfo &info);
-    bool enable_allocator (bool enable);
 
     // derive from ImageHandler
     virtual XCamReturn execute_buffer (const SmartPtr<Parameters> &param, bool sync);
@@ -66,8 +64,10 @@
     virtual XCamReturn terminate ();
 
 protected:
-    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param) = 0;
-    virtual XCamReturn start_work (const SmartPtr<Parameters> &param) = 0;
+    // derived from ImageHandler
+    virtual SmartPtr<BufferPool> create_allocator ();
+    virtual XCamReturn configure_rest ();
+
     //virtual SmartPtr<Worker::Arguments> get_first_worker_args (const SmartPtr<SoftWorker> &worker, SmartPtr<Parameters> &params) = 0;
     virtual void work_well_done (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
     virtual void work_broken (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
@@ -76,7 +76,6 @@
     bool check_work_continue (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
 
 private:
-    XCamReturn confirm_configured ();
     void param_ended (SmartPtr<ImageHandler::Parameters> param, XCamReturn err);
     static bool is_param_error (const SmartPtr<ImageHandler::Parameters> &param);
 
@@ -85,10 +84,7 @@
 
 private:
     SmartPtr<ThreadPool>    _threads;
-    VideoBufferInfo         _out_video_info;
     SmartPtr<SyncMeta>      _cur_sync;
-    bool                    _need_configure;
-    bool                    _enable_allocator;
     SafeList<Parameters>    _params;
     mutable std::atomic<int32_t>  _wip_buf_count;
 };
diff --git a/modules/soft/soft_stitcher.cpp b/modules/soft/soft_stitcher.cpp
index 42f0c93..f5189e1 100644
--- a/modules/soft/soft_stitcher.cpp
+++ b/modules/soft/soft_stitcher.cpp
@@ -31,7 +31,7 @@
 #define ENABLE_FEATURE_MATCH HAVE_OPENCV
 
 #if ENABLE_FEATURE_MATCH
-#include "cv_capi_feature_match.h"
+#include "ocv/cv_capi_feature_match.h"
 #ifndef ANDROID
 #include <opencv2/core/ocl.hpp>
 #endif
@@ -181,18 +181,24 @@
     XCamReturn stop ();
 
     XCamReturn fisheye_dewarp_to_table ();
-    XCamReturn feature_match (
-        const SmartPtr<VideoBuffer> &left_buf,
-        const SmartPtr<VideoBuffer> &right_buf,
-        const uint32_t idx);
+    XCamReturn start_feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, const uint32_t idx);
 
     bool get_and_reset_feature_match_factors (uint32_t idx, Factor &left, Factor &right);
 
 private:
+    SmartPtr<SoftGeoMapper> create_geo_mapper (const Stitcher::RoundViewSlice &view_slice);
+
     XCamReturn init_fisheye (uint32_t idx);
     bool init_dewarp_factors (uint32_t idx);
     XCamReturn create_copier (Stitcher::CopyArea area);
 
+    void calc_factors (
+        const uint32_t &idx, const Factor &last_left_factor, const Factor &last_right_factor,
+        Factor &cur_left, Factor &cur_right);
+
+    void init_feature_match (uint32_t idx);
+
 private:
     FisheyeDewarp           _fisheye [XCAM_STITCH_MAX_CAMERAS];
     Overlap                 _overlaps [XCAM_STITCH_MAX_CAMERAS];
@@ -205,6 +211,21 @@
     SoftStitcher           *_stitcher;
 };
 
+
+void
+StitcherImpl::calc_factors (
+    const uint32_t &idx, const Factor &last_left_factor, const Factor &last_right_factor,
+    Factor &cur_left, Factor &cur_right)
+{
+    Factor match_left_factor, match_right_factor;
+    get_and_reset_feature_match_factors (idx, match_left_factor, match_right_factor);
+
+    cur_left.x = last_left_factor.x * match_left_factor.x;
+    cur_left.y = last_left_factor.y * match_left_factor.y;
+    cur_right.x = last_right_factor.x * match_right_factor.x;
+    cur_right.y = last_right_factor.y * match_right_factor.y;
+}
+
 bool
 StitcherImpl::init_dewarp_factors (uint32_t idx)
 {
@@ -212,27 +233,39 @@
         ERROR, _fisheye[idx].dewarp.ptr (), false,
         "FisheyeDewarp dewarp handler empty");
 
-    Factor match_left_factor, match_right_factor;
-    get_and_reset_feature_match_factors (idx, match_left_factor, match_right_factor);
+    Factor last_left_factor, last_right_factor, cur_left, cur_right;
+    if (_stitcher->get_scale_mode () == ScaleSingleConst) {
+        Factor unify_factor;
+        _fisheye[idx].dewarp->get_factors (unify_factor.x, unify_factor.y);
+        if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started.
+            return true;
+        }
+        last_left_factor = last_right_factor = unify_factor;
 
-    Factor unify_factor, last_left_factor, last_right_factor;
-    _fisheye[idx].dewarp->get_factors (unify_factor.x, unify_factor.y);
-    last_left_factor = last_right_factor = unify_factor;
-    if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) ||
-            XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started.
-        return true;
+        calc_factors (idx, last_left_factor, last_right_factor, cur_left, cur_right);
+        unify_factor.x = (cur_left.x + cur_right.x) / 2.0f;
+        unify_factor.y = (cur_left.y + cur_right.y) / 2.0f;
+
+        _fisheye[idx].dewarp->set_factors (unify_factor.x, unify_factor.y);
+    } else {
+        SmartPtr<SoftDualConstGeoMapper> dewarp = _fisheye[idx].dewarp.dynamic_cast_ptr<SoftDualConstGeoMapper> ();
+        XCAM_ASSERT (dewarp.ptr ());
+        dewarp->get_left_factors (last_left_factor.x, last_left_factor.y);
+        dewarp->get_right_factors (last_right_factor.x, last_right_factor.y);
+        if (XCAM_DOUBLE_EQUAL_AROUND (last_left_factor.x, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (last_left_factor.y, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (last_right_factor.y, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (last_right_factor.y, 0.0f)) { // not started.
+            return true;
+        }
+
+        calc_factors (idx, last_left_factor, last_right_factor, cur_left, cur_right);
+
+        dewarp->set_left_factors (cur_left.x, cur_left.y);
+        dewarp->set_right_factors (cur_right.x, cur_right.y);
     }
 
-    Factor cur_left, cur_right;
-    cur_left.x = last_left_factor.x * match_left_factor.x;
-    cur_left.y = last_left_factor.y * match_left_factor.y;
-    cur_right.x = last_right_factor.x * match_right_factor.x;
-    cur_right.y = last_right_factor.y * match_right_factor.y;
-
-    unify_factor.x = (cur_left.x + cur_right.x) / 2.0f;
-    unify_factor.y = (cur_left.y + cur_right.y) / 2.0f;
-    _fisheye[idx].dewarp->set_factors (unify_factor.x, unify_factor.y);
-
     return true;
 }
 
@@ -280,17 +313,39 @@
     return true;
 }
 
+SmartPtr<SoftGeoMapper>
+StitcherImpl::create_geo_mapper (const Stitcher::RoundViewSlice &view_slice)
+{
+    SmartPtr<SoftGeoMapper> dewarp;
+    if (_stitcher->get_scale_mode () == ScaleSingleConst)
+        dewarp = new SoftGeoMapper ("sitcher_remapper");
+    else if (_stitcher->get_scale_mode () == ScaleDualConst)
+        dewarp = new SoftDualConstGeoMapper ("sitcher_dualconst_remapper");
+    else {
+        SmartPtr<SoftDualCurveGeoMapper> geomap = new SoftDualCurveGeoMapper ("sitcher_dualcurve_remapper");
+        XCAM_ASSERT (geomap.ptr ());
+
+        BowlDataConfig bowl = _stitcher->get_bowl_config ();
+        float scaled_height = (bowl.wall_height + bowl.ground_length / 2.0f) /
+                              (bowl.wall_height + bowl.ground_length) * view_slice.height;
+
+        geomap->set_scaled_height (scaled_height);
+        dewarp = geomap;
+    }
+
+    XCAM_ASSERT (dewarp.ptr ());
+    return dewarp;
+}
+
 XCamReturn
 StitcherImpl::init_fisheye (uint32_t idx)
 {
     FisheyeDewarp &fisheye = _fisheye[idx];
-    SmartPtr<ImageHandler::Callback> dewarp_cb = new CbGeoMap (_stitcher);
-    fisheye.dewarp = new SoftGeoMapper ("sitcher_remapper");
-    XCAM_ASSERT (fisheye.dewarp.ptr ());
-    fisheye.dewarp->set_callback (dewarp_cb);
+    Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (idx);
 
-    Stitcher::RoundViewSlice view_slice =
-        _stitcher->get_round_view_slice (idx);
+    SmartPtr<ImageHandler::Callback> dewarp_cb = new CbGeoMap (_stitcher);
+    fisheye.dewarp = create_geo_mapper (view_slice);;
+    fisheye.dewarp->set_callback (dewarp_cb);
 
     VideoBufferInfo buf_info;
     buf_info.init (
@@ -298,8 +353,9 @@
         XCAM_ALIGN_UP (view_slice.width, SOFT_STITCHER_ALIGNMENT_X),
         XCAM_ALIGN_UP (view_slice.height, SOFT_STITCHER_ALIGNMENT_Y));
 
-    fisheye.buf_pool = new SoftVideoBufAllocator (buf_info);
-    XCAM_ASSERT (fisheye.buf_pool.ptr ());
+    SmartPtr<BufferPool> pool = new SoftVideoBufAllocator (buf_info);
+    XCAM_ASSERT (pool.ptr ());
+    fisheye.buf_pool = pool;
     XCAM_FAIL_RETURN (
         ERROR, fisheye.buf_pool->reserve (2), XCAM_RETURN_ERROR_MEM,
         "stitcher:%s reserve dewarp buffer pool(w:%d,h:%d) failed",
@@ -329,6 +385,61 @@
     return XCAM_RETURN_NO_ERROR;
 }
 
+void
+StitcherImpl::init_feature_match (uint32_t idx)
+{
+#if ENABLE_FEATURE_MATCH
+
+#ifndef ANDROID
+    FeatureMatchMode fm_mode = _stitcher->get_fm_mode ();
+    if (fm_mode == FMNone)
+        return ;
+    else if (fm_mode == FMDefault)
+        _overlaps[idx].matcher = FeatureMatch::create_default_feature_match ();
+    else if (fm_mode == FMCluster)
+        _overlaps[idx].matcher = FeatureMatch::create_cluster_feature_match ();
+    else if (fm_mode == FMCapi)
+        _overlaps[idx].matcher = FeatureMatch::create_capi_feature_match ();
+    else {
+        XCAM_LOG_ERROR ("unsupported FeatureMatchMode: %d", fm_mode);
+        XCAM_ASSERT (false);
+    }
+#else
+    _overlaps[idx].matcher = new CVCapiFeatureMatch;
+#endif
+    XCAM_ASSERT (_overlaps[idx].matcher.ptr ());
+
+    FMConfig config;
+    config.sitch_min_width = 136;
+    config.min_corners = 4;
+    config.offset_factor = 0.8f;
+    config.delta_mean_offset = 120.0f;
+    config.recur_offset_error = 8.0f;
+    config.max_adjusted_offset = 24.0f;
+    config.max_valid_offset_y = 20.0f;
+    config.max_track_error = 28.0f;
+#ifdef ANDROID
+    config.max_track_error = 3600.0f;
+#endif
+    _overlaps[idx].matcher->set_config (config);
+    _overlaps[idx].matcher->set_fm_index (idx);
+
+    const BowlDataConfig bowl = _stitcher->get_bowl_config ();
+    const Stitcher::ImageOverlapInfo &info = _stitcher->get_overlap (idx);
+    Rect left_ovlap = info.left;
+    Rect right_ovlap = info.right;
+
+    left_ovlap.pos_y = 0;
+    left_ovlap.height = int32_t (bowl.wall_height / (bowl.wall_height + bowl.ground_length) * left_ovlap.height);
+    right_ovlap.pos_y = 0;
+    right_ovlap.height = left_ovlap.height;
+    _overlaps[idx].matcher->set_crop_rect (left_ovlap, right_ovlap);
+#else
+    XCAM_LOG_ERROR ("FeatureMatch unsupported");
+    XCAM_ASSERT (false);
+#endif
+}
+
 XCamReturn
 StitcherImpl::init_config (uint32_t count)
 {
@@ -342,23 +453,7 @@
             "stitcher:%s init fisheye failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i);
 
 #if ENABLE_FEATURE_MATCH
-        _overlaps[i].matcher = new CVCapiFeatureMatch;
-
-        CVFMConfig config;
-        config.sitch_min_width = 136;
-        config.min_corners = 4;
-        config.offset_factor = 0.8f;
-        config.delta_mean_offset = 120.0f;
-        config.recur_offset_error = 8.0f;
-        config.max_adjusted_offset = 24.0f;
-        config.max_valid_offset_y = 20.0f;
-#ifndef ANDROID
-        config.max_track_error = 28.0f;
-#else
-        config.max_track_error = 3600.0f;
-#endif
-        _overlaps[i].matcher->set_config (config);
-        _overlaps[i].matcher->set_fm_index (i);
+        init_feature_match (i);
 #endif
 
         _overlaps[i].blender = create_soft_blender ().dynamic_cast_ptr<SoftBlender>();
@@ -436,7 +531,7 @@
         _fisheye[i].dewarp->set_output_size (view_slice.width, view_slice.height);
         if (bowl.angle_end < bowl.angle_start)
             bowl.angle_start -= 360.0f;
-        XCAM_LOG_INFO (
+        XCAM_LOG_DEBUG (
             "soft-stitcher:%s camera(idx:%d) info (angle start:%.2f, range:%.2f), bowl info (angle start%.2f, end:%.2f)",
             XCAM_STR (_stitcher->get_name ()), i,
             view_slice.hori_angle_start, view_slice.hori_angle_range,
@@ -493,55 +588,6 @@
 }
 
 XCamReturn
-StitcherImpl::feature_match (
-    const SmartPtr<VideoBuffer> &left_buf,
-    const SmartPtr<VideoBuffer> &right_buf,
-    const uint32_t idx)
-{
-    const Stitcher::ImageOverlapInfo overlap_info = _stitcher->get_overlap (idx);
-    Rect left_ovlap = overlap_info.left;
-    Rect right_ovlap = overlap_info.right;
-    const VideoBufferInfo left_buf_info = left_buf->get_video_info ();
-
-    left_ovlap.pos_y = left_ovlap.height / 5;
-    left_ovlap.height = left_ovlap.height / 2;
-    right_ovlap.pos_y = right_ovlap.height / 5;
-    right_ovlap.height = right_ovlap.height / 2;
-
-    _overlaps[idx].matcher->reset_offsets ();
-    _overlaps[idx].matcher->optical_flow_feature_match (
-        left_buf, right_buf, left_ovlap, right_ovlap, left_buf_info.width);
-    float left_offsetx = _overlaps[idx].matcher->get_current_left_offset_x ();
-    Factor left_factor, right_factor;
-
-    uint32_t left_idx = idx;
-    float center_x = (float) _stitcher->get_center (left_idx).slice_center_x;
-    float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f);
-    float range = feature_center_x - center_x;
-    XCAM_ASSERT (range > 1.0f);
-    right_factor.x = (range + left_offsetx / 2.0f) / range;
-    right_factor.y = 1.0;
-    XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f);
-
-    uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num ();
-    center_x = (float) _stitcher->get_center (right_idx).slice_center_x;
-    feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f);
-    range = center_x - feature_center_x;
-    XCAM_ASSERT (range > 1.0f);
-    left_factor.x = (range + left_offsetx / 2.0f) / range;
-    left_factor.y = 1.0;
-    XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f);
-
-    {
-        SmartLock locker (_map_mutex);
-        _fisheye[left_idx].right_match_factor = right_factor;
-        _fisheye[right_idx].left_match_factor = left_factor;
-    }
-
-    return XCAM_RETURN_NO_ERROR;
-}
-
-XCamReturn
 StitcherImpl::start_single_blender (
     const uint32_t idx,
     const SmartPtr<BlenderParam> &param)
@@ -561,6 +607,53 @@
 }
 
 XCamReturn
+StitcherImpl::start_feature_match (
+    const SmartPtr<VideoBuffer> &left_buf,
+    const SmartPtr<VideoBuffer> &right_buf,
+    const uint32_t idx)
+{
+#if ENABLE_FEATURE_MATCH
+    _overlaps[idx].matcher->reset_offsets ();
+    _overlaps[idx].matcher->feature_match (left_buf, right_buf);
+
+    Rect left_ovlap, right_ovlap;
+    _overlaps[idx].matcher->get_crop_rect (left_ovlap, right_ovlap);
+
+    float left_offsetx = _overlaps[idx].matcher->get_current_left_offset_x ();
+    Factor left_factor, right_factor;
+
+    uint32_t left_idx = idx;
+    float center_x = (float) _stitcher->get_center (left_idx).slice_center_x;
+    float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f);
+    float range = feature_center_x - center_x;
+    XCAM_ASSERT (range > 1.0f);
+    right_factor.x = (range + left_offsetx / 2.0f) / range;
+    right_factor.y = 1.0f;
+    XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f);
+
+    uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num ();
+    center_x = (float) _stitcher->get_center (right_idx).slice_center_x;
+    feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f);
+    range = center_x - feature_center_x;
+    XCAM_ASSERT (range > 1.0f);
+    left_factor.x = (range + left_offsetx / 2.0f) / range;
+    left_factor.y = 1.0f;
+    XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f);
+
+    {
+        SmartLock locker (_map_mutex);
+        _fisheye[left_idx].right_match_factor = right_factor;
+        _fisheye[right_idx].left_match_factor = left_factor;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+#else
+    XCAM_LOG_ERROR ("FeatureMatch unsupported");
+    return XCAM_RETURN_ERROR_PARAM;
+#endif
+}
+
+XCamReturn
 StitcherImpl::start_overlap_tasks (
     const SmartPtr<SoftStitcher::StitcherParam> &param,
     const uint32_t idx, const SmartPtr<VideoBuffer> &buf)
@@ -606,20 +699,23 @@
 
 #if ENABLE_FEATURE_MATCH
     //start feature match
-    if (cur_param.ptr ()) {
-        ret = feature_match (cur_param->in_buf, cur_param->in1_buf, idx);
-        XCAM_FAIL_RETURN (
-            ERROR, xcam_ret_is_ok (ret), ret,
-            "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx);
-    }
+    if (_stitcher->get_fm_mode ()) {
+        if (cur_param.ptr ()) {
+            ret = start_feature_match (cur_param->in_buf, cur_param->in1_buf, idx);
+            XCAM_FAIL_RETURN (
+                ERROR, xcam_ret_is_ok (ret), ret,
+                "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx);
+        }
 
-    if (prev_param.ptr ()) {
-        ret = feature_match (prev_param->in_buf, prev_param->in1_buf, pre_idx);
-        XCAM_FAIL_RETURN (
-            ERROR, xcam_ret_is_ok (ret), ret,
-            "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx);
+        if (prev_param.ptr ()) {
+            ret = start_feature_match (prev_param->in_buf, prev_param->in1_buf, pre_idx);
+            XCAM_FAIL_RETURN (
+                ERROR, xcam_ret_is_ok (ret), ret,
+                "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx);
+        }
     }
 #endif
+
     return XCAM_RETURN_NO_ERROR;
 }
 
@@ -718,8 +814,10 @@
     : SoftHandler (name)
     , Stitcher (SOFT_STITCHER_ALIGNMENT_X, SOFT_STITCHER_ALIGNMENT_Y)
 {
-    _impl = new SoftSitcherPriv::StitcherImpl (this);
-    XCAM_ASSERT (_impl.ptr ());
+    SmartPtr<SoftSitcherPriv::StitcherImpl> impl = new SoftSitcherPriv::StitcherImpl (this);
+    XCAM_ASSERT (impl.ptr ());
+    _impl = impl;
+
 #if ENABLE_FEATURE_MATCH
 #ifndef ANDROID
     cv::ocl::setUseOpenCL (false);
@@ -801,7 +899,7 @@
     if (!check_work_continue (param, error))
         return;
 
-    XCAM_LOG_INFO ("soft-stitcher:%s camera(idx:%d) dewarp done", XCAM_STR (get_name ()), dewarp_param->idx);
+    XCAM_LOG_DEBUG ("soft-stitcher:%s camera(idx:%d) dewarp done", XCAM_STR (get_name ()), dewarp_param->idx);
     stitcher_dump_buf (dewarp_param->out_buf, dewarp_param->idx, "stitcher-dewarp");
 
     //start both blender and feature match
@@ -834,7 +932,7 @@
     }
 
     stitcher_dump_buf (blender_param->out_buf, blender_param->idx, "stitcher-blend");
-    XCAM_LOG_INFO ("blender:(%s) overlap:%d done", XCAM_STR (handler->get_name ()), blender_param->idx);
+    XCAM_LOG_DEBUG ("blender:(%s) overlap:%d done", XCAM_STR (handler->get_name ()), blender_param->idx);
 
     if (_impl->dec_task_count (param) == 0) {
         work_well_done (param, error);
@@ -859,7 +957,7 @@
         _impl->remove_task_count (param);
         return;
     }
-    XCAM_LOG_INFO ("soft-stitcher:%s camera(idx:%d) copy done", XCAM_STR (get_name ()), args->idx);
+    XCAM_LOG_DEBUG ("soft-stitcher:%s camera(idx:%d) copy done", XCAM_STR (get_name ()), args->idx);
 
     if (_impl->dec_task_count (param) == 0) {
         work_well_done (param, error);
diff --git a/modules/soft/soft_worker.cpp b/modules/soft/soft_worker.cpp
index 3a76345..9688155 100644
--- a/modules/soft/soft_worker.cpp
+++ b/modules/soft/soft_worker.cpp
@@ -103,8 +103,6 @@
 
 SoftWorker::SoftWorker (const char *name, const SmartPtr<Callback> &cb)
     : Worker (name, cb)
-    , _global (1, 1, 1)
-    , _local (1, 1, 1)
     , _work_unit (1, 1, 1)
 {
 }
@@ -136,30 +134,6 @@
     return true;
 }
 
-bool
-SoftWorker::set_global_size (const WorkSize &size)
-{
-    XCAM_FAIL_RETURN (
-        ERROR, size.value[0] && size.value[1] && size.value[2], false,
-        "SoftWorker(%s) set global size(x:%d, y:%d, z:%d) failed.",
-        XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]);
-
-    _global = size;
-    return true;
-}
-
-bool
-SoftWorker::set_local_size (const WorkSize &size)
-{
-    XCAM_FAIL_RETURN (
-        ERROR, size.value[0] && size.value[1] && size.value[2], false,
-        "SoftWorker(%s) set local size(x:%d, y:%d, z:%d) failed.",
-        XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]);
-
-    _local = size;
-    return true;
-}
-
 XCamReturn
 SoftWorker::stop ()
 {
@@ -172,14 +146,17 @@
 {
     XCamReturn ret = XCAM_RETURN_NO_ERROR;
 
-    XCAM_ASSERT (_local.value[0] * _local.value[1] * _local.value[2]);
-    XCAM_ASSERT (_global.value[0] * _global.value[1] * _global.value[2]);
+    const WorkSize &global = get_global_size ();
+    const WorkSize &local = get_local_size ();
+
+    XCAM_ASSERT (local.value[0] && local.value[1] && local.value[2]);
+    XCAM_ASSERT (global.value[0] && global.value[1] && global.value[2]);
 
     WorkSize items;
     uint32_t max_items = 1;
 
-    for (uint32_t i = 0; i < SOFT_MAX_DIM; ++i) {
-        items.value[i] = xcam_ceil (_global.value[i],  _local.value[i]) / _local.value[i];
+    for (uint32_t i = 0; i < WORK_MAX_DIM; ++i) {
+        items.value[i] = xcam_ceil (global.value[i],  local.value[i]) / local.value[i];
         max_items *= items.value[i];
     }
 
@@ -196,8 +173,10 @@
     if (!_threads.ptr ()) {
         char thr_name [XCAM_MAX_STR_SIZE];
         snprintf (thr_name, XCAM_MAX_STR_SIZE, "%s-thrs", XCAM_STR(get_name ()));
-        _threads = new ThreadPool (thr_name);
-        XCAM_ASSERT (_threads.ptr ());
+
+        SmartPtr<ThreadPool> threads = new ThreadPool (thr_name);
+        XCAM_ASSERT (threads.ptr ());
+        _threads = threads;
         _threads->set_threads (max_items, max_items + 1); //extra thread to process all_items_done
         ret = _threads->start ();
         XCAM_FAIL_RETURN (
@@ -236,13 +215,16 @@
 SoftWorker::get_range (const WorkSize &item)
 {
     WorkRange range;
-    for (uint32_t i = 0; i < SOFT_MAX_DIM; ++i) {
-        range.pos[i] = item.value[i] * _local.value[i];
-        XCAM_ASSERT (range.pos[i] < _global.value[i]);
-        if (range.pos[i] + _local.value[i] > _global.value[i])
-            range.pos_len[i] = _global.value[i] - range.pos[i];
+    const WorkSize &global = get_global_size ();
+    const WorkSize &local = get_local_size ();
+
+    for (uint32_t i = 0; i < WORK_MAX_DIM; ++i) {
+        range.pos[i] = item.value[i] * local.value[i];
+        XCAM_ASSERT (range.pos[i] < global.value[i]);
+        if (range.pos[i] + local.value[i] > global.value[i])
+            range.pos_len[i] = global.value[i] - range.pos[i];
         else
-            range.pos_len[i] = _local.value[i];
+            range.pos_len[i] = local.value[i];
     }
     return range;
 }
diff --git a/modules/soft/soft_worker.h b/modules/soft/soft_worker.h
index a851893..e734328 100644
--- a/modules/soft/soft_worker.h
+++ b/modules/soft/soft_worker.h
@@ -24,15 +24,13 @@
 #include <xcam_std.h>
 #include <worker.h>
 
-#define SOFT_MAX_DIM 3
-
 namespace XCam {
 
 class ThreadPool;
 
 struct WorkRange {
-    uint32_t pos[SOFT_MAX_DIM];
-    uint32_t pos_len[SOFT_MAX_DIM];
+    uint32_t pos[WORK_MAX_DIM];
+    uint32_t pos_len[WORK_MAX_DIM];
 
     WorkRange () {
         xcam_mem_clear (pos);
@@ -40,15 +38,6 @@
     }
 };
 
-struct WorkSize {
-    uint32_t value[SOFT_MAX_DIM];
-    WorkSize (uint32_t x = 1, uint32_t y = 1, uint32_t z = 1) {
-        value[0] = x;
-        value[1] = y;
-        value[2] = z;
-    }
-};
-
 //multi-thread worker
 class SoftWorker
     : public Worker
@@ -65,14 +54,6 @@
     }
 
     bool set_threads (const SmartPtr<ThreadPool> &threads);
-    bool set_global_size (const WorkSize &size);
-    const WorkSize &get_global_size () const {
-        return _global;
-    }
-    bool set_local_size (const WorkSize &size);
-    const WorkSize &get_local_size () const {
-        return _local;
-    }
 
     // derived from Worker
     virtual XCamReturn work (const SmartPtr<Arguments> &args);
@@ -91,8 +72,6 @@
 
 private:
     SmartPtr<ThreadPool>    _threads;
-    WorkSize                _global;
-    WorkSize                _local;
     WorkSize                _work_unit;
 };
 
diff --git a/modules/vulkan/Makefile.am b/modules/vulkan/Makefile.am
new file mode 100644
index 0000000..22763f0
--- /dev/null
+++ b/modules/vulkan/Makefile.am
@@ -0,0 +1,76 @@
+lib_LTLIBRARIES = libxcam_vulkan.la
+
+XCAM_VK_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)              \
+    $(LIBVULKAN_CFLAGS)           \
+    -I$(top_srcdir)/xcore         \
+    -I$(top_srcdir)/modules       \
+    -I$(top_builddir)/shaders/spv \
+    $(NULL)
+
+XCAM_VK_LIBS = \
+    $(LIBVULKAN_LIBS)                     \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
+
+if HAVE_OPENCV
+XCAM_VK_LIBS += $(top_builddir)/modules/ocv/libxcam_ocv.la
+endif
+
+xcam_vulkan_sources = \
+    vk_cmdbuf.cpp              \
+    vk_descriptor.cpp          \
+    vk_device.cpp              \
+    vk_handler.cpp             \
+    vk_instance.cpp            \
+    vk_memory.cpp              \
+    vk_pipeline.cpp            \
+    vk_shader.cpp              \
+    vk_sync.cpp                \
+    vk_video_buf_allocator.cpp \
+    vk_worker.cpp              \
+    vulkan_common.cpp          \
+    vk_copy_handler.cpp        \
+    vk_geomap_handler.cpp      \
+    vk_blender.cpp             \
+    vk_stitcher.cpp            \
+    $(NULL)
+
+libxcam_vulkan_la_SOURCES = \
+    $(xcam_vulkan_sources) \
+    $(NULL)
+
+libxcam_vulkan_la_CXXFLAGS = \
+    $(XCAM_VK_CXXFLAGS) \
+    $(NULL)
+
+libxcam_vulkan_la_LIBADD = \
+    $(XCAM_VK_LIBS) \
+    $(NULL)
+
+libxcam_vulkan_la_LDFLAGS = \
+    $(XCAM_LT_LDFLAGS) \
+    $(NULL)
+
+libxcam_vulkanincludedir = $(includedir)/xcam/vulkan
+
+nobase_libxcam_vulkaninclude_HEADERS = \
+    vk_cmdbuf.h              \
+    vk_descriptor.h          \
+    vk_device.h              \
+    vk_handler.h             \
+    vk_instance.h            \
+    vk_memory.h              \
+    vk_pipeline.h            \
+    vk_shader.h              \
+    vk_sync.h                \
+    vk_video_buf_allocator.h \
+    vk_worker.h              \
+    vulkan_common.h          \
+    vk_copy_handler.h        \
+    vk_geomap_handler.h      \
+    vk_blender.h             \
+    vk_stitcher.h            \
+    $(NULL)
+
+libxcam_vulkan_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/modules/vulkan/vk_blender.cpp b/modules/vulkan/vk_blender.cpp
new file mode 100644
index 0000000..f880649
--- /dev/null
+++ b/modules/vulkan/vk_blender.cpp
@@ -0,0 +1,1537 @@
+/*
+ * vk_blender.cpp - vulkan blender implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "xcam_utils.h"
+
+#include "vk_device.h"
+#include "vk_worker.h"
+#include "vk_blender.h"
+#include "vk_video_buf_allocator.h"
+
+#define DUMP_BUFFER 0
+
+#define GAUSS_RADIUS 2
+#define GAUSS_DIAMETER ((GAUSS_RADIUS)*2+1)
+
+const float gauss_coeffs[GAUSS_DIAMETER] = {0.152f, 0.222f, 0.252f, 0.222f, 0.152f};
+
+#define GS_SHADER_BINDING_COUNT          4
+#define LAP_SHADER_BINDING_COUNT         6
+#define BLEND_SHADER_BINDING_COUNT       7
+#define RECONSTRUCT_SHADER_BINDING_COUNT 9
+
+#define CHECK_RET(ret, format, ...) \
+    if (!xcam_ret_is_ok (ret)) { \
+        XCAM_LOG_ERROR (format, ## __VA_ARGS__); \
+    }
+
+#define DECLARE_VK_PUSH_CONST(PushConstClass, PushConstsProp) \
+    class PushConstClass : public VKConstRange::VKPushConstArg { \
+    private: PushConstsProp    _prop; \
+    public: \
+        PushConstClass (const PushConstsProp &prop) : _prop (prop) {} \
+        bool get_const_data (VkPushConstantRange &range, void *& ptr) { \
+            range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; \
+            range.offset = 0; \
+            range.size = sizeof (_prop); \
+            ptr = &_prop; \
+            return true; } \
+    }
+
+namespace XCam {
+
+#if DUMP_BUFFER
+static void
+dump_vkbuf_with_perfix (const SmartPtr<VKBuffer> &buf, const char *perfix_name)
+{
+    XCAM_ASSERT (buf.ptr ());
+    XCAM_ASSERT (perfix_name);
+
+    const VKBufInfo &info = buf->get_buf_info ();
+    char file_name[XCAM_VK_NAME_LENGTH];
+    snprintf (
+        file_name, XCAM_VK_NAME_LENGTH, "%s-%dx%d.%s",
+        perfix_name, info.width, info.height, xcam_fourcc_to_string (info.format));
+
+    FILE *fp = fopen (file_name, "wb");
+    if (!fp) {
+        XCAM_LOG_ERROR ( "vk-blend open file(%s) failed", file_name);
+    }
+
+    uint8_t *ptr = (uint8_t *)buf->map ();
+    for (uint32_t i = 0; i < info.height * 3 / 2; ++i) {
+        uint8_t *start = ptr + info.aligned_width * i;
+        fwrite (start, info.width, 1, fp);
+    }
+    buf->unmap ();
+    fclose (fp);
+}
+#define dump_vkbuf dump_vkbuf_with_perfix
+
+static void
+dump_level_vkbuf (const SmartPtr<VKBuffer> &buf, const char *name, uint32_t level, uint32_t idx)
+{
+    char file_name[XCAM_VK_NAME_LENGTH];
+    snprintf (file_name, XCAM_VK_NAME_LENGTH, "%s-L%d-Idx%d", name, level, idx);
+
+    dump_vkbuf_with_perfix (buf, file_name);
+}
+#endif
+
+namespace VKBlenderPriv {
+
+enum ShaderID {
+    ShaderGaussScalePyr = 0,
+    ShaderLapTransPyr,
+    ShaderBlendPyr,
+    ShaderReconstructPyr
+};
+
+static const VKShaderInfo shaders_info[] = {
+    VKShaderInfo (
+    "main",
+    std::vector<uint32_t> {
+#include "shader_gauss_scale_pyr.comp.spv"
+    }),
+    VKShaderInfo (
+    "main",
+    std::vector<uint32_t> {
+#include "shader_lap_trans_pyr.comp.spv"
+    }),
+    VKShaderInfo (
+    "main",
+    std::vector<uint32_t> {
+#include "shader_blend_pyr.comp.spv"
+    }),
+    VKShaderInfo (
+    "main",
+    std::vector<uint32_t> {
+#include "shader_reconstruct_pyr.comp.spv"
+    })
+};
+
+struct GaussScalePushConstsProp {
+    uint     in_img_width;
+    uint     in_img_height;
+    uint     in_offset_x;
+    uint     out_img_width;
+    uint     out_img_height;
+    uint     merge_width;
+
+    GaussScalePushConstsProp ()
+        : in_img_width (0)
+        , in_img_height (0)
+        , in_offset_x (0)
+        , out_img_width (0)
+        , out_img_height (0)
+        , merge_width (0)
+    {}
+};
+
+struct LapPushConstsProp {
+    uint     in_img_width;
+    uint     in_img_height;
+    uint     in_offset_x;
+    uint     gaussscale_img_width;
+    uint     gaussscale_img_height;
+    uint     merge_width;
+
+    LapPushConstsProp ()
+        : in_img_width (0)
+        , in_img_height (0)
+        , in_offset_x (0)
+        , gaussscale_img_width (0)
+        , gaussscale_img_height (0)
+        , merge_width (0)
+    {}
+};
+
+struct BlendPushConstsProp {
+    uint     in_img_width;
+
+    BlendPushConstsProp ()
+        : in_img_width (0)
+    {}
+};
+
+struct ReconstructPushConstsProp {
+    uint     lap_img_width;
+    uint     lap_img_height;
+    uint     out_img_width;
+    uint     out_offset_x;
+    uint     prev_blend_img_width;
+    uint     prev_blend_img_height;
+
+    ReconstructPushConstsProp ()
+        : lap_img_width (0)
+        , lap_img_height (0)
+        , out_img_width (0)
+        , out_offset_x (0)
+        , prev_blend_img_width (0)
+        , prev_blend_img_height (0)
+    {}
+};
+
+DECLARE_VK_PUSH_CONST (VKGaussScalePushConst, GaussScalePushConstsProp);
+DECLARE_VK_PUSH_CONST (VKLapPushConst, LapPushConstsProp);
+DECLARE_VK_PUSH_CONST (VKBlendPushConst, BlendPushConstsProp);
+DECLARE_VK_PUSH_CONST (VKReconstructPushConst, ReconstructPushConstsProp);
+
+DECLARE_WORK_CALLBACK (CbGaussScalePyr, VKBlender, gauss_scale_done);
+DECLARE_WORK_CALLBACK (CbLapTransPyr, VKBlender, lap_trans_done);
+DECLARE_WORK_CALLBACK (CbBlendPyr, VKBlender, blend_done);
+DECLARE_WORK_CALLBACK (CbReconstructPyr, VKBlender, reconstruct_done);
+
+class BlendArgs
+    : public VKWorker::VKArguments
+{
+public:
+    BlendArgs (uint32_t lv, VKBlender::BufIdx i = VKBlender::BufIdx0);
+
+    uint32_t get_level () {
+        return _level;
+    }
+    VKBlender::BufIdx get_idx () {
+        return _idx;
+    }
+
+private:
+    uint32_t             _level;
+    VKBlender::BufIdx    _idx;
+};
+
+struct PyrLayer {
+    uint32_t                                blend_width;
+    uint32_t                                blend_height;
+
+    SmartPtr<VKBlender::Sync>               lap_sync[VKBlender::BufIdxMax];
+    SmartPtr<VKBlender::Sync>               blend_sync;
+    SmartPtr<VKBlender::Sync>               reconstruct_sync;
+
+    SmartPtr<VKBuffer>                      gs_buf[VKBlender::BufIdxMax];
+    SmartPtr<VKBuffer>                      lap_buf[VKBlender::BufIdxMax];
+    SmartPtr<VKBuffer>                      mask;
+    SmartPtr<VKBuffer>                      blend_buf;
+    SmartPtr<VKBuffer>                      reconstruct_buf;
+
+    VKDescriptor::SetBindInfoArray          gs_bindings[VKBlender::BufIdxMax];
+    VKDescriptor::SetBindInfoArray          lap_bindings[VKBlender::BufIdxMax];
+    VKDescriptor::SetBindInfoArray          blend_bindings;
+    VKDescriptor::SetBindInfoArray          reconstruct_bindings;
+
+    SmartPtr<VKConstRange::VKPushConstArg>  gs_consts[VKBlender::BufIdxMax];
+    SmartPtr<VKConstRange::VKPushConstArg>  lap_consts[VKBlender::BufIdxMax];
+    SmartPtr<VKConstRange::VKPushConstArg>  blend_consts;
+    SmartPtr<VKConstRange::VKPushConstArg>  reconstruct_consts;
+
+    WorkSize                                gs_global_size[VKBlender::BufIdxMax];
+    WorkSize                                lap_global_size[VKBlender::BufIdxMax];
+    WorkSize                                blend_global_size;
+    WorkSize                                reconstruct_global_size;
+
+    VKWorker                               *gauss_scale[VKBlender::BufIdxMax];
+    VKWorker                               *lap_trans[VKBlender::BufIdxMax];
+    VKWorker                               *blend;
+    VKWorker                               *reconstruct;
+
+    PyrLayer ();
+};
+
+typedef std::map<ShaderID, SmartPtr<VKWorker>>    VKWorkers;
+
+class BlenderImpl {
+public:
+    PyrLayer                pyr_layer[XCAM_VK_MAX_LEVEL];
+    uint32_t                pyr_layers_num;
+
+private:
+    VKBlender              *_blender;
+    VKWorkers               _workers;
+
+public:
+    BlenderImpl (VKBlender *blender, uint32_t layers_num)
+        : pyr_layers_num (layers_num)
+        , _blender (blender)
+    {
+        XCAM_ASSERT (layers_num >= 2 && layers_num <= XCAM_VK_MAX_LEVEL);
+    }
+
+    XCamReturn start_gauss_scale (uint32_t level, VKBlender::BufIdx idx);
+    XCamReturn start_lap_trans (uint32_t level, VKBlender::BufIdx idx);
+    XCamReturn start_top_blend ();
+    XCamReturn start_reconstruct (uint32_t level);
+    XCamReturn stop ();
+
+    void init_syncs ();
+    XCamReturn init_layers_bufs (const SmartPtr<ImageHandler::Parameters> &base);
+    XCamReturn bind_io_bufs_to_layer0 (
+        SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output);
+    XCamReturn bind_io_vkbufs_to_desc ();
+    XCamReturn fix_parameters ();
+    XCamReturn create_workers (const SmartPtr<VKBlender> &blender);
+    XCamReturn redirect_workers ();
+
+private:
+    XCamReturn start_lap_tran (uint32_t level, VKBlender::BufIdx idx);
+
+    XCamReturn layer0_allocate_bufs (SmartPtr<VKDevice> dev);
+    XCamReturn layer0_init_mask (SmartPtr<VKDevice> dev);
+
+    XCamReturn layerx_allocate_bufs (SmartPtr<VKDevice> dev, uint32_t level);
+    XCamReturn allocate_vk_bufs (SmartPtr<VKDevice> dev, uint32_t level);
+    XCamReturn scale_down_mask (SmartPtr<VKDevice> dev, uint32_t level);
+
+    XCamReturn fix_gs_params (uint32_t level, VKBlender::BufIdx idx);
+    XCamReturn fix_lap_trans_params (uint32_t level, VKBlender::BufIdx idx);
+    XCamReturn fix_blend_params ();
+    XCamReturn fix_reconstruct_params (uint32_t level);
+};
+
+BlendArgs::BlendArgs (uint32_t lv, VKBlender::BufIdx i)
+    : _level (lv)
+    , _idx (i)
+{
+    XCAM_ASSERT (lv < XCAM_VK_DEFAULT_LEVEL);
+    XCAM_ASSERT (i < VKBlender::BufIdxMax);
+}
+
+PyrLayer::PyrLayer ()
+    : blend_width (0)
+    , blend_height (0)
+{
+}
+
+void
+BlenderImpl::init_syncs ()
+{
+    for (uint32_t i = 0; i < pyr_layers_num - 1; ++i) {
+        PyrLayer &layer = pyr_layer[i];
+
+        layer.lap_sync[VKBlender::BufIdx0] = new VKBlender::Sync (2);
+        XCAM_ASSERT (layer.lap_sync[VKBlender::BufIdx0].ptr ());
+        layer.lap_sync[VKBlender::BufIdx1] = new VKBlender::Sync (2);
+        XCAM_ASSERT (layer.lap_sync[VKBlender::BufIdx1].ptr ());
+
+        layer.reconstruct_sync = new VKBlender::Sync (3);
+        XCAM_ASSERT (layer.reconstruct_sync.ptr ());
+    }
+
+    pyr_layer[pyr_layers_num - 1].blend_sync = new VKBlender::Sync (2);
+    XCAM_ASSERT (pyr_layer[pyr_layers_num - 1].blend_sync.ptr ());
+}
+
+XCamReturn
+BlenderImpl::bind_io_bufs_to_layer0 (
+    SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output)
+{
+    XCAM_ASSERT (input0.ptr () && input1.ptr ());
+
+    SmartPtr<VKVideoBuffer> in0_vk = input0.dynamic_cast_ptr<VKVideoBuffer> ();
+    SmartPtr<VKVideoBuffer> in1_vk = input1.dynamic_cast_ptr<VKVideoBuffer> ();
+
+    PyrLayer &layer0 = pyr_layer[0];
+    layer0.gs_buf[VKBlender::BufIdx0] = in0_vk->get_vk_buf ();
+    layer0.gs_buf[VKBlender::BufIdx1] = in1_vk->get_vk_buf ();
+    XCAM_ASSERT (layer0.gs_buf[VKBlender::BufIdx0].ptr () && layer0.gs_buf[VKBlender::BufIdx1].ptr ());
+
+    if (!output.ptr ())
+        return XCAM_RETURN_NO_ERROR;
+
+    SmartPtr<VKVideoBuffer> out_vk = output.dynamic_cast_ptr<VKVideoBuffer> ();
+    XCAM_ASSERT (out_vk.ptr ());
+
+    layer0.reconstruct_buf = out_vk->get_vk_buf ();
+    XCAM_ASSERT (layer0.reconstruct_buf.ptr ());
+    layer0.blend_buf = layer0.reconstruct_buf;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::bind_io_vkbufs_to_desc ()
+{
+    PyrLayer &layer0 = pyr_layer[0];
+    PyrLayer &layer1 = pyr_layer[1];
+    XCAM_ASSERT (layer0.gs_buf[VKBlender::BufIdx0].ptr () && layer0.gs_buf[VKBlender::BufIdx1].ptr ());
+    XCAM_ASSERT (layer0.reconstruct_buf.ptr ());
+
+    VKDescriptor::SetBindInfoArray &gs_bindings0 = layer1.gs_bindings[VKBlender::BufIdx0];
+    VKDescriptor::SetBindInfoArray &gs_bindings1 = layer1.gs_bindings[VKBlender::BufIdx1];
+    gs_bindings0[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneYIdx);
+    gs_bindings0[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneUVIdx);
+    gs_bindings1[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneYIdx);
+    gs_bindings1[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneUVIdx);
+
+    VKDescriptor::SetBindInfoArray &lap_bindings0 = layer0.lap_bindings[VKBlender::BufIdx0];
+    VKDescriptor::SetBindInfoArray &lap_bindings1 = layer0.lap_bindings[VKBlender::BufIdx1];
+    lap_bindings0[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneYIdx);
+    lap_bindings0[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx0], NV12PlaneUVIdx);
+    lap_bindings1[0].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneYIdx);
+    lap_bindings1[1].desc = VKBufDesc (layer0.gs_buf[VKBlender::BufIdx1], NV12PlaneUVIdx);
+
+    layer0.reconstruct_bindings[4].desc = VKBufDesc (layer0.reconstruct_buf, NV12PlaneYIdx);
+    layer0.reconstruct_bindings[5].desc = VKBufDesc (layer0.reconstruct_buf, NV12PlaneUVIdx);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static void
+convert_to_vkinfo (const VideoBufferInfo &info, VKBufInfo &vk_info)
+{
+    vk_info.format = info.format;
+    vk_info.width = info.width;
+    vk_info.height = info.height;
+    vk_info.aligned_width = info.aligned_width;
+    vk_info.aligned_height = info.aligned_height;
+    vk_info.size = info.size;
+    vk_info.strides[0] = info.strides[0];
+    vk_info.strides[1] = info.strides[1];
+    vk_info.offsets[0] = info.offsets[0];
+    vk_info.offsets[1] = info.offsets[1];
+    vk_info.slice_size[0] = info.strides[0] * info.aligned_height;
+    vk_info.slice_size[1] = info.size - info.offsets[1];
+}
+
+XCamReturn
+BlenderImpl::layer0_allocate_bufs (SmartPtr<VKDevice> dev)
+{
+    if (pyr_layers_num == 1)
+        return XCAM_RETURN_NO_ERROR;
+
+    PyrLayer &layer0 = pyr_layer[0];
+    XCAM_FAIL_RETURN (
+        ERROR, layer0.blend_width && layer0.blend_height, XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid blend size:%dx%d", layer0.blend_width, layer0.blend_height);
+
+    VideoBufferInfo info;
+    info.init (
+        V4L2_PIX_FMT_NV12, layer0.blend_width, layer0.blend_height,
+        XCAM_ALIGN_UP (layer0.blend_width, VK_BLENDER_ALIGN_X),
+        XCAM_ALIGN_UP (layer0.blend_height, VK_BLENDER_ALIGN_X));
+
+    VKBufInfo vk_info;
+    convert_to_vkinfo (info, vk_info);
+
+    for (int idx = 0; idx < VKBlender::BufIdxMax; ++idx) {
+        layer0.lap_buf[idx] = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size);
+        XCAM_ASSERT (layer0.lap_buf[idx].ptr ());
+        layer0.lap_buf[idx]->set_buf_info (vk_info);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::allocate_vk_bufs (SmartPtr<VKDevice> dev, uint32_t level)
+{
+    XCAM_ASSERT (level >= 1 && level < pyr_layers_num);
+
+    PyrLayer &layer = pyr_layer[level];
+    VideoBufferInfo info;
+    info.init (
+        V4L2_PIX_FMT_NV12, layer.blend_width, layer.blend_height,
+        XCAM_ALIGN_UP (layer.blend_width, VK_BLENDER_ALIGN_X),
+        XCAM_ALIGN_UP (layer.blend_height, VK_BLENDER_ALIGN_X));
+
+    VKBufInfo vk_info;
+    convert_to_vkinfo (info, vk_info);
+
+    bool top_layer = (level == pyr_layers_num - 1);
+    for (int idx = 0; idx < VKBlender::BufIdxMax; ++idx) {
+        layer.gs_buf[idx] = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size);
+        XCAM_ASSERT (layer.gs_buf[idx].ptr ());
+        layer.gs_buf[idx]->set_buf_info (vk_info);
+
+        if (top_layer)
+            continue;
+
+        layer.lap_buf[idx] = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size);
+        XCAM_ASSERT (layer.lap_buf[idx].ptr ());
+        layer.lap_buf[idx]->set_buf_info (vk_info);
+    }
+
+    layer.reconstruct_buf = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, vk_info.size);
+    XCAM_ASSERT (layer.reconstruct_buf.ptr ());
+    layer.reconstruct_buf->set_buf_info (vk_info);
+
+    if (top_layer)
+        layer.blend_buf = layer.reconstruct_buf;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::layer0_init_mask (SmartPtr<VKDevice> dev)
+{
+    PyrLayer &layer = pyr_layer[0];
+    XCAM_ASSERT (layer.blend_width && ((layer.blend_width % VK_BLENDER_ALIGN_X) == 0));
+
+    uint32_t buf_size = layer.blend_width * sizeof (uint8_t);
+    SmartPtr<VKBuffer> buf = VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, buf_size);
+    XCAM_ASSERT (buf.ptr ());
+
+    VKBufInfo info;
+    info.width = layer.blend_width;
+    info.height = 1;
+    info.size = buf_size;
+    buf->set_buf_info (info);
+
+    std::vector<float> gauss_table;
+    uint32_t quater = info.width / 4;
+
+    get_gauss_table (quater, (quater + 1) / 4.0f, gauss_table, false);
+    for (uint32_t i = 0; i < gauss_table.size (); ++i) {
+        float value = ((i < quater) ? (128.0f * (2.0f - gauss_table[i])) : (128.0f * gauss_table[i]));
+        value = XCAM_CLAMP (value, 0.0f, 255.0f);
+        gauss_table[i] = value;
+    }
+
+    uint8_t *mask_ptr = (uint8_t *) buf->map (buf_size, 0);
+    XCAM_FAIL_RETURN (ERROR, mask_ptr, XCAM_RETURN_ERROR_PARAM, "vk-blend map range failed");
+
+    uint32_t gauss_start_pos = (info.width - gauss_table.size ()) / 2;
+    uint32_t idx = 0;
+    for (idx = 0; idx < gauss_start_pos; ++idx) {
+        mask_ptr[idx] = 255;
+    }
+    for (uint32_t i = 0; i < gauss_table.size (); ++idx, ++i) {
+        mask_ptr[idx] = (uint8_t) gauss_table[i];
+    }
+    for (; idx < info.width; ++idx) {
+        mask_ptr[idx] = 0;
+    }
+    buf->unmap ();
+
+    layer.mask = buf;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::scale_down_mask (SmartPtr<VKDevice> dev, uint32_t level)
+{
+    XCAM_ASSERT (level >= 1 && level < pyr_layers_num);
+
+    PyrLayer &layer = pyr_layer[level];
+    PyrLayer &prev_layer = pyr_layer[level - 1];
+
+    XCAM_ASSERT (prev_layer.mask.ptr ());
+    XCAM_ASSERT (layer.blend_width && ((layer.blend_width % VK_BLENDER_ALIGN_X) == 0));
+
+    uint32_t buf_size = layer.blend_width * sizeof (uint8_t);
+    SmartPtr<VKBuffer> buf =  VKBuffer::create_buffer (dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, buf_size);
+    XCAM_ASSERT (buf.ptr ());
+
+    VKBufInfo info;
+    info.width = layer.blend_width;
+    info.height = 1;
+    info.size = buf_size;
+    buf->set_buf_info (info);
+
+    const VKBufInfo prev_info = prev_layer.mask->get_buf_info ();
+    uint8_t *prev_ptr = (uint8_t *) prev_layer.mask->map (prev_info.size, 0);
+    XCAM_FAIL_RETURN (ERROR, prev_ptr, XCAM_RETURN_ERROR_PARAM, "vk-blend map range failed");
+
+    uint8_t *cur_ptr = (uint8_t *) buf->map (info.size, 0);
+    XCAM_FAIL_RETURN (ERROR, cur_ptr, XCAM_RETURN_ERROR_PARAM, "vk-blend map range failed");
+
+    for (uint32_t i = 0; i < info.width; ++i) {
+        int prev_start = i * 2 - 2;
+        float sum = 0.0f;
+
+        for (int j = 0; j < GAUSS_DIAMETER; ++j) {
+            int prev_idx = XCAM_CLAMP (prev_start + j, 0, (int)prev_info.width);
+            sum += prev_ptr[prev_idx] * gauss_coeffs[j];
+        }
+
+        cur_ptr[i] = XCAM_CLAMP (sum, 0.0f, 255.0f);
+    }
+
+    buf->unmap ();
+    prev_layer.mask->unmap ();
+
+    layer.mask = buf;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::layerx_allocate_bufs (SmartPtr<VKDevice> dev, uint32_t level)
+{
+    XCAM_ASSERT (level >= 1 && level < pyr_layers_num);
+
+    PyrLayer &layer = pyr_layer[level];
+    PyrLayer &prev_layer = pyr_layer[level - 1];
+    XCAM_FAIL_RETURN (
+        ERROR, prev_layer.blend_width && prev_layer.blend_height, XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid blend size:%dx%d", prev_layer.blend_width, prev_layer.blend_height);
+
+    layer.blend_width =  XCAM_ALIGN_UP ((prev_layer.blend_width + 1) / 2, VK_BLENDER_ALIGN_X);
+    layer.blend_height = XCAM_ALIGN_UP ((prev_layer.blend_height + 1) / 2, VK_BLENDER_ALIGN_Y);
+
+    XCamReturn ret = allocate_vk_bufs (dev, level);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend build vk buffers failed, level:%d", level);
+
+    ret = scale_down_mask (dev, level);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend scale down mask failed, level:%d", level);
+
+    return ret;
+}
+
+static XCamReturn
+check_desc (
+    const VideoBufferInfo &in0_info, const VideoBufferInfo &in1_info,
+    const Rect &merge0_area, const Rect &merge1_area)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        in0_info.width && in0_info.height && in1_info.width &&
+        in0_info.height == in1_info.height,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid buffer size: in0:%dx%d in1:%dx%d out:%dx%d",
+        in0_info.width, in0_info.height, in1_info.width, in1_info.height);
+
+    XCAM_FAIL_RETURN (
+        ERROR,
+        merge0_area.width && merge0_area.width == merge1_area.width &&
+        merge0_area.pos_y == 0 && merge1_area.pos_y == 0 &&
+        merge0_area.height == merge1_area.height && merge0_area.height == (int32_t)in0_info.height,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid merge area: merge0(%d, %d, %d, %d) merge1(%d, %d, %d, %d)",
+        merge0_area.pos_x, merge0_area.pos_y, merge0_area.width, merge0_area.height,
+        merge1_area.pos_x, merge1_area.pos_y, merge1_area.width, merge1_area.height);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::init_layers_bufs (const SmartPtr<ImageHandler::Parameters> &base)
+{
+    XCAM_ASSERT (base.ptr ());
+    SmartPtr<VKBlender::BlenderParam> param = base.dynamic_cast_ptr<VKBlender::BlenderParam> ();
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->in1_buf.ptr ());
+
+    const VideoBufferInfo &in0_info = param->in_buf->get_video_info ();
+    const VideoBufferInfo &in1_info = param->in1_buf->get_video_info ();
+    const Rect merge0_area = _blender->get_input_merge_area (VKBlender::BufIdx0);
+    const Rect merge1_area = _blender->get_input_merge_area (VKBlender::BufIdx1);
+
+    XCamReturn ret = check_desc (in0_info, in1_info, merge0_area, merge1_area);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend check desc failed");
+
+    PyrLayer &layer0 = pyr_layer[0];
+    layer0.blend_width = XCAM_ALIGN_UP (merge0_area.width, VK_BLENDER_ALIGN_X);
+    layer0.blend_height = XCAM_ALIGN_UP (merge0_area.height, VK_BLENDER_ALIGN_Y);
+
+    SmartPtr<VKDevice> dev = _blender->get_vk_device ();
+    XCAM_ASSERT (dev.ptr ());
+
+    ret = bind_io_bufs_to_layer0 (param->in_buf, param->in1_buf, param->out_buf);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend bind bufs to layer0 failed");
+    ret = layer0_allocate_bufs (dev);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend layer0 build buffers failed");
+    ret = layer0_init_mask (dev);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend layer0 init mask failed");
+
+    for (uint32_t level = 1; level < pyr_layers_num; ++level) {
+        layerx_allocate_bufs (dev, level);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "vk-blend build buffers failed, level:%d", level);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static SmartPtr<VKWorker>
+create_gauss_scale_pyr_shader (const SmartPtr<VKBlender> &blender)
+{
+    SmartPtr<VKDevice> dev = blender->get_vk_device ();
+    XCAM_ASSERT (dev.ptr ());
+
+    GaussScalePushConstsProp prop;
+    VKConstRange::VKPushConstArgs push_consts;
+    push_consts.push_back (new VKGaussScalePushConst (prop));
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < GS_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    SmartPtr<VKWorker> worker = new VKWorker (dev, "VKGaussScaleShader", new CbGaussScalePyr (blender));
+    XCAM_ASSERT (worker.ptr ());
+
+    XCamReturn ret = worker->build (shaders_info[ShaderGaussScalePyr], binding_layout, push_consts);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKGaussScaleShader failed");
+
+    return worker;
+}
+
+static SmartPtr<VKWorker>
+create_lap_trans_pyr_shader (const SmartPtr<VKBlender> &blender)
+{
+    SmartPtr<VKDevice> dev = blender->get_vk_device ();
+    XCAM_ASSERT (dev.ptr ());
+
+    LapPushConstsProp prop;
+    VKConstRange::VKPushConstArgs push_consts;
+    push_consts.push_back (new VKLapPushConst (prop));
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < LAP_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    SmartPtr<VKWorker> worker = new VKWorker (dev, "VKLapTransShader", new CbLapTransPyr (blender));
+    XCAM_ASSERT (worker.ptr ());
+
+    XCamReturn ret = worker->build (shaders_info[ShaderLapTransPyr], binding_layout, push_consts);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKLapTransShader failed");
+
+    return worker;
+}
+
+static SmartPtr<VKWorker>
+create_blend_pyr_shader (const SmartPtr<VKBlender> &blender)
+{
+    SmartPtr<VKDevice> dev = blender->get_vk_device ();
+    XCAM_ASSERT (dev.ptr ());
+
+    BlendPushConstsProp prop;
+    VKConstRange::VKPushConstArgs push_consts;
+    push_consts.push_back (new VKBlendPushConst (prop));
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < BLEND_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    SmartPtr<VKWorker> worker = new VKWorker (dev, "VKBlendPyrShader", new CbBlendPyr (blender));
+    XCAM_ASSERT (worker.ptr ());
+
+    XCamReturn ret = worker->build (shaders_info[ShaderBlendPyr], binding_layout, push_consts);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKBlendPyrShader failed");
+
+    return worker;
+}
+
+static SmartPtr<VKWorker>
+create_reconstruct_pyr_shader (const SmartPtr<VKBlender> &blender)
+{
+    SmartPtr<VKDevice> dev = blender->get_vk_device ();
+    XCAM_ASSERT (dev.ptr ());
+
+    ReconstructPushConstsProp prop;
+    VKConstRange::VKPushConstArgs push_consts;
+    push_consts.push_back (new VKReconstructPushConst (prop));
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < RECONSTRUCT_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    SmartPtr<VKWorker> worker = new VKWorker (dev, "VKReconstructShader", new CbReconstructPyr (blender));
+    XCAM_ASSERT (worker.ptr ());
+
+    XCamReturn ret = worker->build (shaders_info[ShaderReconstructPyr], binding_layout, push_consts);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), NULL, "vk-blend build VKReconstructShader failed");
+
+    return worker;
+}
+
+XCamReturn
+BlenderImpl::create_workers (const SmartPtr<VKBlender> &blender)
+{
+    XCAM_ASSERT (blender.ptr ());
+
+    VKWorkers::iterator i = _workers.find (ShaderGaussScalePyr);
+    if (i == _workers.end ()) {
+        SmartPtr<VKWorker> gauss_scale = create_gauss_scale_pyr_shader (blender);
+        XCAM_ASSERT (gauss_scale.ptr ());
+        _workers.insert (std::make_pair (ShaderGaussScalePyr, gauss_scale));
+    }
+
+    i = _workers.find (ShaderLapTransPyr);
+    if (i == _workers.end ()) {
+        SmartPtr<VKWorker> lap_trans = create_lap_trans_pyr_shader (blender);
+        XCAM_ASSERT (lap_trans.ptr ());
+        _workers.insert (std::make_pair (ShaderLapTransPyr, lap_trans));
+    }
+
+    i = _workers.find (ShaderBlendPyr);
+    if (i == _workers.end ()) {
+        SmartPtr<VKWorker> blend = create_blend_pyr_shader (blender);
+        XCAM_ASSERT (blend.ptr ());
+        _workers.insert (std::make_pair (ShaderBlendPyr, blend));
+    }
+
+    i = _workers.find (ShaderReconstructPyr);
+    if (i == _workers.end ()) {
+        SmartPtr<VKWorker> reconstruct = create_reconstruct_pyr_shader (blender);
+        XCAM_ASSERT (reconstruct.ptr ());
+        _workers.insert (std::make_pair (ShaderReconstructPyr, reconstruct));
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::redirect_workers ()
+{
+    VKWorkers::iterator i = _workers.find (ShaderGaussScalePyr);
+    XCAM_ASSERT (i != _workers.end ());
+    SmartPtr<VKWorker> gauss_scale = i->second;
+
+    i = _workers.find (ShaderLapTransPyr);
+    XCAM_ASSERT (i != _workers.end ());
+    SmartPtr<VKWorker> lap_trans = i->second;
+
+    i = _workers.find (ShaderBlendPyr);
+    XCAM_ASSERT (i != _workers.end ());
+    SmartPtr<VKWorker> top_blend = i->second;
+
+    i = _workers.find (ShaderReconstructPyr);
+    XCAM_ASSERT (i != _workers.end ());
+    SmartPtr<VKWorker> reconstruct = i->second;
+
+    XCAM_ASSERT (gauss_scale.ptr () && lap_trans.ptr () && reconstruct.ptr () && top_blend.ptr ());
+    for (uint32_t i = 0; i < pyr_layers_num - 1; ++i) {
+        PyrLayer &layer_next = pyr_layer[i + 1];
+        layer_next.gauss_scale[VKBlender::BufIdx0] = gauss_scale.ptr ();
+        layer_next.gauss_scale[VKBlender::BufIdx1] = gauss_scale.ptr ();
+
+        PyrLayer &layer = pyr_layer[i];
+        layer.lap_trans[VKBlender::BufIdx0] = lap_trans.ptr ();
+        layer.lap_trans[VKBlender::BufIdx1] = lap_trans.ptr ();
+        layer.reconstruct = reconstruct.ptr ();
+    }
+
+    PyrLayer &top_layer = pyr_layer[pyr_layers_num - 1];
+    top_layer.blend = top_blend.ptr ();
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::fix_parameters ()
+{
+    for (uint32_t i = 0; i < pyr_layers_num - 1; ++i) {
+        fix_gs_params (i + 1, VKBlender::BufIdx0);
+        fix_gs_params (i + 1, VKBlender::BufIdx1);
+
+        fix_lap_trans_params (i, VKBlender::BufIdx0);
+        fix_lap_trans_params (i, VKBlender::BufIdx1);
+
+        fix_reconstruct_params (i);
+    }
+
+    fix_blend_params ();
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::fix_gs_params (uint32_t level, VKBlender::BufIdx idx)
+{
+    XCAM_ASSERT (level >= 1);
+
+    uint32_t level_in = level - 1;
+    PyrLayer &layer_in = pyr_layer[level_in];
+    PyrLayer &layer_out = pyr_layer[level];
+    XCAM_ASSERT (layer_out.gs_buf[idx].ptr () && (layer_in.gs_buf[idx].ptr () || level == 1));
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < GS_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    VKDescriptor::SetBindInfoArray bindings (GS_SHADER_BINDING_COUNT);
+    bindings[0].layout = binding_layout[0];
+    bindings[1].layout = binding_layout[1];
+    if (layer_in.gs_buf[idx].ptr ()) {
+        bindings[0].desc = VKBufDesc (layer_in.gs_buf[idx], NV12PlaneYIdx);
+        bindings[1].desc = VKBufDesc (layer_in.gs_buf[idx], NV12PlaneUVIdx);
+    }
+    bindings[2].layout = binding_layout[2];
+    bindings[2].desc = VKBufDesc (layer_out.gs_buf[idx], NV12PlaneYIdx);
+    bindings[3].layout = binding_layout[3];
+    bindings[3].desc = VKBufDesc (layer_out.gs_buf[idx], NV12PlaneUVIdx);
+    layer_out.gs_bindings[idx] = bindings;
+
+    const VKBufInfo in_info = layer_in.gs_buf[idx]->get_buf_info ();
+    const VKBufInfo out_info = layer_out.gs_buf[idx]->get_buf_info ();
+
+    size_t unit_bytes = sizeof (uint32_t);
+    GaussScalePushConstsProp prop;
+    prop.in_img_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes;
+    prop.in_img_height = in_info.height;
+    prop.out_img_width = XCAM_ALIGN_UP (out_info.width, unit_bytes) / unit_bytes;
+    prop.out_img_height = out_info.height;
+    if (level == 1) {
+        const Rect area = _blender->get_input_merge_area (idx);
+        prop.in_offset_x = XCAM_ALIGN_UP (area.pos_x, unit_bytes) / unit_bytes;
+        prop.merge_width = XCAM_ALIGN_UP (area.width, unit_bytes) / unit_bytes;
+    } else {
+        prop.in_offset_x = 0;
+        prop.merge_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes;
+    }
+    layer_out.gs_consts[idx] = new VKGaussScalePushConst (prop);
+
+    layer_out.gs_global_size[idx] = WorkSize (
+        XCAM_ALIGN_UP (prop.out_img_width, 8) / 8,
+        XCAM_ALIGN_UP (out_info.height, 16) / 16);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::fix_lap_trans_params (uint32_t level, VKBlender::BufIdx idx)
+{
+    XCAM_ASSERT (level < pyr_layers_num - 1);
+
+    PyrLayer &layer = pyr_layer[level];
+    PyrLayer &layer_next = pyr_layer[level + 1];
+    XCAM_ASSERT ((layer.gs_buf[idx].ptr () || level == 0) && layer_next.gs_buf[idx].ptr ());
+    XCAM_ASSERT (layer.lap_buf[idx].ptr ());
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < LAP_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    VKDescriptor::SetBindInfoArray bindings (LAP_SHADER_BINDING_COUNT);
+    bindings[0].layout = binding_layout[0];
+    bindings[1].layout = binding_layout[1];
+    if (layer.gs_buf[idx].ptr ()) {
+        bindings[0].desc = VKBufDesc (layer.gs_buf[idx], NV12PlaneYIdx);
+        bindings[1].desc = VKBufDesc (layer.gs_buf[idx], NV12PlaneUVIdx);
+    }
+    bindings[2].layout = binding_layout[2];
+    bindings[2].desc = VKBufDesc (layer_next.gs_buf[idx], NV12PlaneYIdx);
+    bindings[3].layout = binding_layout[3];
+    bindings[3].desc = VKBufDesc (layer_next.gs_buf[idx], NV12PlaneUVIdx);
+    bindings[4].layout = binding_layout[4];
+    bindings[4].desc = VKBufDesc (layer.lap_buf[idx], NV12PlaneYIdx);
+    bindings[5].layout = binding_layout[5];
+    bindings[5].desc = VKBufDesc (layer.lap_buf[idx], NV12PlaneUVIdx);
+    layer.lap_bindings[idx] = bindings;
+
+    const VKBufInfo in_info = layer.gs_buf[idx]->get_buf_info ();
+    const VKBufInfo gs_info = layer_next.gs_buf[idx]->get_buf_info ();
+
+    size_t unit_bytes = sizeof (uint32_t) * 2;
+    LapPushConstsProp prop;
+    prop.in_img_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes;
+    prop.in_img_height = in_info.height;
+    prop.gaussscale_img_width = XCAM_ALIGN_UP (gs_info.width, sizeof (uint32_t)) / sizeof (uint32_t);
+    prop.gaussscale_img_height = gs_info.height;
+    if (level == 0) {
+        const Rect area = _blender->get_input_merge_area (idx);
+        prop.in_offset_x = XCAM_ALIGN_UP (area.pos_x, unit_bytes) / unit_bytes;
+        prop.merge_width = XCAM_ALIGN_UP (area.width, unit_bytes) / unit_bytes;
+    } else {
+        prop.in_offset_x = 0;
+        prop.merge_width = XCAM_ALIGN_UP (in_info.width, unit_bytes) / unit_bytes;
+    }
+    layer.lap_consts[idx] = new VKLapPushConst (prop);
+
+    layer.lap_global_size[idx] = WorkSize (
+        XCAM_ALIGN_UP (prop.merge_width, 8) / 8,
+        XCAM_ALIGN_UP (in_info.height, 32) / 32);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::fix_blend_params ()
+{
+    PyrLayer &top_layer = pyr_layer[pyr_layers_num - 1];
+    XCAM_ASSERT (top_layer.gs_buf[VKBlender::BufIdx0].ptr () && top_layer.gs_buf[VKBlender::BufIdx1].ptr ());
+    XCAM_ASSERT (top_layer.mask.ptr ());
+    XCAM_ASSERT (top_layer.blend_buf.ptr ());
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < BLEND_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    VKDescriptor::SetBindInfoArray bindings (BLEND_SHADER_BINDING_COUNT);
+    bindings[0].layout = binding_layout[0];
+    bindings[0].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx0], NV12PlaneYIdx);
+    bindings[1].layout = binding_layout[1];
+    bindings[1].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx0], NV12PlaneUVIdx);
+    bindings[2].layout = binding_layout[2];
+    bindings[2].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx1], NV12PlaneYIdx);
+    bindings[3].layout = binding_layout[3];
+    bindings[3].desc = VKBufDesc (top_layer.gs_buf[VKBlender::BufIdx1], NV12PlaneUVIdx);
+    bindings[4].layout = binding_layout[4];
+    bindings[4].desc = VKBufDesc (top_layer.blend_buf, NV12PlaneYIdx);
+    bindings[5].layout = binding_layout[5];
+    bindings[5].desc = VKBufDesc (top_layer.blend_buf, NV12PlaneUVIdx);
+    bindings[6].layout = binding_layout[6];
+    bindings[6].desc = VKBufDesc (top_layer.mask);
+    top_layer.blend_bindings = bindings;
+
+    const VKBufInfo in0_info = top_layer.gs_buf[VKBlender::BufIdx0]->get_buf_info ();
+    size_t unit_bytes = sizeof (uint32_t) * 2;
+    BlendPushConstsProp prop;
+    prop.in_img_width = XCAM_ALIGN_UP (in0_info.width, unit_bytes) / unit_bytes;
+    top_layer.blend_consts = new VKBlendPushConst (prop);
+
+    top_layer.blend_global_size = WorkSize (
+        XCAM_ALIGN_UP (prop.in_img_width, 8) / 8,
+        XCAM_ALIGN_UP (in0_info.height, 16) / 16);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::fix_reconstruct_params (uint32_t level)
+{
+    XCAM_ASSERT (level < pyr_layers_num - 1);
+
+    PyrLayer &layer = pyr_layer[level];
+    PyrLayer &prev_layer = pyr_layer[level + 1];
+
+    XCAM_ASSERT (layer.lap_buf[VKBlender::BufIdx0].ptr ());
+    XCAM_ASSERT (layer.lap_buf[VKBlender::BufIdx1].ptr ());
+    XCAM_ASSERT (prev_layer.reconstruct_buf.ptr () && (layer.reconstruct_buf.ptr () || level == 0));
+    XCAM_ASSERT (layer.mask.ptr ());
+
+    VKDescriptor::BindingArray binding_layout;
+    binding_layout.clear ();
+    for (int i = 0; i < RECONSTRUCT_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        binding_layout.push_back (binding);
+    }
+
+    VKDescriptor::SetBindInfoArray bindings (RECONSTRUCT_SHADER_BINDING_COUNT);
+    bindings[0].layout = binding_layout[0];
+    bindings[0].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx0], NV12PlaneYIdx);
+    bindings[1].layout = binding_layout[1];
+    bindings[1].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx0], NV12PlaneUVIdx);
+    bindings[2].layout = binding_layout[2];
+    bindings[2].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx1], NV12PlaneYIdx);
+    bindings[3].layout = binding_layout[3];
+    bindings[3].desc = VKBufDesc (layer.lap_buf[VKBlender::BufIdx1], NV12PlaneUVIdx);
+    bindings[4].layout = binding_layout[4];
+    bindings[5].layout = binding_layout[5];
+    if (layer.reconstruct_buf.ptr ()) {
+        bindings[4].desc = VKBufDesc (layer.reconstruct_buf, NV12PlaneYIdx);
+        bindings[5].desc = VKBufDesc (layer.reconstruct_buf, NV12PlaneUVIdx);
+    }
+    bindings[6].layout = binding_layout[6];
+    bindings[6].desc = VKBufDesc (prev_layer.reconstruct_buf, NV12PlaneYIdx);
+    bindings[7].layout = binding_layout[7];
+    bindings[7].desc = VKBufDesc (prev_layer.reconstruct_buf, NV12PlaneUVIdx);
+    bindings[8].layout = binding_layout[8];
+    bindings[8].desc = VKBufDesc (layer.mask);
+    layer.reconstruct_bindings = bindings;
+
+    const VKBufInfo lap0_info = layer.lap_buf[VKBlender::BufIdx0]->get_buf_info ();
+    const VKBufInfo prev_recons_info = prev_layer.reconstruct_buf->get_buf_info ();
+
+    size_t unit_bytes = sizeof (uint32_t) * 2;
+    ReconstructPushConstsProp prop;
+    prop.lap_img_width = XCAM_ALIGN_UP (lap0_info.width, unit_bytes) / unit_bytes;
+    prop.lap_img_height = lap0_info.height;
+    prop.prev_blend_img_width = XCAM_ALIGN_UP (prev_recons_info.width, sizeof (uint32_t)) / sizeof (uint32_t);
+    prop.prev_blend_img_height = prev_recons_info.height;
+    if (level == 0) {
+        const VideoBufferInfo info = _blender->get_out_video_info ();
+        prop.out_img_width = XCAM_ALIGN_UP (info.width, unit_bytes) / unit_bytes;
+
+        const Rect area = _blender->get_merge_window ();
+        prop.out_offset_x = XCAM_ALIGN_UP (area.pos_x, unit_bytes) / unit_bytes;
+    } else {
+        const VKBufInfo info = layer.reconstruct_buf->get_buf_info ();
+        prop.out_img_width = XCAM_ALIGN_UP (info.width, unit_bytes) / unit_bytes;
+        prop.out_offset_x = 0;
+    }
+    layer.reconstruct_consts = new VKReconstructPushConst (prop);
+
+    layer.reconstruct_global_size = WorkSize (
+        XCAM_ALIGN_UP (prop.lap_img_width, 8) / 8,
+        XCAM_ALIGN_UP (lap0_info.height, 32) / 32);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::start_gauss_scale (uint32_t level, VKBlender::BufIdx idx)
+{
+    XCAM_ASSERT (level >= 1 && level < pyr_layers_num);
+
+    PyrLayer &layer = pyr_layer[level];
+    layer.gauss_scale[idx]->set_global_size (layer.gs_global_size[idx]);
+
+    SmartPtr<BlendArgs> args = new BlendArgs (level, idx);
+    args->set_bindings (layer.gs_bindings[idx]);
+    args->add_push_const (layer.gs_consts[idx]);
+
+    return layer.gauss_scale[idx]->work (args);
+}
+
+XCamReturn
+BlenderImpl::start_lap_tran (uint32_t level, VKBlender::BufIdx idx)
+{
+    PyrLayer &layer = pyr_layer[level];
+
+    SmartPtr<VKBlender::Sync> &sync = layer.lap_sync[idx];
+    if (!sync->is_synced ())
+        return XCAM_RETURN_NO_ERROR;
+    sync->reset ();
+
+    layer.lap_trans[idx]->set_global_size (layer.lap_global_size[idx]);
+
+    SmartPtr<BlendArgs> args = new BlendArgs (level, idx);
+    args->set_bindings (layer.lap_bindings[idx]);
+    args->add_push_const (layer.lap_consts[idx]);
+
+    return layer.lap_trans[idx]->work (args);
+}
+
+XCamReturn
+BlenderImpl::start_lap_trans (uint32_t level, VKBlender::BufIdx idx)
+{
+    XCAM_ASSERT (level >= 1 && level < pyr_layers_num);
+
+    uint32_t pre_level = level - 1;
+    pyr_layer[pre_level].lap_sync[idx]->increment ();
+
+    XCamReturn ret = start_lap_tran (pre_level, idx);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-blend start lap tran failed, level:%d idx:%d", pre_level, idx);
+
+    if (level == pyr_layers_num - 1)
+        return XCAM_RETURN_NO_ERROR;
+    pyr_layer[level].lap_sync[idx]->increment ();
+
+    ret = start_lap_tran (level, idx);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-blend start lap tran failed, level:%d idx:%d", level, idx);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+BlenderImpl::start_top_blend ()
+{
+    uint32_t level = pyr_layers_num - 1;
+    PyrLayer &layer = pyr_layer[level];
+
+    SmartPtr<VKBlender::Sync> &sync = layer.blend_sync;
+    if (!sync->is_synced ())
+        return XCAM_RETURN_NO_ERROR;
+    sync->reset ();
+
+    SmartPtr<VKWorker::VKArguments> args = new VKWorker::VKArguments;
+    args->set_bindings (layer.blend_bindings);
+    args->add_push_const (layer.blend_consts);
+
+    layer.blend->set_global_size (layer.blend_global_size);
+
+    return layer.blend->work (args);
+}
+
+XCamReturn
+BlenderImpl::start_reconstruct (uint32_t level)
+{
+    XCAM_ASSERT (level < pyr_layers_num - 1);
+    PyrLayer &layer = pyr_layer[level];
+
+    SmartPtr<VKBlender::Sync> &sync = layer.reconstruct_sync;
+    if (!sync->is_synced ())
+        return XCAM_RETURN_NO_ERROR;
+    sync->reset ();
+
+    SmartPtr<BlendArgs> args = new BlendArgs (level);
+    args->set_bindings (layer.reconstruct_bindings);
+    args->add_push_const (layer.reconstruct_consts);
+
+    layer.reconstruct->set_global_size (layer.reconstruct_global_size);
+
+    return layer.reconstruct->work (args);
+}
+
+XCamReturn
+BlenderImpl::stop ()
+{
+    for (uint32_t lv = 0; lv < pyr_layers_num; ++lv) {
+        pyr_layer[lv].gs_buf[VKBlender::BufIdx0].release ();
+        pyr_layer[lv].gs_buf[VKBlender::BufIdx1].release ();
+        pyr_layer[lv].lap_buf[VKBlender::BufIdx0].release ();
+        pyr_layer[lv].lap_buf[VKBlender::BufIdx1].release ();
+        pyr_layer[lv].reconstruct_buf.release ();
+        pyr_layer[lv].blend_buf.release ();
+
+        pyr_layer[lv].gs_consts[VKBlender::BufIdx0].release ();
+        pyr_layer[lv].gs_consts[VKBlender::BufIdx1].release ();
+        pyr_layer[lv].lap_consts[VKBlender::BufIdx0].release ();
+        pyr_layer[lv].lap_consts[VKBlender::BufIdx1].release ();
+        pyr_layer[lv].reconstruct_consts.release ();
+        pyr_layer[lv].blend_consts.release ();
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
+
+VKBlender::VKBlender (const SmartPtr<VKDevice> dev, const char *name)
+    : VKHandler (dev, name)
+    , Blender (VK_BLENDER_ALIGN_X, VK_BLENDER_ALIGN_Y)
+{
+    SmartPtr<VKBlenderPriv::BlenderImpl> impl =
+        new VKBlenderPriv::BlenderImpl (this, XCAM_VK_DEFAULT_LEVEL);
+    XCAM_ASSERT (impl.ptr ());
+
+    _impl = impl;
+}
+
+VKBlender::~VKBlender ()
+{
+}
+
+XCamReturn
+VKBlender::blend (
+    const SmartPtr<VideoBuffer> &in0, const SmartPtr<VideoBuffer> &in1, SmartPtr<VideoBuffer> &out_buf)
+{
+    XCAM_ASSERT (in0.ptr () && in1.ptr ());
+
+    SmartPtr<BlenderParam> param = new BlenderParam (in0, in1, out_buf);
+    XCAM_ASSERT (param.ptr ());
+
+    XCamReturn ret = execute_buffer (param, true);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend execute buffer failed");
+
+    finish ();
+    if (!out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+static XCamReturn
+check_merge_area (const SmartPtr<VKBlender> &blender)
+{
+    Rect in0_area, in1_area, out_area;
+
+    in0_area = blender->get_input_merge_area (VKBlender::BufIdx0);
+    XCAM_FAIL_RETURN (
+        ERROR,
+        in0_area.pos_y == 0 && in0_area.width && in0_area.height &&
+        in0_area.pos_x % VK_BLENDER_ALIGN_X == 0 &&
+        in0_area.width % VK_BLENDER_ALIGN_X == 0 &&
+        in0_area.height % VK_BLENDER_ALIGN_Y == 0,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid input0 merge area, pos_x:%d, pos_y:%d, width:%d, height:%d",
+        in0_area.pos_x, in0_area.pos_y, in0_area.width, in0_area.height);
+
+    in1_area = blender->get_input_merge_area (VKBlender::BufIdx1);
+    XCAM_FAIL_RETURN (
+        ERROR,
+        in1_area.pos_y == 0 && in1_area.width && in1_area.height &&
+        in1_area.pos_x % VK_BLENDER_ALIGN_X == 0 &&
+        in1_area.width % VK_BLENDER_ALIGN_X == 0 &&
+        in1_area.height % VK_BLENDER_ALIGN_Y == 0,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid input1 merge area, pos_x:%d, pos_y:%d, width:%d, height:%d",
+        in1_area.pos_x, in1_area.pos_y, in1_area.width, in1_area.height);
+
+    out_area = blender->get_merge_window ();
+    XCAM_FAIL_RETURN (
+        ERROR,
+        out_area.pos_y == 0 && out_area.width && out_area.height &&
+        out_area.pos_x % VK_BLENDER_ALIGN_X == 0 &&
+        out_area.width % VK_BLENDER_ALIGN_X == 0 &&
+        out_area.height % VK_BLENDER_ALIGN_Y == 0,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid output merge area, pos_x:%d, pos_y:%d, width:%d, height:%d",
+        out_area.pos_x, out_area.pos_y, out_area.width, out_area.height);
+
+    XCAM_FAIL_RETURN (
+        ERROR,
+        in0_area.width == in1_area.width && in0_area.height == in1_area.height &&
+        in0_area.width == out_area.width && in0_area.height == out_area.height,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid input or output overlap area, input0:%dx%d, input1:%dx%d, output:%dx%d",
+        in0_area.width, in0_area.height, in1_area.width, in1_area.height, out_area.width, out_area.height);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKBlender::set_output_info (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    const VideoBufferInfo &in0_info = param->in_buf->get_video_info ();
+    XCAM_FAIL_RETURN (
+        ERROR, in0_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
+        "vk-blend only support NV12 format, but input format is %s",
+        xcam_fourcc_to_string (in0_info.format));
+
+    uint32_t out_width, out_height;
+    get_output_size (out_width, out_height);
+    XCAM_FAIL_RETURN (
+        ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
+        "vk-blend invalid output size:%dx%d", out_width, out_height);
+
+    VideoBufferInfo out_info;
+    out_info.init (
+        in0_info.format, out_width, out_height,
+        XCAM_ALIGN_UP (out_width, VK_BLENDER_ALIGN_X),
+        XCAM_ALIGN_UP (out_height, VK_BLENDER_ALIGN_Y));
+    set_out_video_info (out_info);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKBlender::configure_resource (const SmartPtr<Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr ());
+    XCAM_ASSERT (_impl->pyr_layers_num <= XCAM_VK_MAX_LEVEL);
+
+    SmartPtr<BlenderParam> blend_param = param.dynamic_cast_ptr<BlenderParam> ();
+    XCAM_ASSERT (blend_param.ptr () && blend_param->in_buf.ptr () && blend_param->in1_buf.ptr ());
+
+    XCamReturn ret = set_output_info (param);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend set output video info failed");
+
+    ret = check_merge_area (this);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend check merge area failed");
+
+    _impl->init_syncs ();
+
+    ret = _impl->init_layers_bufs (param);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend init buffers failed");
+
+    ret = _impl->fix_parameters ();
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend fix parameters failed");
+
+    ret = _impl->create_workers (this);
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend create workers failed");
+
+    ret = _impl->redirect_workers ();
+    XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), ret, "vk-blend redirect workers failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKBlender::start_work (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    SmartPtr<VKBlender::BlenderParam> blend_param = param.dynamic_cast_ptr<BlenderParam> ();
+    XCAM_ASSERT (blend_param.ptr ());
+    XCAM_ASSERT (blend_param->in_buf.ptr () && blend_param->in1_buf.ptr () && blend_param->out_buf.ptr ());
+
+#if DUMP_BUFFER
+    SmartPtr<VKVideoBuffer> in0_vk = blend_param->in_buf.dynamic_cast_ptr<VKVideoBuffer> ();
+    SmartPtr<VKVideoBuffer> in1_vk = blend_param->in1_buf.dynamic_cast_ptr<VKVideoBuffer> ();
+    XCAM_ASSERT (in0_vk.ptr () && in1_vk.ptr ());
+    dump_level_vkbuf (in0_vk->get_vk_buf (), "blend-in", 0, VKBlender::BufIdx0);
+    dump_level_vkbuf (in1_vk->get_vk_buf (), "blend-in", 0, VKBlender::BufIdx1);
+#endif
+
+    _impl->bind_io_bufs_to_layer0 (blend_param->in_buf, blend_param->in1_buf, blend_param->out_buf);
+    _impl->bind_io_vkbufs_to_desc ();
+
+    _impl->pyr_layer[0].lap_sync[BufIdx0]->increment ();
+    _impl->pyr_layer[0].lap_sync[BufIdx1]->increment ();
+
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+    ret = _impl->start_gauss_scale (1, BufIdx0);
+    CHECK_RET (ret, "vk-blend start gauss scale failed, level:1 index:0\n");
+
+    ret = _impl->start_gauss_scale (1, BufIdx1);
+    CHECK_RET (ret, "vk-blend start gauss scale failed, level:1 index:1\n");
+
+    execute_done (param, ret);
+
+    return ret;
+}
+
+void
+VKBlender::gauss_scale_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    if (!xcam_ret_is_ok (error)) {
+        XCAM_LOG_ERROR ("vk-blend gauss scale failed");
+        return ;
+    }
+
+    SmartPtr<VKBlenderPriv::BlendArgs> args = base.dynamic_cast_ptr<VKBlenderPriv::BlendArgs> ();
+    XCAM_ASSERT (args.ptr ());
+    uint32_t level = args->get_level ();
+    uint32_t next_level = level + 1;
+    BufIdx idx = args->get_idx ();
+
+    SmartPtr<VKWorker> gs_worker = worker.dynamic_cast_ptr<VKWorker> ();
+    XCAM_ASSERT (gs_worker.ptr ());
+    gs_worker->wait_fence ();
+
+#if DUMP_BUFFER
+    dump_level_vkbuf (_impl->pyr_layer[level].gs_buf[idx], "gauss-scale", level, idx);
+#endif
+
+    XCamReturn ret = _impl->start_lap_trans (level, idx);
+    CHECK_RET (ret, "vk-blend execute laplace transformation failed, level:%d idx:%d", level, idx);
+
+    if (next_level == _impl->pyr_layers_num) {
+        _impl->pyr_layer[level].blend_sync->increment ();
+
+        ret = _impl->start_top_blend ();
+        CHECK_RET (ret, "vk-blend execute top blend failed, level:%d idx:%d", level, idx);
+    } else {
+        ret = _impl->start_gauss_scale (next_level, idx);
+        CHECK_RET (ret, "vk-blend execute gauss scale failed, level:%d idx:%d", next_level, idx);
+    }
+}
+
+void
+VKBlender::lap_trans_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (base);
+    if (!xcam_ret_is_ok (error)) {
+        XCAM_LOG_ERROR ("vk-blend laplace transformation failed");
+        return ;
+    }
+
+    SmartPtr<VKBlenderPriv::BlendArgs> args = base.dynamic_cast_ptr<VKBlenderPriv::BlendArgs> ();
+    XCAM_ASSERT (args.ptr ());
+    uint32_t level = args->get_level ();
+
+    SmartPtr<VKWorker> laptrans_worker = worker.dynamic_cast_ptr<VKWorker> ();
+    XCAM_ASSERT (laptrans_worker.ptr ());
+    laptrans_worker->wait_fence ();
+
+#if DUMP_BUFFER
+    BufIdx idx = args->get_idx ();
+    dump_level_vkbuf (_impl->pyr_layer[level].lap_buf[idx], "lap", level, idx);
+#endif
+
+    _impl->pyr_layer[level].reconstruct_sync->increment ();
+
+    XCamReturn ret = _impl->start_reconstruct (level);
+    CHECK_RET (ret, "vk-blend execute reconstruct failed, level:%d", level);
+}
+
+void
+VKBlender::blend_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (base);
+    if (!xcam_ret_is_ok (error)) {
+        XCAM_LOG_ERROR ("vk-blend blend failed");
+        return ;
+    }
+
+    SmartPtr<VKWorker> blend_worker = worker.dynamic_cast_ptr<VKWorker> ();
+    XCAM_ASSERT (blend_worker.ptr ());
+    blend_worker->wait_fence ();
+
+#if DUMP_BUFFER
+    dump_vkbuf (_impl->pyr_layer[_impl->pyr_layers_num - 1].blend_buf, "blend-top");
+#endif
+
+    uint32_t pre_level = _impl->pyr_layers_num - 2;
+    _impl->pyr_layer[pre_level].reconstruct_sync->increment ();
+
+    XCamReturn ret = _impl->start_reconstruct (pre_level);
+    CHECK_RET (ret, "vk-blend execute reconstruct failed, level:%d", pre_level);
+}
+
+void
+VKBlender::reconstruct_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (base);
+    if (!xcam_ret_is_ok (error)) {
+        XCAM_LOG_ERROR ("vk-blend reconstruct failed");
+        return ;
+    }
+
+    SmartPtr<VKBlenderPriv::BlendArgs> args = base.dynamic_cast_ptr<VKBlenderPriv::BlendArgs> ();
+    XCAM_ASSERT (args.ptr ());
+    uint32_t level = args->get_level ();
+
+    SmartPtr<VKWorker> reconstruct_worker = worker.dynamic_cast_ptr<VKWorker> ();
+    XCAM_ASSERT (reconstruct_worker.ptr ());
+    reconstruct_worker->wait_fence ();
+
+#if DUMP_BUFFER
+    BufIdx idx = args->get_idx ();
+    dump_level_vkbuf (_impl->pyr_layer[level].reconstruct_buf, "reconstruct", level, idx);
+#endif
+
+    if (level == 0) {
+        return;
+    }
+
+    uint32_t pre_level = level - 1;
+    _impl->pyr_layer[pre_level].reconstruct_sync->increment ();
+
+    XCamReturn ret = _impl->start_reconstruct (pre_level);
+    CHECK_RET (ret, "vk-blend execute reconstruct failed, level:%d", pre_level);
+}
+
+SmartPtr<VKHandler>
+create_vk_blender (const SmartPtr<VKDevice> &dev)
+{
+    SmartPtr<VKBlender> blender = new VKBlender (dev);
+    XCAM_ASSERT (blender.ptr ());
+
+    return blender;
+}
+
+SmartPtr<Blender>
+Blender::create_vk_blender (const SmartPtr<VKDevice> &dev)
+{
+    SmartPtr<VKHandler> handler = XCam::create_vk_blender (dev);
+    return handler.dynamic_cast_ptr<Blender> ();
+}
+
+}
diff --git a/modules/vulkan/vk_blender.h b/modules/vulkan/vk_blender.h
new file mode 100644
index 0000000..223b48f
--- /dev/null
+++ b/modules/vulkan/vk_blender.h
@@ -0,0 +1,120 @@
+/*
+ * vk_blender.h - vulkan blender class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_VK_BLENDER_H
+#define XCAM_VK_BLENDER_H
+
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_handler.h>
+#include <interface/blender.h>
+
+#define VK_BLENDER_ALIGN_X 8
+#define VK_BLENDER_ALIGN_Y 4
+
+#define XCAM_VK_MAX_LEVEL 4
+#define XCAM_VK_DEFAULT_LEVEL 2
+
+namespace XCam {
+
+namespace VKBlenderPriv {
+class BlenderImpl;
+}
+
+class VKBlender
+    : public VKHandler, public Blender
+{
+    friend class VKBlenderPriv::BlenderImpl;
+    friend SmartPtr<VKHandler> create_vk_blender (const SmartPtr<VKDevice> &dev);
+
+public:
+    struct BlenderParam : ImageHandler::Parameters {
+        SmartPtr<VideoBuffer> in1_buf;
+
+        BlenderParam (
+            const SmartPtr<VideoBuffer> &in0,
+            const SmartPtr<VideoBuffer> &in1,
+            const SmartPtr<VideoBuffer> &out)
+            : Parameters (in0, out)
+            , in1_buf (in1)
+        {}
+    };
+
+    class Sync
+    {
+    public:
+         Sync (uint32_t threshold)
+            : _count (0), _threshold (threshold)
+        {}
+
+        void increment () {
+            ++_count;
+        }
+        void reset () {
+            _count = 0;
+        }
+        bool is_synced () {
+            return (_threshold == _count);
+        }
+
+    private:
+        uint32_t          _count;
+        const uint32_t    _threshold;
+    };
+
+    enum BufIdx {
+        BufIdx0    = 0,
+        BufIdx1,
+        BufIdxMax
+    };
+
+public:
+    ~VKBlender ();
+
+    void gauss_scale_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+    void lap_trans_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+    void blend_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+    void reconstruct_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+
+protected:
+    explicit VKBlender (const SmartPtr<VKDevice> dev, const char *name = "VKBlender");
+
+    // derived from Blender interface
+    XCamReturn blend (
+        const SmartPtr<VideoBuffer> &in0, const SmartPtr<VideoBuffer> &in1, SmartPtr<VideoBuffer> &out);
+
+    // derived from VKHandler
+    XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+    XCamReturn set_output_info (const SmartPtr<ImageHandler::Parameters> &param);
+
+private:
+    SmartPtr<VKBlenderPriv::BlenderImpl>    _impl;
+};
+
+extern SmartPtr<VKHandler> create_vk_blender (const SmartPtr<VKDevice> &dev);
+
+}
+
+#endif // XCAM_VK_BLENDER_H
diff --git a/modules/vulkan/vk_cmdbuf.cpp b/modules/vulkan/vk_cmdbuf.cpp
new file mode 100644
index 0000000..1bc33be
--- /dev/null
+++ b/modules/vulkan/vk_cmdbuf.cpp
@@ -0,0 +1,172 @@
+/*
+ * vk_cmdbuf.cpp - Vulkan command buffer
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_cmdbuf.h"
+#include "vulkan_common.h"
+#include "vk_pipeline.h"
+
+namespace XCam {
+
+VKCmdBuf::Pool::Pool (const SmartPtr<VKDevice> dev, VkCommandPool id)
+    : _pool_id (id)
+    , _dev (dev)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id));
+}
+
+VKCmdBuf::Pool::~Pool ()
+{
+    if (XCAM_IS_VALID_VK_ID (_pool_id))
+        _dev->destroy_cmd_pool (_pool_id);
+}
+
+SmartPtr<VKCmdBuf>
+VKCmdBuf::Pool::allocate_buffer ()
+{
+    //VkCommandBufferAllocateInfo info {};
+    VkCommandBuffer cmd_buf_id = _dev->allocate_cmd_buffer (_pool_id);
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (cmd_buf_id), NULL,
+        "VKCmdBuf allocate cmd buffer failed");
+    return new VKCmdBuf (this, cmd_buf_id);
+}
+
+void
+VKCmdBuf::Pool::free_buffer (VkCommandBuffer buf_id)
+{
+    XCAM_ASSERT (_dev.ptr ());
+    _dev->free_cmd_buffer (_pool_id, buf_id);
+}
+
+SmartPtr<VKCmdBuf::Pool>
+VKCmdBuf::create_pool (const SmartPtr<VKDevice> dev, VkFlags queue_flag)
+{
+    VkCommandPool pool_id = dev->create_cmd_pool (queue_flag);
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (pool_id), NULL,
+        "VKCmdBuf create_pool failed");
+    SmartPtr<VKCmdBuf::Pool> pool = new VKCmdBuf::Pool (dev, pool_id);
+    return pool;
+}
+
+SmartPtr<VKCmdBuf>
+VKCmdBuf::create_command_buffer (
+    const SmartPtr<VKDevice> dev,
+    const SmartPtr<VKCmdBuf::Pool> pool)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, dev.ptr (), NULL,
+        "VKCmdBuf create command buffer failed");
+
+    SmartPtr<VKCmdBuf::Pool> cmdbuf_pool = pool;
+    if (!pool.ptr()) {
+        cmdbuf_pool = create_pool (dev, VK_QUEUE_COMPUTE_BIT);
+    }
+
+    XCAM_FAIL_RETURN (
+        ERROR, cmdbuf_pool.ptr (), NULL,
+        "VKCmdBuf create command pool failed");
+
+    return cmdbuf_pool->allocate_buffer ();
+}
+
+VKCmdBuf::VKCmdBuf (const SmartPtr<VKCmdBuf::Pool> pool, VkCommandBuffer buf_id)
+    : _cmd_buf_id (buf_id)
+    , _pool (pool)
+{
+}
+
+VKCmdBuf::~VKCmdBuf ()
+{
+    if (_pool.ptr () && XCAM_IS_VALID_VK_ID (_cmd_buf_id))
+        _pool->free_buffer (_cmd_buf_id);
+}
+
+VKCmdBuf::DispatchParam::DispatchParam (const SmartPtr<VKPipeline> &p, uint32_t x, uint32_t y, uint32_t z)
+    : _group_size (x, y, z)
+    , _pipeline (p)
+{
+}
+
+VKCmdBuf::DispatchParam::~DispatchParam ()
+{
+}
+
+bool
+VKCmdBuf::DispatchParam::update_push_consts (VKConstRange::VKPushConstArgs & push_consts)
+{
+    _push_consts = push_consts;
+    return true;
+}
+
+XCamReturn
+VKCmdBuf::DispatchParam::fill_cmd_buf (VKCmdBuf &buf)
+{
+    XCamReturn ret = _pipeline->bind_by (buf);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret),
+        ret, "VKCmdBuf DispatchParam fill command buffer failed when binding pipeline");
+
+    for (size_t i = 0; i < _push_consts.size (); ++i) {
+        XCAM_RETURN_CHECK (
+            ERROR, _pipeline->push_consts_by (buf, _push_consts[i]),
+            "VKCmdBuf DispatchParam fill command buffer failed when push consts (:%d)", i);
+    }
+    return buf.dispatch (_group_size);
+}
+
+XCamReturn
+VKCmdBuf::record (const SmartPtr<DispatchParam> param)
+{
+    VkCommandBufferBeginInfo buf_begin_info = {};
+    buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    buf_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+    buf_begin_info.pInheritanceInfo = NULL;
+
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_cmd_buf_id));
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkBeginCommandBuffer (_cmd_buf_id, &buf_begin_info),
+        XCAM_RETURN_ERROR_VULKAN, "VKCmdBuf begin command buffer failed");
+
+    XCamReturn ret = param->fill_cmd_buf (*this);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret),
+        ret, "VKCmdBuf dispatch params failed");
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkEndCommandBuffer (_cmd_buf_id),
+        XCAM_RETURN_ERROR_VULKAN, "VKCmdBuf begin command buffer failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKCmdBuf::dispatch (const GroupSize &group)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, group.x * group.y * group.z > 0,
+        XCAM_RETURN_ERROR_VULKAN, "VKCmdBuf dispatch params failed");
+
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_cmd_buf_id));
+    vkCmdDispatch (_cmd_buf_id, group.x, group.y, group.z);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
diff --git a/modules/vulkan/vk_cmdbuf.h b/modules/vulkan/vk_cmdbuf.h
new file mode 100644
index 0000000..458bea3
--- /dev/null
+++ b/modules/vulkan/vk_cmdbuf.h
@@ -0,0 +1,106 @@
+/*
+ * vk_cmdbuf.h - Vulkan command buffer
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_CMD_BUF_H
+#define XCAM_VK_CMD_BUF_H
+
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_descriptor.h>
+#include <vulkan/vk_device.h>
+
+namespace XCam {
+
+class VKCmdBuf
+{
+public:
+    struct GroupSize {
+        uint32_t x;
+        uint32_t y;
+        uint32_t z;
+        GroupSize (uint32_t x_, uint32_t y_, uint32_t z_)
+            : x (x_)
+            , y (y_)
+            , z (z_)
+        {}
+    };
+
+    class DispatchParam {
+        friend class VKCmdBuf;
+    public:
+        DispatchParam (const SmartPtr<VKPipeline> &p, uint32_t x, uint32_t y = 1, uint32_t z = 1);
+        virtual ~DispatchParam ();
+        bool update_push_consts (VKConstRange::VKPushConstArgs & push_consts);
+    protected:
+        virtual XCamReturn fill_cmd_buf (VKCmdBuf &buf);
+        XCAM_DEAD_COPY (DispatchParam);
+
+    protected:
+        GroupSize                       _group_size;
+        const SmartPtr<VKPipeline>      _pipeline;
+        VKConstRange::VKPushConstArgs   _push_consts;
+    };
+
+    class Pool
+        : public RefObj
+    {
+        friend class VKCmdBuf;
+    public:
+        ~Pool ();
+        SmartPtr<VKCmdBuf> allocate_buffer ();
+        void free_buffer (VkCommandBuffer buf_id);
+
+    private:
+        explicit Pool (const SmartPtr<VKDevice> dev, VkCommandPool id);
+        XCAM_DEAD_COPY (Pool);
+    private:
+        VkCommandPool         _pool_id;
+        SmartPtr<VKDevice>    _dev;
+    };
+
+public:
+    static SmartPtr<VKCmdBuf>
+    create_command_buffer (const SmartPtr<VKDevice> dev, const SmartPtr<Pool> pool = NULL);
+    static SmartPtr<Pool> create_pool (const SmartPtr<VKDevice> dev, VkFlags queue_flag);
+    virtual ~VKCmdBuf ();
+
+    VkCommandBuffer get_cmd_buf_id () const {
+        return _cmd_buf_id;
+    }
+
+    XCamReturn record (const SmartPtr<DispatchParam> param);
+
+    // for fill_cmd_buf
+    XCamReturn dispatch (const GroupSize &group);
+
+protected:
+    explicit VKCmdBuf (const SmartPtr<Pool> pool, VkCommandBuffer buf_id);
+
+private:
+    XCAM_DEAD_COPY (VKCmdBuf);
+
+protected:
+    VkCommandBuffer                  _cmd_buf_id;
+
+    SmartPtr<Pool>                   _pool;
+};
+
+}
+
+#endif  //XCAM_VK_CMD_BUF_H
diff --git a/modules/vulkan/vk_copy_handler.cpp b/modules/vulkan/vk_copy_handler.cpp
new file mode 100644
index 0000000..4a89446
--- /dev/null
+++ b/modules/vulkan/vk_copy_handler.cpp
@@ -0,0 +1,270 @@
+/*
+ * vk_copy_handler.cpp - vulkan copy handler
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include <vulkan/vulkan_std.h>
+#include "vk_copy_handler.h"
+#include "vk_video_buf_allocator.h"
+#include "vk_shader.h"
+#include "vk_memory.h"
+#include "vk_worker.h"
+#include "vk_device.h"
+
+#define COPY_SHADER_BINDING_COUNT 2
+#define INVALID_INDEX (uint32_t)(-1)
+
+namespace XCam {
+
+namespace {
+
+DECLARE_WORK_CALLBACK (CbCopyShader, VKCopyHandler, copy_done);
+
+class CopyArgs
+    : public VKWorker::VKArguments
+{
+public:
+    explicit CopyArgs (const SmartPtr<ImageHandler::Parameters> &param)
+        : _param (param)
+    {
+        XCAM_ASSERT (param.ptr ());
+    }
+    const SmartPtr<ImageHandler::Parameters> &get_param () const {
+        return _param;
+    }
+
+private:
+    SmartPtr<ImageHandler::Parameters>    _param;
+};
+
+class VKCopyPushConst
+    : public VKConstRange::VKPushConstArg
+{
+public:
+    VKCopyPushConst (const VKCopyHandler::PushConstsProp &prop)
+        : _prop (prop)
+    {}
+
+    bool get_const_data (VkPushConstantRange &range, void *& ptr) {
+        range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+        range.offset = 0;
+        range.size = sizeof (_prop);
+        ptr = &_prop;
+        return true;
+    }
+
+private:
+    VKCopyHandler::PushConstsProp _prop;
+};
+
+};
+
+static const VKShaderInfo copy_shader_info (
+    "main",
+std::vector<uint32_t> {
+#include "shader_copy.comp.spv"
+});
+
+#if 0
+VKCopyArguments::VKCopyArguments (const SmartPtr<VKBuffer> in, SmartPtr<VKBuffer> out)
+    : _in_buf (in)
+    , _out_buf (out)
+{
+    XCAM_ASSERT (in.ptr());
+    XCAM_ASSERT (out.ptr());
+}
+
+XCamReturn
+VKCopyArguments::prepare_bindings (VKDescriptor::SetBindInfoArray &binding_array)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _in_buf.ptr () && _out_buf.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "VKCopyArguments input or output buffer is empty.");
+
+    binding_array.resize (2);
+    binding_array[0].layout = new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0);
+    binding_array[0].desc = VKBufDesc (_in_buf);
+
+    binding_array[0].layout = new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
+    binding_array[0].desc = VKBufDesc (_out_buf);
+    return XCAM_RETURN_NO_ERROR;
+}
+#endif
+
+VKCopyHandler::PushConstsProp::PushConstsProp ()
+    : in_img_width (0)
+    , in_x_offset (0)
+    , out_img_width (0)
+    , out_x_offset (0)
+    , copy_width (0)
+{
+}
+
+VKCopyHandler::VKCopyHandler (const SmartPtr<VKDevice> &dev, const char* name)
+    : VKHandler (dev, name)
+    , _index (INVALID_INDEX)
+{
+}
+
+bool
+VKCopyHandler::set_copy_area (uint32_t idx, const Rect &in_area, const Rect &out_area)
+{
+    XCAM_FAIL_RETURN (
+        ERROR,
+        idx != INVALID_INDEX &&
+        in_area.width && in_area.height &&
+        in_area.width == out_area.width && in_area.height == out_area.height,
+        false,
+        "VKCopyHandler(%s): set copy area(idx:%d) failed, input size:%dx%d output size:%dx%d",
+        XCAM_STR (get_name ()), idx, in_area.width, in_area.height, out_area.width, out_area.height);
+
+    _index = idx;
+    _in_area = in_area;
+    _out_area = out_area;
+
+    XCAM_LOG_DEBUG ("VKCopyHandler: copy area(idx:%d) input area(%d, %d, %d, %d) output area(%d, %d, %d, %d)",
+        idx,
+        in_area.pos_x, in_area.pos_y, in_area.width, in_area.height,
+        out_area.pos_x, out_area.pos_y, out_area.width, out_area.height);
+
+    return true;
+}
+
+#define UNIT_BYTES (4*sizeof(uint32_t))
+
+XCamReturn
+VKCopyHandler::configure_resource (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+    XCAM_ASSERT (param.ptr ());
+    XCAM_ASSERT (!_worker.ptr ());
+
+    XCAM_FAIL_RETURN (
+        ERROR, param->in_buf.ptr (), XCAM_RETURN_ERROR_VULKAN,
+        "VKCopyHandler(%s) param.in_buf is empty.", XCAM_STR (get_name ()));
+    XCAM_FAIL_RETURN (
+        ERROR, _index != INVALID_INDEX, XCAM_RETURN_ERROR_PARAM,
+        "VKCopyHandler(%s) invalid copy area, need set copy area first", XCAM_STR (get_name ()));
+
+    VideoBufferInfo in_info = param->in_buf->get_video_info ();
+    VideoBufferInfo out_info;
+    if (param->out_buf.ptr ())
+        out_info = param->out_buf->get_video_info ();
+    else
+        out_info = get_out_video_info ();
+    XCAM_FAIL_RETURN (
+        ERROR, out_info.is_valid (), XCAM_RETURN_ERROR_PARAM,
+        "VKCopyHandler(%s) invalid out info.", XCAM_STR (get_name ()));
+
+    _image_prop.in_img_width = in_info.aligned_width / UNIT_BYTES;
+    _image_prop.in_x_offset = _in_area.pos_x / UNIT_BYTES;
+    _image_prop.out_img_width = out_info.aligned_width / UNIT_BYTES;
+    _image_prop.out_x_offset = _out_area.pos_x / UNIT_BYTES;
+    _image_prop.copy_width = _in_area.width / UNIT_BYTES;
+    WorkSize global_size (
+        XCAM_ALIGN_UP (_image_prop.copy_width, 8 ) / 8,
+        XCAM_ALIGN_UP (_in_area.height * 3 / 2, 8 ) / 8);
+
+    _binding_layout.clear ();
+    for (int i = 0; i < COPY_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        _binding_layout.push_back (binding);
+    }
+
+    if (!_worker.ptr ()) {
+        _worker = new VKWorker(get_vk_device(), "CbCopyShader", new CbCopyShader (this));
+        XCAM_ASSERT (_worker.ptr());
+
+        _worker->set_global_size (global_size);
+
+        VKConstRange::VKPushConstArgs push_consts;
+        push_consts.push_back (new VKCopyPushConst (_image_prop));
+        ret = _worker->build (copy_shader_info, _binding_layout, push_consts);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_VULKAN,
+            "VKCopyHandler(%s) build copy shader failed.", XCAM_STR (get_name ()));
+    }
+
+    return ret;
+}
+
+XCamReturn
+VKCopyHandler::start_work (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (_binding_layout.size () == COPY_SHADER_BINDING_COUNT);
+    SmartPtr<VKVideoBuffer> in_vk = param->in_buf.dynamic_cast_ptr<VKVideoBuffer> ();
+    SmartPtr<VKVideoBuffer> out_vk = param->out_buf.dynamic_cast_ptr<VKVideoBuffer> ();
+
+    XCAM_FAIL_RETURN (
+        ERROR, in_vk.ptr () && out_vk.ptr(), XCAM_RETURN_ERROR_VULKAN,
+        "VKCopyHandler(%s) param.in_buf or param.out_buf is not vk buf.", XCAM_STR (get_name ()));
+
+    VKDescriptor::SetBindInfoArray bindings (_binding_layout.size ());
+    bindings[0].layout = _binding_layout[0];
+    bindings[0].desc = VKBufDesc (in_vk->get_vk_buf ());
+    bindings[1].layout = _binding_layout[1];
+    bindings[1].desc = VKBufDesc (out_vk->get_vk_buf ());
+
+    SmartPtr<CopyArgs> args = new CopyArgs (param);
+    args->set_bindings (bindings);
+    args->add_push_const (new VKCopyPushConst (_image_prop));
+    return _worker->work (args);
+}
+
+void
+VKCopyHandler::copy_done (
+    const SmartPtr<Worker> &worker,
+    const SmartPtr<Worker::Arguments> &base,
+    const XCamReturn error)
+{
+    if (!xcam_ret_is_ok (error)) {
+        XCAM_LOG_ERROR ("VKCopyHandler(%s) copy failed.", XCAM_STR (get_name ()));
+    }
+
+    SmartPtr<VKWorker> vk_worker = worker.dynamic_cast_ptr<VKWorker> ();
+    XCAM_ASSERT (vk_worker.ptr ());
+    vk_worker->wait_fence ();
+
+    SmartPtr<CopyArgs> args = base.dynamic_cast_ptr<CopyArgs> ();
+    XCAM_ASSERT (args.ptr ());
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+}
+
+XCamReturn
+VKCopyHandler::copy (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf)
+{
+    SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in_buf, out_buf);
+    XCAM_ASSERT (param.ptr ());
+
+    XCamReturn ret = execute_buffer (param, false);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "VKCopyHandler(%s) copy failed", XCAM_STR (get_name ()));
+
+    if (!out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+};
diff --git a/modules/vulkan/vk_copy_handler.h b/modules/vulkan/vk_copy_handler.h
new file mode 100644
index 0000000..8c71bae
--- /dev/null
+++ b/modules/vulkan/vk_copy_handler.h
@@ -0,0 +1,90 @@
+/*
+ * vk_copy_handler.h - vulkan copy handler
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_COPY_HANDLER_H
+#define XCAM_VK_COPY_HANDLER_H
+
+#include <xcam_utils.h>
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_worker.h>
+#include <vulkan/vk_handler.h>
+#include <vulkan/vk_descriptor.h>
+
+namespace XCam {
+
+#if 0
+class VKCopyArguments
+    : public VKWorker::VKArguments
+{
+public:
+    explicit VKCopyArguments (const SmartPtr<VKBuffer> in, SmartPtr<VKBuffer> out);
+
+private:
+    virtual XCamReturn prepare_bindings (VKDescriptor::SetBindInfoArray &binding_array);
+private:
+    SmartPtr<VKBuffer>        _in_buf;
+    SmartPtr<VKBuffer>        _out_buf;
+};
+#endif
+
+class VKCopyHandler
+    : public VKHandler
+{
+public:
+    struct PushConstsProp {
+        uint    in_img_width;
+        uint    in_x_offset;
+        uint    out_img_width;
+        uint    out_x_offset;
+        uint    copy_width;
+
+        PushConstsProp ();
+    };
+
+public:
+    explicit VKCopyHandler (const SmartPtr<VKDevice> &dev, const char* name = "vk-copy-handler");
+
+    bool set_copy_area (uint32_t idx, const Rect &in_area, const Rect &out_area);
+    uint32_t get_index () {
+        return _index;
+    }
+
+    XCamReturn copy (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf);
+    void copy_done (
+        const SmartPtr<Worker> &worker,
+        const SmartPtr<Worker::Arguments> &base,
+        const XCamReturn error);
+
+private:
+    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    virtual XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    SmartPtr<VKWorker>               _worker;
+    PushConstsProp                   _image_prop;
+    VKDescriptor::BindingArray       _binding_layout;
+
+    uint32_t                         _index;
+    Rect                             _in_area;
+    Rect                             _out_area;
+};
+
+}
+#endif //XCAM_VK_COPY_HANDLER_H
diff --git a/modules/vulkan/vk_descriptor.cpp b/modules/vulkan/vk_descriptor.cpp
new file mode 100644
index 0000000..888d3d6
--- /dev/null
+++ b/modules/vulkan/vk_descriptor.cpp
@@ -0,0 +1,220 @@
+/*
+ * vk_descriptor.cpp - Vulkan descriptor
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_descriptor.h"
+#include "vk_device.h"
+
+namespace XCam {
+
+namespace VKDescriptor {
+
+SetLayoutBinding::SetLayoutBinding (
+    VkDescriptorType type, VkShaderStageFlags stage, uint32_t idx, uint32_t count)
+{
+    xcam_mem_clear (_binding);
+    _binding.binding = idx;
+    _binding.descriptorType = type;
+    _binding.descriptorCount = count;
+    _binding.stageFlags = stage;
+    _binding.pImmutableSamplers = NULL;
+}
+
+SetLayoutBinding::~SetLayoutBinding ()
+{
+}
+
+VkBindingArray
+get_vk_layoutbindings (const BindingArray &array)
+{
+    VkBindingArray ret;
+    ret.reserve (array.size ());
+    for (size_t i = 0; i < array.size (); ++i) {
+        ret.push_back(array[i]->get_vk_binding ());
+    }
+    return ret;
+}
+
+Pool::Pool (const SmartPtr<VKDevice> dev)
+    : _pool_id (VK_NULL_HANDLE)
+    , _set_size (0)
+    , _dev (dev)
+{}
+
+Pool::~Pool ()
+{
+    if (XCAM_IS_VALID_VK_ID (_pool_id)) {
+        _dev->destroy_desc_pool (_pool_id);
+    }
+}
+
+void
+Pool::add_binding (const SmartPtr<SetLayoutBinding> &bind)
+{
+    VkDescriptorSetLayoutBinding vk_binding = bind->get_vk_binding ();
+    Pool::TypeTable::iterator i = _types.find (vk_binding.descriptorType);
+    if (i == _types.end ())
+        _types.insert (i, Pool::TypeTable::value_type (vk_binding.descriptorType, vk_binding.descriptorCount));
+    else
+        i->second += vk_binding.descriptorCount;
+}
+
+bool
+Pool::add_set_bindings (const BindingArray &binds)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !XCAM_IS_VALID_VK_ID (_pool_id), false,
+        "vk desriptor pool was inited, cannot add new binding.");
+
+    for (BindingArray::const_iterator i = binds.begin (); i != binds.end (); ++i) {
+        add_binding (*i);
+    }
+    ++_set_size;
+
+    return true;
+}
+
+XCamReturn
+Pool::create ()
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !_types.empty (), XCAM_RETURN_ERROR_PARAM,
+        "vk desriptor pool cannot create since no types added.");
+
+    XCAM_FAIL_RETURN (
+        ERROR, _dev.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "vk desriptor pool cannot create, device is null");
+
+    std::vector<VkDescriptorPoolSize> pool_sizes;
+    pool_sizes.reserve (_types.size ());
+    for (Pool::TypeTable::iterator i = _types.begin (); i != _types.end(); ++i) {
+        VkDescriptorPoolSize new_size = {};
+        new_size.type = i->first;
+        new_size.descriptorCount = i->second;
+        pool_sizes.push_back (new_size);
+    }
+
+    XCAM_ASSERT (_set_size);
+    VkDescriptorPoolCreateInfo create_info = {};
+    create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+    create_info.maxSets = _set_size;
+    create_info.poolSizeCount = pool_sizes.size ();
+    create_info.pPoolSizes = pool_sizes.data ();
+
+    _pool_id = _dev->create_desc_pool (create_info);
+
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (_pool_id), XCAM_RETURN_ERROR_VULKAN,
+        "vk desriptor pool create pool_id failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+SmartPtr<Set>
+Pool::allocate_set (const SetBindInfoArray &bind_array, VkDescriptorSetLayout layout)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (_pool_id), NULL,
+        "vk desriptor pool allocate set failed, pool was not ready");
+
+#if 0
+    XCAM_FAIL_RETURN (
+        ERROR, bind_array.size () == bufs.size (), NULL,
+        "vk desriptor pool allocate set failed, bindings and bufs sizes are not matched");
+#endif
+
+    XCAM_FAIL_RETURN (
+        ERROR, _set_size > 0, NULL,
+        "vk desriptor pool allocate set failed, bindings and bufs sizes are not matched");
+
+    //TODO remove binds types from _types
+
+    VkDescriptorSetAllocateInfo alloc_info = {};
+    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+    alloc_info.descriptorPool = _pool_id;
+    alloc_info.pSetLayouts = &layout;
+    alloc_info.descriptorSetCount = 1;
+
+    VkDescriptorSet desc_set_id = _dev->allocate_desc_set (alloc_info);
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (desc_set_id) > 0, NULL,
+        "vk desriptor pool allocate set failed");
+    SmartPtr<Set> new_set = new Set (desc_set_id, this);
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (new_set->update_set (bind_array)), NULL,
+        "vk descriptor pool update set failed");
+
+    --_set_size;
+    return new_set;
+}
+
+void
+Pool::destroy_desc_set (VkDescriptorSet set_id)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_pool_id));
+    if (xcam_ret_is_ok (_dev->free_desc_set (set_id, _pool_id)))
+        ++_set_size;
+}
+
+Set::Set (VkDescriptorSet set_id, const SmartPtr<Pool> pool)
+    : _set_id (set_id)
+    , _pool (pool)
+{
+}
+
+Set::~Set ()
+{
+    if (XCAM_IS_VALID_VK_ID (_set_id)) {
+        _pool->destroy_desc_set (_set_id);
+    }
+}
+
+XCamReturn
+Set::update_set (const SetBindInfoArray &bind_array)
+{
+    std::vector<VkWriteDescriptorSet> write_desc_info (bind_array.size ());
+    for (uint32_t i = 0; i < bind_array.size (); ++i) {
+        const SetBindInfo &bind_info = bind_array[i];
+        SmartPtr<SetLayoutBinding> bind = bind_info.layout;
+        XCAM_ASSERT (bind.ptr () && bind_info.desc.buf.ptr ());
+
+        VkWriteDescriptorSet &info = write_desc_info[i];
+        xcam_mem_clear (info);
+        info.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+        info.dstSet = _set_id;
+        info.dstBinding = bind->get_index ();
+        info.descriptorCount = 1;
+        info.descriptorType = bind->get_desc_type();
+        info.pBufferInfo = &bind_info.desc.desc_info;
+    }
+    SmartPtr<VKDevice> dev = _pool->get_device ();
+    XCAM_ASSERT (dev.ptr ());
+    XCamReturn ret = dev->update_desc_set (write_desc_info);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk descriptor pool update set failed");
+
+    _bind_array = bind_array;
+    return ret;
+}
+
+}
+
+}
diff --git a/modules/vulkan/vk_descriptor.h b/modules/vulkan/vk_descriptor.h
new file mode 100644
index 0000000..63eff6a
--- /dev/null
+++ b/modules/vulkan/vk_descriptor.h
@@ -0,0 +1,163 @@
+/*
+ * vk_descriptor.h - Vulkan descriptor
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_DESCRIPTOR_H
+#define XCAM_VK_DESCRIPTOR_H
+
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_memory.h>
+#include <map>
+
+namespace XCam {
+
+class VKDevice;
+
+namespace VKDescriptor {
+
+class SetLayoutBinding
+{
+public:
+    virtual ~SetLayoutBinding ();
+    const VkDescriptorSetLayoutBinding &get_vk_binding () const {
+        return _binding;
+    }
+    VkDescriptorType get_desc_type () const {
+        return _binding.descriptorType;
+    }
+    uint32_t get_index () const {
+        return _binding.binding;
+    }
+
+protected:
+    explicit SetLayoutBinding (
+        VkDescriptorType type, VkShaderStageFlags stage, uint32_t idx, uint32_t count);
+
+private:
+    XCAM_DEAD_COPY (SetLayoutBinding);
+protected:
+    VkDescriptorSetLayoutBinding    _binding;
+};
+
+template <VkShaderStageFlags stage>
+class LayoutBinding
+    : public SetLayoutBinding
+{
+public:
+    explicit LayoutBinding (VkDescriptorType type, uint32_t idx)
+        : SetLayoutBinding (type, stage, idx, 1)
+    {}
+};
+
+typedef LayoutBinding<VK_SHADER_STAGE_COMPUTE_BIT> ComputeLayoutBinding;
+typedef LayoutBinding<VK_SHADER_STAGE_VERTEX_BIT> VetexLayoutBinding;
+typedef LayoutBinding<VK_SHADER_STAGE_FRAGMENT_BIT> FragmentLayoutBinding;
+
+typedef std::vector<SmartPtr<SetLayoutBinding>>  BindingArray;
+
+typedef std::vector<VkDescriptorSetLayoutBinding>  VkBindingArray;
+
+VkBindingArray get_vk_layoutbindings (const BindingArray &array);
+
+struct SetBindInfo {
+    SmartPtr<SetLayoutBinding>   layout;
+    VKBufDesc                    desc;
+};
+
+typedef std::vector<SetBindInfo> SetBindInfoArray;
+
+class Pool;
+class Set {
+public:
+    explicit Set (VkDescriptorSet set_id, const SmartPtr<Pool> pool);
+    ~Set ();
+    XCamReturn update_set (const SetBindInfoArray &bind_array);
+    VkDescriptorSet get_set_id () const {
+        return _set_id;
+    }
+
+private:
+    XCAM_DEAD_COPY (Set);
+
+    VkDescriptorSet           _set_id;
+    SetBindInfoArray          _bind_array;
+    SmartPtr<Pool>            _pool;
+};
+
+class Pool
+    : public RefObj
+{
+    friend class Set;
+public:
+    explicit Pool (const SmartPtr<VKDevice> dev);
+    ~Pool ();
+    bool add_set_bindings (const BindingArray &binds);
+    XCamReturn create ();
+    const SmartPtr<VKDevice> &get_device() const {
+        return _dev;
+    }
+
+    SmartPtr<Set> allocate_set (
+        const SetBindInfoArray &bind_array, VkDescriptorSetLayout layout);
+
+private:
+    XCAM_DEAD_COPY (Pool);
+    void add_binding (const SmartPtr<SetLayoutBinding> &bind);
+    void destroy_desc_set (VkDescriptorSet set_id);
+
+private:
+    typedef std::map<VkDescriptorType, uint32_t>  TypeTable;
+
+    VkDescriptorPool                _pool_id;
+    uint32_t                        _set_size;
+    TypeTable                       _types;
+    const SmartPtr<VKDevice>        _dev;
+};
+
+}
+
+namespace VKConstRange {
+
+class VKPushConstArg {
+public:
+    virtual ~VKPushConstArg () {}
+    virtual bool get_const_data (VkPushConstantRange &range, void *& ptr) = 0;
+};
+
+typedef std::vector<SmartPtr<VKPushConstArg>> VKPushConstArgs;
+
+typedef std::vector<VkPushConstantRange> VKConstantArray;
+
+template <VkShaderStageFlags stage>
+VkPushConstantRange
+get_constants (uint32_t size, uint32_t offset)
+{
+    VkPushConstantRange range = {};
+    range.stageFlags = stage;
+    range.offset = offset;
+    range.size = size;
+    return range;
+}
+
+#define get_compute_consts get_constants<VK_SHADER_STAGE_COMPUTE_BIT>
+}
+
+}
+
+#endif  //XCAM_VK_DESCRIPTOR_H
diff --git a/modules/vulkan/vk_device.cpp b/modules/vulkan/vk_device.cpp
new file mode 100644
index 0000000..bf5e68e
--- /dev/null
+++ b/modules/vulkan/vk_device.cpp
@@ -0,0 +1,471 @@
+/*
+ * vk_device.cpp - vulkan device
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vulkan_common.h"
+#include "vk_device.h"
+#include "vk_shader.h"
+#include "vk_instance.h"
+#include "vk_sync.h"
+#include "vk_cmdbuf.h"
+#include "file_handle.h"
+
+namespace XCam {
+
+SmartPtr<VKDevice> VKDevice::_default_dev;
+Mutex VKDevice::_default_mutex;
+
+VKDevice::~VKDevice ()
+{
+    if (_dev_id)
+        vkDestroyDevice (_dev_id, _allocator.ptr ());
+}
+
+VKDevice::VKDevice (VkDevice id, const SmartPtr<VKInstance> &instance)
+    : _dev_id (id)
+    , _instance (instance)
+{
+    XCAM_ASSERT (instance.ptr ());
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id));
+    _allocator = instance->get_allocator ();
+}
+
+SmartPtr<VKDevice>
+VKDevice::default_device ()
+{
+    SmartLock lock (_default_mutex);
+    if (!_default_dev.ptr()) {
+        _default_dev = create_device ();
+    }
+    XCAM_FAIL_RETURN (
+        ERROR, _default_dev.ptr (), NULL,
+        "VKDevice prepare default device failed.");
+    return _default_dev;
+}
+
+SmartPtr<VKDevice>
+VKDevice::create_device ()
+{
+    SmartPtr<VKInstance> instance = VKInstance::get_instance ();
+    XCAM_FAIL_RETURN (
+        ERROR, instance.ptr (), NULL,
+        "vk create device failed");
+
+    VkPhysicalDevice phy_dev = instance->get_physical_dev ();
+    uint32_t compute_idx = instance->get_compute_queue_family_idx ();
+    SmartPtr<VkAllocationCallbacks> allocator = instance->get_allocator ();
+
+    float priority = 1.0f; //TODO, queue priority change?
+    VkDeviceQueueCreateInfo dev_queue_info = {};
+    dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+    dev_queue_info.queueFamilyIndex = compute_idx; // default use compute idx
+    dev_queue_info.queueCount = 1;
+    dev_queue_info.pQueuePriorities = &priority;
+
+    VkDeviceCreateInfo dev_create_info = {};
+    dev_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+    //TODO, add graphics queue info
+    dev_create_info.queueCreateInfoCount = 1;
+    dev_create_info.pQueueCreateInfos = &dev_queue_info;
+
+    VkDevice dev_id = 0;
+    XCAM_VK_CHECK_RETURN (
+        ERROR,
+        vkCreateDevice (phy_dev, &dev_create_info, allocator.ptr (), &dev_id),
+        NULL, "create vk device failed");
+
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (dev_id));
+    SmartPtr<VKDevice> device = new VKDevice (dev_id, instance);
+    XCAM_ASSERT (device.ptr ());
+
+    XCamReturn ret = device->prepare_compute_queue ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), NULL,
+        "VKDevice prepare compute queue failed.");
+
+    return device;
+}
+
+XCamReturn
+VKDevice::prepare_compute_queue ()
+{
+    uint32_t compute_idx = _instance->get_compute_queue_family_idx ();
+    vkGetDeviceQueue (_dev_id, compute_idx, 0, &_compute_queue);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+SmartPtr<VKShader>
+VKDevice::create_shader (const char *file_name)
+{
+    FileHandle file (file_name, "rb");
+    XCAM_FAIL_RETURN (
+        ERROR, file.is_valid (), NULL,
+        "VKDevice load shader failed when opend shader file:%s.",
+        XCAM_STR (file_name));
+
+    size_t file_size;
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (file.get_file_size (file_size)) || file_size == 0, NULL,
+        "VKDevice load shader failed when read shader file:%s.",
+        XCAM_STR (file_name));
+    std::vector<uint32_t> content (XCAM_ALIGN_UP (file_size, 4) / 4, 0);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (file.read_file ((void *)content.data (), file_size)), NULL,
+        "VKDevice load shader failed when read shader file:%s.",
+        XCAM_STR (file_name));
+    file.close ();
+
+    SmartPtr<VKShader> shader = create_shader (content);
+    if (shader.ptr ())
+        shader->set_name (file_name);
+    return shader;
+}
+
+SmartPtr<VKShader>
+VKDevice::create_shader (const std::vector<uint32_t> &binary)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (_dev_id), NULL,
+        "VKDevice load shader failed with error of null device ready.");
+    XCAM_FAIL_RETURN (
+        ERROR, binary.size () > 5, NULL,
+        "VKDevice load shader failed since binary is corrupt.");
+
+    VkShaderModule shader_id;
+    VkShaderModuleCreateInfo module_create_info = {};
+    module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    module_create_info.pNext = NULL;
+    module_create_info.codeSize = binary.size() * sizeof (binary[0]);
+    module_create_info.pCode = binary.data();
+    module_create_info.flags = 0;
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkCreateShaderModule (_dev_id, &module_create_info, NULL, &shader_id),
+        NULL, "VKDevice create shader module failed.");
+
+    XCAM_IS_VALID_VK_ID (shader_id);
+    return new VKShader (this, shader_id);
+}
+
+void
+VKDevice::destroy_shader_id (VkShaderModule shader)
+{
+    if (XCAM_IS_VALID_VK_ID(_dev_id) && XCAM_IS_VALID_VK_ID (shader))
+        vkDestroyShaderModule (_dev_id, shader, _allocator.ptr());
+}
+
+VkDeviceMemory
+VKDevice::allocate_mem_id (VkDeviceSize size, VkMemoryPropertyFlags memory_prop)
+{
+    VkDeviceMemory mem_id;
+    VkMemoryAllocateInfo mem_alloc_info = {};
+    mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    mem_alloc_info.allocationSize = size;
+    mem_alloc_info.memoryTypeIndex = _instance->get_mem_type_index (memory_prop);
+
+    XCAM_FAIL_RETURN (
+        ERROR, mem_alloc_info.memoryTypeIndex != (uint32_t)(-1), VK_NULL_HANDLE,
+        "VKDevice create mem id failed, can NOT find memory type:0x%08x.", (uint32_t)memory_prop);
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkAllocateMemory (_dev_id, &mem_alloc_info, _allocator.ptr (), &mem_id),
+        VK_NULL_HANDLE, "create vk buffer failed in allocating memory");
+    return mem_id;
+}
+
+void
+VKDevice::free_mem_id (VkDeviceMemory mem)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (mem));
+
+    vkFreeMemory (_dev_id, mem, _allocator.ptr ());
+}
+
+XCamReturn
+VKDevice::map_mem (VkDeviceMemory mem, VkDeviceSize size, VkDeviceSize offset, void *&ptr)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (mem));
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkMapMemory (_dev_id, mem, offset, size, 0, &ptr), XCAM_RETURN_ERROR_VULKAN,
+        "vk device map mem failed. size:%lld", size);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void
+VKDevice::unmap_mem (VkDeviceMemory mem)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (mem));
+    vkUnmapMemory (_dev_id, mem);
+}
+
+VkBuffer
+VKDevice::create_buf_id (VkBufferUsageFlags usage, uint32_t size)
+{
+    VkBufferCreateInfo buf_create_info = {};
+    buf_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buf_create_info.size = size;
+    buf_create_info.usage = usage;
+    buf_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    VkBuffer buf_id;
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkCreateBuffer (_dev_id, &buf_create_info, _allocator.ptr (), &buf_id),
+        VK_NULL_HANDLE, "create vk buffer failed");
+
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf_id));
+    return buf_id;
+}
+
+void
+VKDevice::destroy_buf_id (VkBuffer buf)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf));
+
+    vkDestroyBuffer (_dev_id, buf, _allocator.ptr ());
+}
+
+XCamReturn
+VKDevice::bind_buffer (VkBuffer buf, VkDeviceMemory mem, VkDeviceSize offset)
+{
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkBindBufferMemory (_dev_id, buf, mem, offset),
+        XCAM_RETURN_ERROR_VULKAN, "vkdevice bind buffer to mem failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+VkDescriptorPool
+VKDevice::create_desc_pool (const VkDescriptorPoolCreateInfo &info)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+
+    VkDescriptorPool pool_id;
+    XCAM_VK_CHECK_RETURN (
+        ERROR,
+        vkCreateDescriptorPool (_dev_id, &info, _allocator.ptr (), &pool_id),
+        VK_NULL_HANDLE,
+        "vkdevice create desriptor pool failed");
+    return pool_id;
+}
+
+void
+VKDevice::destroy_desc_pool (VkDescriptorPool pool)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool));
+    vkDestroyDescriptorPool (_dev_id, pool, _allocator.ptr ());
+}
+
+VkDescriptorSet
+VKDevice::allocate_desc_set (const VkDescriptorSetAllocateInfo &info)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+
+    VkDescriptorSet set_id;
+    XCAM_VK_CHECK_RETURN (
+        ERROR,
+        vkAllocateDescriptorSets (_dev_id, &info, &set_id),
+        VK_NULL_HANDLE,
+        "vkdevice create desriptor set failed");
+    return set_id;
+
+}
+
+XCamReturn
+VKDevice::free_desc_set (VkDescriptorSet set, VkDescriptorPool pool)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (set));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool));
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR,
+        vkFreeDescriptorSets (_dev_id, pool, 1, &set),
+        XCAM_RETURN_ERROR_VULKAN,
+        "vkdevice free desriptor set from pool failed");
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKDevice::update_desc_set (const std::vector<VkWriteDescriptorSet> &sets)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    vkUpdateDescriptorSets (_dev_id, sets.size (), sets.data (), 0, NULL);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+VkCommandPool
+VKDevice::create_cmd_pool (VkFlags queue_flag)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (_instance.ptr ());
+    VkCommandPool pool_id = VK_NULL_HANDLE;
+
+    VkCommandPoolCreateInfo create_pool_info = {};
+    create_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    create_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+
+    if (queue_flag == VK_QUEUE_COMPUTE_BIT)
+        create_pool_info.queueFamilyIndex = _instance->get_compute_queue_family_idx ();
+    else if (queue_flag == VK_QUEUE_GRAPHICS_BIT)
+        create_pool_info.queueFamilyIndex = _instance->get_graphics_queue_family_idx ();
+    else {
+        XCAM_LOG_WARNING ("VKDevice create command pool failed, queue_flag(%d) not supported.", queue_flag);
+        return VK_NULL_HANDLE;
+    }
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkCreateCommandPool (_dev_id, &create_pool_info,  _allocator.ptr (), &pool_id),
+        VK_NULL_HANDLE, "VKDevice create command pool failed.");
+    return pool_id;
+}
+
+void
+VKDevice::destroy_cmd_pool (VkCommandPool pool)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool));
+    vkDestroyCommandPool (_dev_id, pool, _allocator.ptr ());
+}
+
+VkCommandBuffer
+VKDevice::allocate_cmd_buffer (VkCommandPool pool)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool));
+
+    VkCommandBufferAllocateInfo allocate_info = {};
+    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    allocate_info.commandPool = pool;
+    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    allocate_info.commandBufferCount = 1;
+
+    VkCommandBuffer buf_id = VK_NULL_HANDLE;
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkAllocateCommandBuffers (_dev_id, &allocate_info, &buf_id),
+        VK_NULL_HANDLE, "VKDevice create command buffers failed.");
+    return buf_id;
+}
+
+void
+VKDevice::free_cmd_buffer (VkCommandPool pool, VkCommandBuffer buf)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pool));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf));
+
+    vkFreeCommandBuffers (_dev_id, pool, 1, &buf);
+}
+
+SmartPtr<VKFence>
+VKDevice::create_fence (VkFenceCreateFlags flags)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+
+    VkFenceCreateInfo fence_info = {};
+    fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
+    fence_info.flags = flags;
+
+    VkFence fence_id = VK_NULL_HANDLE;
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkCreateFence (_dev_id, &fence_info,  _allocator.ptr (), &fence_id),
+        NULL, "VKDevice create fence failed.");
+    return new VKFence (this, fence_id);
+}
+
+void
+VKDevice::destroy_fence (VkFence fence)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (fence));
+
+    vkDestroyFence (_dev_id, fence, _allocator.ptr ());
+}
+
+XCamReturn
+VKDevice::reset_fence (VkFence fence)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (fence));
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkResetFences (_dev_id, 1,  &fence),
+        XCAM_RETURN_ERROR_VULKAN, "VKDevice reset fence failed.");
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKDevice::wait_for_fence (VkFence fence, uint64_t timeout)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_dev_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (fence));
+
+    VkResult ret = vkWaitForFences (_dev_id, 1,  &fence, VK_TRUE, timeout);
+    if (ret == VK_TIMEOUT) {
+        XCAM_LOG_DEBUG ("VKDevice wait for fence timeout");
+        return XCAM_RETURN_ERROR_TIMEOUT;
+    }
+
+    XCAM_FAIL_RETURN (
+        ERROR, ret == VK_SUCCESS,
+        XCAM_RETURN_ERROR_VULKAN, "VKDevice wait for fence failed.");
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKDevice::compute_queue_submit (const SmartPtr<VKCmdBuf> cmd_buf, const SmartPtr<VKFence> fence)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, cmd_buf.ptr (),
+        XCAM_RETURN_ERROR_PARAM, "VKDevice compute queue submit failed, cmd_buf is empty.");
+
+    VkCommandBuffer buf_id = cmd_buf->get_cmd_buf_id ();
+    VkSubmitInfo submit_info = {};
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &buf_id;
+
+    VkFence fence_id = VK_NULL_HANDLE;
+    if (fence.ptr ())
+        fence_id = fence->get_fence_id ();
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkQueueSubmit (_compute_queue, 1, &submit_info, fence_id),
+        XCAM_RETURN_ERROR_VULKAN, "VKDevice compute queue submit failed.");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKDevice::compute_queue_wait_idle ()
+{
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (_compute_queue),
+        XCAM_RETURN_ERROR_PARAM, "VKDevice compute queue wait idle failed, queue_id is null");
+
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkQueueWaitIdle (_compute_queue),
+        XCAM_RETURN_ERROR_VULKAN, "VKDevice compute queue wait idle failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+}
diff --git a/modules/vulkan/vk_device.h b/modules/vulkan/vk_device.h
new file mode 100644
index 0000000..27a07a1
--- /dev/null
+++ b/modules/vulkan/vk_device.h
@@ -0,0 +1,120 @@
+/*
+ * vk_device.h - vulkan device
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_DEVICE_H
+#define XCAM_VK_DEVICE_H
+
+#include <vulkan/vulkan_std.h>
+#include <xcam_mutex.h>
+
+namespace XCam {
+
+class VKPipeline;
+class VKShader;
+class VKFence;
+class VKCmdBuf;
+class VKInstance;
+class VKMemory;
+class VKBuffer;
+
+namespace VKDescriptor {
+class Pool;
+class Set;
+};
+
+class VKDevice
+    : public RefObj
+{
+    friend class VKFence;
+    friend class VKShader;
+    friend class VKPipeline;
+    friend class VKCmdBuf;
+    friend class VKDescriptor::Pool;
+    friend class VKDescriptor::Set;
+    friend class VKMemory;
+    friend class VKBuffer;
+public:
+    ~VKDevice ();
+    static SmartPtr<VKDevice> default_device ();
+    static SmartPtr<VKDevice> create_device ();
+
+    VkDevice get_dev_id () const {
+        return _dev_id;
+    }
+    SmartPtr<VkAllocationCallbacks>
+    get_allocation_cb () const {
+        return _allocator;
+    }
+
+    SmartPtr<VKShader> create_shader (const char *file_name);
+    SmartPtr<VKShader> create_shader (const std::vector<uint32_t> &binary);
+    //SmartPtr<VKPipeline> create_pipeline (const SmartPtr<VKShader> shader);
+    SmartPtr<VKFence> create_fence (VkFenceCreateFlags flags = VK_FENCE_CREATE_SIGNALED_BIT);
+    XCamReturn compute_queue_submit (const SmartPtr<VKCmdBuf> cmd_buf, const SmartPtr<VKFence> fence);
+    XCamReturn compute_queue_wait_idle ();
+
+protected:
+    void destroy_shader_id (VkShaderModule shader);
+    VkDeviceMemory allocate_mem_id (VkDeviceSize size, VkMemoryPropertyFlags memory_prop);
+    void free_mem_id (VkDeviceMemory mem);
+    XCamReturn map_mem (VkDeviceMemory mem, VkDeviceSize size, VkDeviceSize offset, void *&ptr);
+    void unmap_mem (VkDeviceMemory mem);
+    VkBuffer create_buf_id (VkBufferUsageFlags usage, uint32_t size);
+    void destroy_buf_id (VkBuffer buf);
+    XCamReturn bind_buffer (VkBuffer buf, VkDeviceMemory mem, VkDeviceSize offset = 0);
+
+    VkDescriptorPool create_desc_pool (const VkDescriptorPoolCreateInfo &info);
+    void destroy_desc_pool (VkDescriptorPool pool);
+
+    VkDescriptorSet allocate_desc_set (const VkDescriptorSetAllocateInfo &info);
+    XCamReturn free_desc_set (VkDescriptorSet set, VkDescriptorPool pool);
+
+    XCamReturn update_desc_set (const std::vector<VkWriteDescriptorSet> &sets);
+    VkCommandPool create_cmd_pool (VkFlags queue_flag = VK_QUEUE_COMPUTE_BIT);
+    void destroy_cmd_pool (VkCommandPool pool);
+
+    VkCommandBuffer allocate_cmd_buffer (VkCommandPool pool);
+    void free_cmd_buffer (VkCommandPool pool, VkCommandBuffer buf);
+
+    void destroy_fence (VkFence fence);
+    XCamReturn reset_fence (VkFence fence);
+    XCamReturn wait_for_fence (VkFence fence, uint64_t timeout);
+
+protected:
+    explicit VKDevice (VkDevice id, const SmartPtr<VKInstance> &instance);
+    XCamReturn prepare_compute_queue ();
+    //SmartPtr<VKLayout> create_desc_set_layout ();
+
+private:
+    XCAM_DEAD_COPY (VKDevice);
+
+private:
+    static SmartPtr<VKDevice>        _default_dev;
+    static Mutex                     _default_mutex;
+
+    VkDevice                         _dev_id;
+    VkQueue                          _compute_queue;
+    SmartPtr<VkAllocationCallbacks>  _allocator;
+    SmartPtr<VKInstance>             _instance;
+};
+
+}
+
+#endif  //XCAM_VK_DEVICE_H
diff --git a/modules/vulkan/vk_geomap_handler.cpp b/modules/vulkan/vk_geomap_handler.cpp
new file mode 100644
index 0000000..4b65a44
--- /dev/null
+++ b/modules/vulkan/vk_geomap_handler.cpp
@@ -0,0 +1,314 @@
+/*
+ * vk_geomap_handler.cpp - vulkan geometry map handler implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "vk_geomap_handler.h"
+#include "vk_video_buf_allocator.h"
+#include "vk_device.h"
+
+#define GEOMAP_SHADER_BINDING_COUNT 5
+
+#define XCAM_VK_GEOMAP_ALIGN_X 4
+#define XCAM_VK_GEOMAP_ALIGN_Y 2
+
+namespace XCam {
+
+namespace {
+
+DECLARE_WORK_CALLBACK (CbGeoMapShader, VKGeoMapHandler, geomap_done);
+
+class GeoMapArgs
+    : public VKWorker::VKArguments
+{
+public:
+    explicit GeoMapArgs (const SmartPtr<ImageHandler::Parameters> &param)
+        : _param (param)
+    {
+        XCAM_ASSERT (param.ptr ());
+    }
+    const SmartPtr<ImageHandler::Parameters> &get_param () const {
+        return _param;
+    }
+
+private:
+    SmartPtr<ImageHandler::Parameters>    _param;
+};
+
+class VKGeoMapPushConst
+    : public VKConstRange::VKPushConstArg
+{
+public:
+    VKGeoMapPushConst (const VKGeoMapHandler::PushConstsProp &prop)
+        : _prop (prop)
+    {}
+
+    bool get_const_data (VkPushConstantRange &range, void *& ptr) {
+        range.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+        range.offset = 0;
+        range.size = sizeof (_prop);
+        ptr = &_prop;
+        return true;
+    }
+
+private:
+    VKGeoMapHandler::PushConstsProp _prop;
+};
+
+static const VKShaderInfo geomap_shader_info (
+    "main",
+std::vector<uint32_t> {
+#include "shader_geomap.comp.spv"
+});
+
+}
+
+VKGeoMapHandler::PushConstsProp::PushConstsProp ()
+    : in_img_width (0)
+    , in_img_height (0)
+    , out_img_width (0)
+    , out_img_height (0)
+    , lut_width (0)
+    , lut_height (0)
+{
+    xcam_mem_clear (lut_step);
+    xcam_mem_clear (lut_std_step);
+}
+
+VKGeoMapHandler::VKGeoMapHandler (const SmartPtr<VKDevice> &dev, const char* name)
+    : VKHandler (dev, name)
+{
+}
+
+bool
+VKGeoMapHandler::set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, data && width && height, false,
+        "VKGeoMapHandler(%s) set look up table failed, data ptr:%p, width:%d, height:%d",
+        XCAM_STR (get_name ()), data, width, height);
+    XCAM_ASSERT (!_lut_buf.ptr ());
+
+    _lut_width = width;
+    _lut_height = height;
+
+    uint32_t lut_size = width * height * 2 * sizeof (float);
+    SmartPtr<VKBuffer> buf = VKBuffer::create_buffer (
+        get_vk_device (), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, lut_size);
+    XCAM_ASSERT (buf.ptr ());
+
+    float *ptr = (float *) buf->map (lut_size, 0);
+    XCAM_FAIL_RETURN (ERROR, ptr, false, "VKGeoMapHandler(%s) map range failed", XCAM_STR (get_name ()));
+    for (uint32_t i = 0; i < height; ++i) {
+        float *ret = &ptr[i * width * 2];
+        const PointFloat2 *line = &data[i * width];
+
+        for (uint32_t j = 0; j < width; ++j) {
+            ret[j * 2] = line[j].x;
+            ret[j * 2 + 1] = line[j].y;
+        }
+    }
+    buf->unmap ();
+    _lut_buf = buf;
+
+    return true;
+}
+
+bool
+VKGeoMapHandler::init_factors ()
+{
+    XCAM_ASSERT (_lut_width && _lut_height);
+
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+
+    if (!XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) && !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f))
+        return true;
+
+    return auto_calculate_factors (_lut_width, _lut_height);
+}
+
+#define UNIT_BYTES (sizeof (uint32_t))
+
+XCamReturn
+VKGeoMapHandler::configure_resource (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, _lut_buf.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "VKGeoMapHandler(%s) configure resource failed, look up table is empty", XCAM_STR (get_name ()));
+
+    const VideoBufferInfo &in_info = param->in_buf->get_video_info ();
+    XCAM_FAIL_RETURN (
+        ERROR, in_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
+        "VKGeoMapHandler(%s) only support NV12 format, but input format is %s",
+        XCAM_STR (get_name ()), xcam_fourcc_to_string (in_info.format));
+
+    uint32_t out_width, out_height;
+    get_output_size (out_width, out_height);
+    VideoBufferInfo out_info;
+    out_info.init (
+        in_info.format, out_width, out_height,
+        XCAM_ALIGN_UP (out_width, XCAM_VK_GEOMAP_ALIGN_X),
+        XCAM_ALIGN_UP (out_height, XCAM_VK_GEOMAP_ALIGN_Y));
+    set_out_video_info (out_info);
+
+    init_factors ();
+
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+    XCAM_FAIL_RETURN (
+        ERROR,
+        !XCAM_DOUBLE_EQUAL_AROUND (factor_x, 0.0f) &&
+        !XCAM_DOUBLE_EQUAL_AROUND (factor_y, 0.0f),
+        XCAM_RETURN_ERROR_PARAM,
+        "VKGeoMapHandler(%s) invalid standard factors: x:%f, y:%f",
+        XCAM_STR (get_name ()), factor_x, factor_y);
+
+    _image_prop.in_img_width = in_info.aligned_width / UNIT_BYTES;
+    _image_prop.in_img_height = in_info.aligned_height;
+    _image_prop.out_img_width = out_info.aligned_width / UNIT_BYTES;
+    _image_prop.out_img_height = out_info.aligned_height;
+    _image_prop.lut_width = _lut_width;
+    _image_prop.lut_height = _lut_height;
+    _image_prop.lut_std_step[0] = 1.0f / factor_x;
+    _image_prop.lut_std_step[1] = 1.0f / factor_y;
+
+    WorkSize global_size (
+        XCAM_ALIGN_UP (_image_prop.out_img_width, 8) / 8,
+        XCAM_ALIGN_UP (_image_prop.out_img_height, 16) / 16);
+
+    _binding_layout.clear ();
+    for (int i = 0; i < GEOMAP_SHADER_BINDING_COUNT; ++i) {
+        SmartPtr<VKDescriptor::SetLayoutBinding> binding =
+            new VKDescriptor::ComputeLayoutBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, i);
+        _binding_layout.push_back (binding);
+    }
+
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+    if (!_worker.ptr ()) {
+        _worker = new VKWorker (get_vk_device(), "CbGeoMapShader", new CbGeoMapShader (this));
+        XCAM_ASSERT (_worker.ptr ());
+
+        _worker->set_global_size (global_size);
+
+        VKConstRange::VKPushConstArgs push_consts;
+        push_consts.push_back (new VKGeoMapPushConst (_image_prop));
+        ret = _worker->build (geomap_shader_info, _binding_layout, push_consts);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_VULKAN,
+            "VKGeoMapHandler(%s) build geomap shader failed.", XCAM_STR (get_name ()));
+    }
+
+    return ret;
+}
+
+XCamReturn
+VKGeoMapHandler::start_work (const SmartPtr<ImageHandler::Parameters> &param)
+{
+    XCAM_ASSERT (_lut_buf.ptr ());
+    XCAM_ASSERT (param.ptr () && param->in_buf.ptr () && param->out_buf.ptr ());
+    XCAM_ASSERT (_binding_layout.size () == GEOMAP_SHADER_BINDING_COUNT);
+
+    SmartPtr<VKVideoBuffer> in_vk = param->in_buf.dynamic_cast_ptr<VKVideoBuffer> ();
+    SmartPtr<VKVideoBuffer> out_vk = param->out_buf.dynamic_cast_ptr<VKVideoBuffer> ();
+    XCAM_FAIL_RETURN (
+        ERROR, in_vk.ptr () && out_vk.ptr(), XCAM_RETURN_ERROR_VULKAN,
+        "VKGeoMapHandler(%s) param.in_buf or param.out_buf is not vk buffer", XCAM_STR (get_name ()));
+
+    VKDescriptor::SetBindInfoArray bindings (_binding_layout.size ());
+    bindings[0].layout = _binding_layout[0];
+    bindings[0].desc = VKBufDesc (in_vk->get_vk_buf (), NV12PlaneYIdx);
+    bindings[1].layout = _binding_layout[1];
+    bindings[1].desc = VKBufDesc (in_vk->get_vk_buf (), NV12PlaneUVIdx);
+    bindings[2].layout = _binding_layout[2];
+    bindings[2].desc = VKBufDesc (out_vk->get_vk_buf (), NV12PlaneYIdx);
+    bindings[3].layout = _binding_layout[3];
+    bindings[3].desc = VKBufDesc (out_vk->get_vk_buf (), NV12PlaneUVIdx);
+    bindings[4].layout = _binding_layout[4];
+    bindings[4].desc = VKBufDesc (_lut_buf);
+
+    float factor_x, factor_y;
+    get_factors (factor_x, factor_y);
+    _image_prop.lut_step[0] = 1.0f / factor_x;
+    _image_prop.lut_step[1] = 1.0f / factor_y;
+    _image_prop.lut_step[2] = _image_prop.lut_step[0];
+    _image_prop.lut_step[3] = _image_prop.lut_step[1];
+
+    SmartPtr<GeoMapArgs> args = new GeoMapArgs (param);
+    XCAM_ASSERT (args.ptr ());
+    args->set_bindings (bindings);
+    args->add_push_const (new VKGeoMapPushConst (_image_prop));
+
+    return _worker->work (args);
+}
+
+void
+VKGeoMapHandler::geomap_done (
+    const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
+{
+    if (!xcam_ret_is_ok (error)) {
+        XCAM_LOG_ERROR ("VKGeoMapHandler(%s) geometry map failed.", XCAM_STR (get_name ()));
+    }
+
+    SmartPtr<VKWorker> vk_worker = worker.dynamic_cast_ptr<VKWorker> ();
+    XCAM_ASSERT (vk_worker.ptr ());
+    vk_worker->wait_fence ();
+
+    SmartPtr<GeoMapArgs> args = base.dynamic_cast_ptr<GeoMapArgs> ();
+    XCAM_ASSERT (args.ptr ());
+    const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
+    XCAM_ASSERT (param.ptr ());
+
+    execute_done (param, error);
+}
+
+XCamReturn
+VKGeoMapHandler::remap (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf)
+{
+    SmartPtr<ImageHandler::Parameters> param = new ImageHandler::Parameters (in_buf, out_buf);
+    XCAM_ASSERT (param.ptr ());
+
+    XCamReturn ret = execute_buffer (param, false);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "VKGeoMapHandler(%s) remap failed", XCAM_STR (get_name ()));
+
+    if (!out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+SmartPtr<VKHandler> create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name)
+{
+    SmartPtr<VKHandler> mapper = new VKGeoMapHandler (dev, name);
+    XCAM_ASSERT (mapper.ptr ());
+
+    return mapper;
+}
+
+SmartPtr<GeoMapper>
+GeoMapper::create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name)
+{
+    SmartPtr<VKHandler> handler = XCam::create_vk_geo_mapper (dev, name);
+    return handler.dynamic_cast_ptr<GeoMapper> ();
+}
+
+};
diff --git a/modules/vulkan/vk_geomap_handler.h b/modules/vulkan/vk_geomap_handler.h
new file mode 100644
index 0000000..bf8d4d3
--- /dev/null
+++ b/modules/vulkan/vk_geomap_handler.h
@@ -0,0 +1,78 @@
+/*
+ * vk_geomap_handler.h - vulkan geometry map handler class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_VK_GEOMAP_HANDLER_H
+#define XCAM_VK_GEOMAP_HANDLER_H
+
+#include <xcam_utils.h>
+#include <interface/geo_mapper.h>
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_worker.h>
+#include <vulkan/vk_handler.h>
+
+namespace XCam {
+
+class VKGeoMapHandler
+    : public VKHandler, public GeoMapper
+{
+public:
+    struct PushConstsProp {
+        uint     in_img_width;
+        uint     in_img_height;
+        uint     out_img_width;
+        uint     out_img_height;
+        uint     lut_width;
+        uint     lut_height;
+        float    lut_step[4];
+        float    lut_std_step[2];
+
+        PushConstsProp ();
+    };
+
+public:
+    explicit VKGeoMapHandler (const SmartPtr<VKDevice> &dev, const char* name = "vk-geomap-handler");
+
+    bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height);
+
+    XCamReturn remap (const SmartPtr<VideoBuffer> &in_buf, SmartPtr<VideoBuffer> &out_buf);
+    void geomap_done (
+        const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error);
+
+private:
+    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    virtual XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    virtual bool init_factors ();
+
+private:
+    SmartPtr<VKWorker>               _worker;
+    PushConstsProp                   _image_prop;
+    VKDescriptor::BindingArray       _binding_layout;
+
+    SmartPtr<VKBuffer>               _lut_buf;
+    uint32_t                         _lut_width;
+    uint32_t                         _lut_height;
+};
+
+extern SmartPtr<VKHandler> create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name);
+
+}
+#endif // XCAM_VK_GEOMAP_HANDLER_H
diff --git a/modules/vulkan/vk_handler.cpp b/modules/vulkan/vk_handler.cpp
new file mode 100644
index 0000000..6aa1a83
--- /dev/null
+++ b/modules/vulkan/vk_handler.cpp
@@ -0,0 +1,60 @@
+/*
+ * vk_handler.cpp - vulkan image handler class
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_handler.h"
+#include "vk_device.h"
+#include "vk_video_buf_allocator.h"
+
+namespace XCam {
+
+VKHandler::VKHandler (const SmartPtr<VKDevice> &dev, const char* name)
+    : ImageHandler (name)
+    , _device (dev)
+{
+}
+
+VKHandler::~VKHandler ()
+{
+}
+
+
+XCamReturn
+VKHandler::finish ()
+{
+    if (_device.ptr ())
+        _device->compute_queue_wait_idle ();
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKHandler::terminate ()
+{
+    finish ();
+    return ImageHandler::terminate ();
+}
+
+SmartPtr<BufferPool>
+VKHandler::create_allocator ()
+{
+    return new VKVideoBufAllocator (_device);
+}
+
+}
diff --git a/modules/vulkan/vk_handler.h b/modules/vulkan/vk_handler.h
new file mode 100644
index 0000000..3d80fa0
--- /dev/null
+++ b/modules/vulkan/vk_handler.h
@@ -0,0 +1,57 @@
+/*
+ * vk_handler.h - vulkan image handler class
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_HANDLER_H
+#define XCAM_VK_HANDLER_H
+
+#include <vulkan/vulkan_std.h>
+#include <image_handler.h>
+
+namespace XCam {
+
+class VKDevice;
+
+class VKHandler
+    : public ImageHandler
+{
+public:
+    explicit VKHandler (const SmartPtr<VKDevice> &dev, const char* name = "vk-handler");
+    ~VKHandler ();
+    const SmartPtr<VKDevice> &get_vk_device () const {
+        return _device;
+    }
+
+    // derive from ImageHandler
+    virtual XCamReturn finish ();
+    virtual XCamReturn terminate ();
+
+protected:
+    SmartPtr<BufferPool> create_allocator ();
+
+private:
+    XCAM_DEAD_COPY (VKHandler);
+
+protected:
+    SmartPtr<VKDevice>      _device;
+};
+
+}
+
+#endif //XCAM_VK_HANDLER_H
diff --git a/modules/vulkan/vk_instance.cpp b/modules/vulkan/vk_instance.cpp
new file mode 100644
index 0000000..81b3e6d
--- /dev/null
+++ b/modules/vulkan/vk_instance.cpp
@@ -0,0 +1,230 @@
+/*
+ * vk_instance.cpp - vulkan instance
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_instance.h"
+#include "vulkan_common.h"
+
+#define APP_NAME "xcam"
+#define ENGINE_NAME "xcam"
+
+#define XCAM_INVALID_VK_QUEUE_IDX UINT32_MAX
+
+namespace XCam {
+
+extern void vk_init_error_string ();
+
+SmartPtr<VKInstance> VKInstance::_instance;
+Mutex VKInstance::_instance_mutex;
+
+VKInstance::~VKInstance ()
+{
+    if (XCAM_IS_VALID_VK_ID (_instance_id))
+        vkDestroyInstance (_instance_id, _allocator.ptr ());
+}
+
+VKInstance::VKInstance (VkInstance id, VkAllocationCallbacks *allocator)
+    : _instance_id (id)
+    , _allocator (allocator)
+    , _physical_device (NULL)
+    , _compute_queue_family_idx (XCAM_INVALID_VK_QUEUE_IDX)
+    , _graphics_queue_family_idx (XCAM_INVALID_VK_QUEUE_IDX)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id));
+    xcam_mem_clear (_device_properties);
+    xcam_mem_clear (_dev_mem_properties);
+}
+
+SmartPtr<VKInstance>
+VKInstance::get_instance ()
+{
+    SmartLock locker (_instance_mutex);
+    if (!_instance.ptr ()) {
+        vk_init_error_string ();
+        _instance = create_instance ();
+    }
+    return _instance;
+}
+
+SmartPtr<VKInstance>
+VKInstance::create_instance ()
+{
+    VkApplicationInfo app_info = {};
+    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    app_info.pApplicationName = APP_NAME;
+    app_info.applicationVersion = 0;
+    app_info.pEngineName = ENGINE_NAME;
+    app_info.engineVersion = xcam_version ();
+    app_info.apiVersion = VK_API_VERSION_1_0;
+
+    VkInstance id;
+    VkInstanceCreateInfo inst_create_info = {};
+    inst_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+    inst_create_info.pApplicationInfo = &app_info;
+    inst_create_info.enabledExtensionCount = 0; // TODO, add extensions
+    XCAM_VK_CHECK_RETURN(
+        ERROR, vkCreateInstance (&inst_create_info, NULL, &id),
+        NULL, "create vk instance failed");
+
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id));
+    SmartPtr<VKInstance> vk_instance = new VKInstance (id, NULL);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (vk_instance->query_physical_info ()), NULL,
+        "vk instance query physical info failed");
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (vk_instance->query_queue_info ()), NULL,
+        "vk instance query queue info failed");
+
+    return vk_instance;
+}
+
+static const char *s_device_types[] = {
+    "OTHER_DEVICE",
+    "INTEGRATED_GPU",
+    "DISCRETE_GPU",
+    "VIRTUAL_GPU",
+    "CPU_TYPE",
+};
+
+static const char*
+device_type_to_str(VkPhysicalDeviceType type)
+{
+    size_t number = sizeof (s_device_types) / sizeof (s_device_types[0]);
+    assert (number == 5);
+    if ((size_t)type < number)
+        return s_device_types [type];
+    return "UNKNOWN_TYPE";
+}
+
+XCamReturn
+VKInstance::query_physical_info ()
+{
+#define MAX_DEV_NUM 256
+    VkPhysicalDevice devs[MAX_DEV_NUM];
+    uint32_t dev_num = 0;
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkEnumeratePhysicalDevices (_instance_id, &dev_num, NULL),
+        XCAM_RETURN_ERROR_VULKAN, "enum vk physical devices failed");
+    XCAM_FAIL_RETURN (
+        ERROR, dev_num, XCAM_RETURN_ERROR_VULKAN,
+        "There is NO vk physical devices");
+
+    dev_num = XCAM_MIN (dev_num, MAX_DEV_NUM);
+    vkEnumeratePhysicalDevices (_instance_id, &dev_num, devs);
+
+    VkPhysicalDevice gpu_dev[VK_PHYSICAL_DEVICE_TYPE_RANGE_SIZE] = {};
+
+    VkPhysicalDeviceProperties dev_prop;
+    for (uint32_t i = 0; i < dev_num; ++i) {
+        vkGetPhysicalDeviceProperties (devs[i], &dev_prop);
+
+        if (dev_prop.deviceType < VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE ||
+                dev_prop.deviceType > VK_PHYSICAL_DEVICE_TYPE_END_RANGE) {
+            continue;
+        }
+        if (gpu_dev[dev_prop.deviceType]) {
+            XCAM_LOG_WARNING (
+                "double vk physical dev, type:%d, name:%s",
+                dev_prop.deviceType, dev_prop.deviceName);
+            continue;
+        }
+        gpu_dev[dev_prop.deviceType] = devs[i];
+#if 0
+        printf ("found vk physical dev_id:%d, name:%s, type:%d, API:%d\n",
+                dev_prop.deviceID, dev_prop.deviceName,
+                device_type_to_str (dev_prop.deviceType), dev_prop.apiVersion);
+#endif
+    }
+
+    if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU])
+        _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU];
+    else if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU])
+        _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU];
+    else if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU])
+        _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU];
+    else if (gpu_dev[VK_PHYSICAL_DEVICE_TYPE_CPU]) {
+        _physical_device = gpu_dev[VK_PHYSICAL_DEVICE_TYPE_CPU];
+        XCAM_LOG_WARNING ("vk device select physical CPU, performance may slow down");
+    } else {
+        XCAM_LOG_ERROR ("did NOT find available vk physical device");
+        return XCAM_RETURN_ERROR_VULKAN;
+    }
+
+    vkGetPhysicalDeviceProperties (_physical_device, &dev_prop);
+    XCAM_LOG_INFO ("choose vk physical dev properties dev_id:%d, name:%s, type:%s, API:%d\n",
+                   dev_prop.deviceID, dev_prop.deviceName,
+                   device_type_to_str (dev_prop.deviceType), dev_prop.apiVersion);
+    _device_properties = dev_prop;
+    vkGetPhysicalDeviceMemoryProperties (_physical_device, &_dev_mem_properties);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKInstance::query_queue_info ()
+{
+    XCAM_ASSERT (_physical_device);
+    // get queue family porperties
+    uint32_t queue_count = 0;
+#define MAX_QUEUE_FAMILY_NUM 256
+    VkQueueFamilyProperties queue_family[MAX_QUEUE_FAMILY_NUM];
+
+    vkGetPhysicalDeviceQueueFamilyProperties (
+        _physical_device, &queue_count, NULL);
+    XCAM_FAIL_RETURN (
+        ERROR, queue_count, XCAM_RETURN_ERROR_VULKAN,
+        "There is NO vk physical devices");
+
+    if (queue_count > MAX_QUEUE_FAMILY_NUM)
+        queue_count = MAX_QUEUE_FAMILY_NUM;
+
+    vkGetPhysicalDeviceQueueFamilyProperties (
+        _physical_device, &queue_count, queue_family);
+
+    for (uint32_t i = 0; i < queue_count; ++i) {
+        if (queue_family[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
+            _compute_queue_family_idx = i;
+        }
+        if (queue_family[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+            _graphics_queue_family_idx = i;
+        }
+    }
+
+    XCAM_FAIL_RETURN (
+        ERROR,
+        _compute_queue_family_idx != XCAM_INVALID_VK_QUEUE_IDX &&
+        _graphics_queue_family_idx != XCAM_INVALID_VK_QUEUE_IDX,
+        XCAM_RETURN_ERROR_VULKAN,
+        "There is NO vk compute/graphics queue family");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+uint32_t
+VKInstance::get_mem_type_index (VkMemoryPropertyFlags prop) const
+{
+    for (uint32_t i = 0; i < _dev_mem_properties.memoryTypeCount; ++i) {
+        if (((uint32_t)(_dev_mem_properties.memoryTypes[i].propertyFlags) & prop) == prop)
+            return i;
+    }
+    return (uint32_t)(-1);
+}
+
+}
diff --git a/modules/vulkan/vk_instance.h b/modules/vulkan/vk_instance.h
new file mode 100644
index 0000000..b4b51d4
--- /dev/null
+++ b/modules/vulkan/vk_instance.h
@@ -0,0 +1,77 @@
+/*
+ * vk_instance.h - vulkan instance
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_INSTANCE_H
+#define XCAM_VK_INSTANCE_H
+
+#include <vulkan/vulkan_std.h>
+#include <xcam_mutex.h>
+
+namespace XCam {
+
+class VKInstance
+{
+public:
+    ~VKInstance ();
+    static SmartPtr<VKInstance> get_instance ();
+
+    VkInstance get_id () const {
+        return _instance_id;
+    }
+    VkPhysicalDevice get_physical_dev () const {
+        return _physical_device;
+    }
+    uint32_t get_compute_queue_family_idx () const {
+        return _compute_queue_family_idx;
+    }
+    uint32_t get_graphics_queue_family_idx () const {
+        return _graphics_queue_family_idx;
+    }
+    uint32_t get_mem_type_index (VkMemoryPropertyFlags prop) const;
+
+    SmartPtr<VkAllocationCallbacks> get_allocator () const {
+        return _allocator;
+    }
+
+private:
+    explicit VKInstance (VkInstance id, VkAllocationCallbacks *allocator);
+    static SmartPtr<VKInstance> create_instance ();
+    XCamReturn query_physical_info ();
+    XCamReturn query_queue_info ();
+
+private:
+    XCAM_DEAD_COPY (VKInstance);
+
+private:
+    static SmartPtr<VKInstance>      _instance;
+    static Mutex                     _instance_mutex;
+
+    VkInstance                       _instance_id;
+    SmartPtr<VkAllocationCallbacks>  _allocator;
+    VkPhysicalDevice                 _physical_device;
+    VkPhysicalDeviceProperties       _device_properties;
+    VkPhysicalDeviceMemoryProperties _dev_mem_properties;
+    uint32_t                         _compute_queue_family_idx;
+    uint32_t                         _graphics_queue_family_idx;
+};
+
+}
+
+#endif  //XCAM_VK_INSTANCE_H
diff --git a/modules/vulkan/vk_memory.cpp b/modules/vulkan/vk_memory.cpp
new file mode 100644
index 0000000..09af690
--- /dev/null
+++ b/modules/vulkan/vk_memory.cpp
@@ -0,0 +1,182 @@
+/*
+ * vk_memory.cpp - Vulkan memory
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_memory.h"
+#include "vk_device.h"
+
+namespace XCam {
+
+VKBufInfo::VKBufInfo ()
+    : format (V4L2_PIX_FMT_NV12)
+    , width (0)
+    , height (0)
+    , aligned_width (0)
+    , aligned_height (0)
+    , size (0)
+{
+    xcam_mem_clear (strides);
+    xcam_mem_clear (offsets);
+    xcam_mem_clear (slice_size);
+}
+
+VKMemory::VKMemory (
+    const SmartPtr<VKDevice> dev,
+    VkDeviceMemory id,
+    uint32_t size,
+    VkMemoryPropertyFlags mem_prop)
+    : _dev (dev)
+    , _mem_id (id)
+    , _mem_prop (mem_prop)
+    , _size (size)
+    , _mapped_ptr (NULL)
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (id));
+}
+
+VKMemory::~VKMemory ()
+{
+    if (XCAM_IS_VALID_VK_ID (_mem_id) && _dev.ptr ()) {
+        _dev->free_mem_id (_mem_id);
+    }
+}
+
+void *
+VKMemory::map (VkDeviceSize size, VkDeviceSize offset)
+{
+    if (_mapped_ptr)
+        return _mapped_ptr;
+
+    XCAM_FAIL_RETURN (
+        ERROR,
+        xcam_ret_is_ok (_dev->map_mem (_mem_id, size, offset, _mapped_ptr)), NULL,
+        "VK memory map failed");
+
+    return _mapped_ptr;
+}
+
+void
+VKMemory::unmap ()
+{
+    if (_mapped_ptr) {
+        _dev->unmap_mem (_mem_id);
+        _mapped_ptr = NULL;
+    }
+}
+
+VKBuffer::VKBuffer (
+    const SmartPtr<VKDevice> dev,
+    VkBuffer buf_id,
+    VkDeviceMemory mem_id,
+    uint32_t size,
+    VkBufferUsageFlags usage,
+    VkMemoryPropertyFlags prop)
+    : VKMemory (dev, mem_id, size, prop)
+    , _buffer_id (buf_id)
+    , _usage_flags (usage)
+    , _prop_flags (prop)
+{
+}
+
+VKBuffer::~VKBuffer ()
+{
+    if (XCAM_IS_VALID_VK_ID (_buffer_id) && _dev.ptr ()) {
+        _dev->destroy_buf_id (_buffer_id);
+    }
+}
+
+XCamReturn
+VKBuffer::bind ()
+{
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_buffer_id));
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_mem_id));
+
+    return _dev->bind_buffer (_buffer_id, _mem_id, 0);
+}
+
+SmartPtr<VKBuffer>
+VKBuffer::create_buffer (
+    const SmartPtr<VKDevice> dev,
+    VkBufferUsageFlags usage,
+    uint32_t size,  void *data,
+    VkMemoryPropertyFlags mem_prop)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, dev.ptr () && size, NULL,
+        "vk create buffer failed because of dev or size errors");
+
+    VkBuffer buf_id = dev->create_buf_id (usage, size);
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (buf_id), NULL,
+        "vk create buffer failed");
+
+    VkDevice dev_id = dev->get_dev_id ();
+    VkMemoryRequirements mem_reqs;
+    vkGetBufferMemoryRequirements (dev_id, buf_id, &mem_reqs);
+    VkDeviceMemory mem_id = dev->allocate_mem_id (mem_reqs.size, mem_prop);
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (mem_id), NULL,
+        "vk create buffer failed in mem allocation");
+
+    // size == mem_reqs.size or size?
+    SmartPtr<VKBuffer> buf = new VKBuffer (dev, buf_id, mem_id, size, usage, mem_prop);
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (buf->bind ()), NULL,
+        "vk create bufer failed when bind with memory");
+    if (!data)
+        return buf;
+
+    void *ptr = buf->map ();
+    XCAM_FAIL_RETURN (
+        ERROR, ptr, NULL,
+        "vk create bufer failed when map the buf");
+    memcpy (ptr, data, size);
+    buf->unmap ();
+
+    return buf;
+
+}
+
+VKBufDesc::VKBufDesc ()
+{
+    xcam_mem_clear (desc_info);
+}
+
+VKBufDesc::VKBufDesc (const SmartPtr<VKBuffer> &buffer, NV12PlaneIdx plane)
+    : buf (buffer)
+{
+    xcam_mem_clear (desc_info);
+    const VKBufInfo info = buffer->get_buf_info ();
+
+    desc_info.buffer = buffer->get_buf_id ();
+    desc_info.offset = info.offsets[plane];
+    desc_info.range = info.slice_size[plane];
+}
+
+VKBufDesc::VKBufDesc (const SmartPtr<VKBuffer> &buffer, uint32_t offset, size_t size)
+    : buf (buffer)
+{
+    xcam_mem_clear (desc_info);
+    desc_info.buffer = buffer->get_buf_id ();
+    desc_info.offset = offset;
+    desc_info.range = size;
+}
+
+}
diff --git a/modules/vulkan/vk_memory.h b/modules/vulkan/vk_memory.h
new file mode 100644
index 0000000..3eba942
--- /dev/null
+++ b/modules/vulkan/vk_memory.h
@@ -0,0 +1,134 @@
+/*
+ * vk_memory.h - Vulkan memory
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_MEMORY_H
+#define XCAM_VK_MEMORY_H
+
+#include <vulkan/vulkan_std.h>
+
+#define XCAM_VK_MAX_COMPONENTS 4
+
+namespace XCam {
+
+struct VKBufInfo {
+    uint32_t        format;
+    uint32_t        width;
+    uint32_t        height;
+    uint32_t        aligned_width;
+    uint32_t        aligned_height;
+    uint32_t        size;
+    uint32_t        strides[XCAM_VK_MAX_COMPONENTS];
+    uint32_t        offsets[XCAM_VK_MAX_COMPONENTS];
+    uint32_t        slice_size[XCAM_VK_MAX_COMPONENTS];
+
+    VKBufInfo ();
+    bool operator == (const VKBufInfo &info) const;
+};
+
+class VKDevice;
+
+class VKMemory
+{
+public:
+    virtual ~VKMemory ();
+    void *map (VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0);
+    void unmap ();
+
+protected:
+    explicit VKMemory (
+        const SmartPtr<VKDevice> dev, VkDeviceMemory id,
+        uint32_t size, VkMemoryPropertyFlags mem_prop);
+    VkDeviceMemory get_mem_id () const {
+        return _mem_id;
+    }
+
+private:
+    XCAM_DEAD_COPY (VKMemory);
+
+protected:
+    const SmartPtr<VKDevice>     _dev;
+    VkDeviceMemory               _mem_id;
+    VkMemoryPropertyFlags        _mem_prop;
+    uint32_t                     _size;
+    void                        *_mapped_ptr;
+};
+
+class VKBuffer
+    : public VKMemory
+{
+public:
+    ~VKBuffer ();
+
+    // usage can be VK_BUFFER_USAGE_STORAGE_BUFFER_BIT or VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+    static SmartPtr<VKBuffer>
+    create_buffer (
+        const SmartPtr<VKDevice> dev,
+        VkBufferUsageFlags usage,
+        uint32_t size,  void *data = NULL,
+        VkMemoryPropertyFlags mem_prop = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+
+    VkBuffer get_buf_id () const {
+        return _buffer_id;
+    }
+    VkBufferUsageFlags get_usage_flags () const {
+        return _usage_flags;
+    }
+    VkMemoryPropertyFlags get_mem_flags () const {
+        return _prop_flags;
+    }
+
+    void set_buf_info (const VKBufInfo &info) {
+        _buf_info = info;
+    }
+    const VKBufInfo &get_buf_info () const {
+        return _buf_info;
+    }
+
+private:
+    explicit VKBuffer (
+        const SmartPtr<VKDevice> dev, VkBuffer buf_id,
+        VkDeviceMemory mem_id, uint32_t size,
+        VkBufferUsageFlags usage, VkMemoryPropertyFlags prop);
+    XCamReturn bind ();
+
+private:
+    XCAM_DEAD_COPY (VKBuffer);
+
+private:
+    VkBuffer                         _buffer_id;
+    VkBufferUsageFlags               _usage_flags;
+    VkMemoryPropertyFlags            _prop_flags;
+    VKBufInfo                        _buf_info;
+};
+
+struct VKBufDesc {
+    SmartPtr<VKBuffer>        buf;
+    VkDescriptorBufferInfo    desc_info;
+
+    VKBufDesc ();
+    VKBufDesc (const SmartPtr<VKBuffer> &buffer, NV12PlaneIdx plane);
+    VKBufDesc (const SmartPtr<VKBuffer> &buffer, uint32_t offset = 0, size_t size = VK_WHOLE_SIZE);
+};
+
+typedef std::vector<SmartPtr<VKBuffer>>  VKBufferArray;
+
+}
+
+#endif  //XCAM_VK_MEMORY_H
diff --git a/modules/vulkan/vk_pipeline.cpp b/modules/vulkan/vk_pipeline.cpp
new file mode 100644
index 0000000..5483582
--- /dev/null
+++ b/modules/vulkan/vk_pipeline.cpp
@@ -0,0 +1,293 @@
+/*
+ * vk_pipeline.cpp - Vulkan pipeline
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_pipeline.h"
+#include "vulkan_common.h"
+#include "vk_cmdbuf.h"
+
+namespace XCam {
+
+VKPipeline::VKPipeline (
+    const SmartPtr<VKDevice> dev,
+    const ShaderVec &shaders,
+    const VKDescriptor::BindingArray &bindings,
+    const VKConstRange::VKConstantArray &consts)
+    : _pipe_id (VK_NULL_HANDLE)
+    , _dev (dev)
+    , _shaders (shaders)
+    , _bindings (bindings)
+    , _push_consts (consts)
+{
+    _allocator = _dev->get_allocation_cb ();
+    xcam_mem_clear (_name);
+}
+
+VKPipeline::~VKPipeline ()
+{
+    if (!_dev.ptr ())
+        return;
+
+    VkDevice dev_id = _dev->get_dev_id ();
+    if (XCAM_IS_VALID_VK_ID (_pipe_id))
+        vkDestroyPipeline (dev_id, _pipe_id, _allocator.ptr ());
+}
+
+void
+VKPipeline::set_desc_pool (const SmartPtr<VKDescriptor::Pool> pool)
+{
+    _pool = pool;
+
+    //TODO, check pool status and allocate set, need or not?
+}
+
+VkDescriptorSetLayout
+VKPipeline::create_desc_set_layout (
+    const VKDescriptor::BindingArray &bindings)
+{
+    VKDescriptor::VkBindingArray array = VKDescriptor::get_vk_layoutbindings (bindings);
+
+    VkDescriptorSetLayoutCreateInfo descriptor_layout = {};
+    descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+    descriptor_layout.bindingCount = array.size ();
+    descriptor_layout.pBindings = array.data ();
+
+    VkDescriptorSetLayout layout = NULL;
+    XCAM_VK_CHECK_RETURN (
+        ERROR,
+        vkCreateDescriptorSetLayout (
+            _dev->get_dev_id (), &descriptor_layout, _allocator.ptr (), &layout),
+        NULL, "VkPipeline create descriptor set layout failed");
+
+    return layout;
+}
+
+
+VkPipelineLayout
+VKPipeline::create_pipeline_layout (
+    VkDescriptorSetLayout desc_layout,
+    const VKConstRange::VKConstantArray &consts)
+{
+    VkPipelineLayoutCreateInfo pipe_layout_create_info = {};
+    pipe_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    pipe_layout_create_info.flags = 0;
+    pipe_layout_create_info.setLayoutCount = 1;
+    pipe_layout_create_info.pSetLayouts = &desc_layout;
+    if (!consts.empty()) {
+        pipe_layout_create_info.pushConstantRangeCount = consts.size ();
+        pipe_layout_create_info.pPushConstantRanges = consts.data ();
+    }
+
+    VkPipelineLayout layout = NULL;
+    XCAM_VK_CHECK_RETURN (
+        ERROR,
+        vkCreatePipelineLayout (
+            _dev->get_dev_id (), &pipe_layout_create_info, NULL, &layout),
+        NULL, "VkPipeline create descriptor set layout failed");
+
+    return layout;
+}
+
+SmartPtr<VKPipeline>
+VKPipeline::create_compute_pipeline (
+    const SmartPtr<VKDevice> dev,
+    const SmartPtr<VKShader> shader,
+    const VKDescriptor::BindingArray &bindings,
+    const VKConstRange::VKConstantArray &consts)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, dev.ptr () && shader.ptr (), NULL,
+        "VKDevice create pipeline with error of null device ready.");
+
+    ShaderVec shaders = {shader};
+    SmartPtr<VKPipeline> pipe = new VKComputePipeline (dev, shaders, bindings, consts);
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (pipe->ensure_layouts ()), NULL,
+        "vk pipeline ensure layouts failed");
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (pipe->ensure_pipeline ()), NULL,
+        "vk pipeline ensure pipeline failed");
+
+    return pipe;
+}
+
+VKComputePipeline::VKComputePipeline (
+    const SmartPtr<VKDevice> dev,
+    const ShaderVec &shaders,
+    const VKDescriptor::BindingArray &bindings,
+    const VKConstRange::VKConstantArray &consts)
+    : VKPipeline (dev, shaders, bindings, consts)
+    , _pipe_layout (VK_NULL_HANDLE)
+    , _desc_layout (VK_NULL_HANDLE)
+{
+}
+
+VKComputePipeline::~VKComputePipeline ()
+{
+    if (!_dev.ptr ())
+        return;
+
+    VkDevice dev_id = _dev->get_dev_id ();
+    if (XCAM_IS_VALID_VK_ID (_pipe_layout))
+        vkDestroyPipelineLayout (dev_id, _pipe_layout, _allocator.ptr ());
+    if (XCAM_IS_VALID_VK_ID (_desc_layout))
+        vkDestroyDescriptorSetLayout (dev_id, _desc_layout, _allocator.ptr ());
+}
+
+XCamReturn
+VKComputePipeline::ensure_layouts ()
+{
+    if (!XCAM_IS_VALID_VK_ID (_desc_layout)) {
+        _desc_layout = create_desc_set_layout (_bindings);
+    }
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID(_desc_layout), XCAM_RETURN_ERROR_VULKAN,
+        "vk compute pipeline create desc layout failed");
+
+    if (!XCAM_IS_VALID_VK_ID (_pipe_layout)) {
+        _pipe_layout = create_pipeline_layout (_desc_layout, _push_consts);
+    }
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID(_pipe_layout), XCAM_RETURN_ERROR_VULKAN,
+        "vk compute pipeline create pipeline layout failed");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKComputePipeline::ensure_pipeline ()
+{
+    XCAM_FAIL_RETURN (
+        ERROR, XCAM_IS_VALID_VK_ID (_desc_layout) && XCAM_IS_VALID_VK_ID (_pipe_layout),
+        XCAM_RETURN_ERROR_PARAM,
+        "vk compute ensure pipeline failed. need ensure desc_layout and pipe_layout first");
+
+    XCAM_FAIL_RETURN (
+        ERROR, !_shaders.empty (), XCAM_RETURN_ERROR_PARAM,
+        "vk compute ensure pipeline failed, shader was empty");
+
+    VkComputePipelineCreateInfo pipeline_create_info =
+        get_compute_create_info (_shaders[0], _pipe_layout);
+
+    VkPipeline pipe_id;
+    XCAM_VK_CHECK_RETURN (
+        ERROR, vkCreateComputePipelines (
+            _dev->get_dev_id (), 0, 1, &pipeline_create_info, 0, &pipe_id),
+        XCAM_RETURN_ERROR_VULKAN, "VK create compute pipeline failed.");
+
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (pipe_id));
+    _pipe_id = pipe_id;
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKComputePipeline::update_bindings (const VKDescriptor::SetBindInfoArray &bind_array)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _pool.ptr () && XCAM_IS_VALID_VK_ID (_desc_layout), XCAM_RETURN_ERROR_PARAM,
+        "vk compute pipeline update bindins failed, pool was not set or desc_layout not ensured");
+
+    if (_desc_set.ptr ())
+        _desc_set.release ();
+
+    _desc_set = _pool->allocate_set (bind_array, _desc_layout);
+    XCAM_FAIL_RETURN (
+        ERROR, _desc_set.ptr (), XCAM_RETURN_ERROR_UNKNOWN,
+        "vk compute pipeline update bindins failed to allocate desc_set or update bindings");
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKComputePipeline::bind_by (VKCmdBuf &cmd_buf)
+{
+
+    VkCommandBuffer buf_id = cmd_buf.get_cmd_buf_id ();
+    VkPipeline pipe_id = get_pipeline_id ();
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (buf_id));
+    XCAM_FAIL_RETURN (
+        ERROR,
+        XCAM_IS_VALID_VK_ID (pipe_id) && XCAM_IS_VALID_VK_ID (_pipe_layout) && _desc_set.ptr (),
+        XCAM_RETURN_ERROR_PARAM,
+        "vk compute pipeline bind command buffer failed, please check pipe_id, pipe_layout and desc_layout.");
+
+    // // bind pipeline sets
+    vkCmdBindPipeline (buf_id, VK_PIPELINE_BIND_POINT_COMPUTE, pipe_id);
+
+    // bind descriptor sets
+    VkDescriptorSet desc_set_id = _desc_set->get_set_id ();
+    vkCmdBindDescriptorSets (
+        buf_id, VK_PIPELINE_BIND_POINT_COMPUTE, _pipe_layout,
+        0, 1, &desc_set_id, 0, NULL);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKComputePipeline::push_consts_by (
+    VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const)
+{
+    VkCommandBuffer cmd_buf_id = cmd_buf.get_cmd_buf_id ();
+    XCAM_FAIL_RETURN (
+        ERROR,
+        XCAM_IS_VALID_VK_ID (cmd_buf_id) && XCAM_IS_VALID_VK_ID (_pipe_layout),
+        XCAM_RETURN_ERROR_PARAM,
+        "vk compute pipeline push_consts by cmdbuf failed, please check pipe_layout and cmd_buf_id.");
+
+    XCAM_ASSERT (push_const.ptr ());
+    VkPushConstantRange const_range;
+    xcam_mem_clear (const_range);
+    void *ptr = NULL;
+    push_const->get_const_data (const_range, ptr);
+
+    XCAM_FAIL_RETURN (
+        ERROR,
+        const_range.stageFlags == VK_SHADER_STAGE_COMPUTE_BIT,
+        XCAM_RETURN_ERROR_PARAM,
+        "vk compute pipeline push_consts by cmdbuf failed, please check pipe_layout and cmd_buf_id.");
+
+    vkCmdPushConstants(
+        cmd_buf_id, _pipe_layout, VK_SHADER_STAGE_COMPUTE_BIT, const_range.offset, const_range.size, ptr);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+VkComputePipelineCreateInfo
+VKComputePipeline::get_compute_create_info (
+    const SmartPtr<VKShader> &shader,
+    VkPipelineLayout &layout)
+{
+    VkPipelineShaderStageCreateInfo shader_stage_create_info = {};
+    shader_stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    shader_stage_create_info.flags = 0;
+    shader_stage_create_info.stage = shader->get_shader_stage_flags ();
+    shader_stage_create_info.module = shader->get_shader_id ();
+    shader_stage_create_info.pName = shader->get_func_name ();
+
+    VkComputePipelineCreateInfo pipeline_create_info = { };
+    pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+    pipeline_create_info.pNext = NULL;
+    pipeline_create_info.flags = 0;
+    pipeline_create_info.stage = shader_stage_create_info;
+    pipeline_create_info.layout = layout;
+
+    return pipeline_create_info;
+}
+
+}
diff --git a/modules/vulkan/vk_pipeline.h b/modules/vulkan/vk_pipeline.h
new file mode 100644
index 0000000..cecb99b
--- /dev/null
+++ b/modules/vulkan/vk_pipeline.h
@@ -0,0 +1,127 @@
+/*
+ * vk_pipeline.h - Vulkan pipeline
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_PIPELINE_H
+#define XCAM_VK_PIPELINE_H
+
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_descriptor.h>
+#include <vulkan/vk_device.h>
+#include <vulkan/vk_shader.h>
+
+namespace XCam {
+
+class VKPipeline
+{
+public:
+    static SmartPtr<VKPipeline>
+    create_compute_pipeline (
+        const SmartPtr<VKDevice> dev,
+        const SmartPtr<VKShader> shader,
+        const VKDescriptor::BindingArray &bindings,
+        const VKConstRange::VKConstantArray &consts);
+
+    virtual ~VKPipeline ();
+
+    VkPipeline get_pipeline_id () const {
+        return _pipe_id;
+    }
+    const char *get_name () const {
+        return _name;
+    }
+    void set_desc_pool (const SmartPtr<VKDescriptor::Pool> pool);
+    //interface
+    virtual XCamReturn update_bindings (const VKDescriptor::SetBindInfoArray &bind_array) = 0;
+
+    // inter-functions, called by VKCmdBuf
+    virtual XCamReturn bind_by (VKCmdBuf &cmd_buf) = 0;
+    virtual XCamReturn push_consts_by (
+        VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const) = 0;
+
+protected:
+    explicit VKPipeline (
+        const SmartPtr<VKDevice> dev,
+        const ShaderVec &shaders,
+        const VKDescriptor::BindingArray &bindings,
+        const VKConstRange::VKConstantArray &consts);
+
+    VkDescriptorSetLayout create_desc_set_layout (
+        const VKDescriptor::BindingArray &bindings);
+
+    VkPipelineLayout create_pipeline_layout (
+        VkDescriptorSetLayout desc_layout,
+        const VKConstRange::VKConstantArray &consts);
+
+    // intra virtual functions
+    virtual XCamReturn ensure_layouts () = 0;
+    virtual XCamReturn ensure_pipeline () = 0;
+
+private:
+    XCAM_DEAD_COPY (VKPipeline);
+
+protected:
+    VkPipeline                       _pipe_id;
+    char                             _name [XCAM_VK_NAME_LENGTH];
+
+    SmartPtr<VKDevice>               _dev;
+    SmartPtr<VkAllocationCallbacks>  _allocator;
+    ShaderVec                        _shaders;
+    VKDescriptor::BindingArray       _bindings;
+    VKConstRange::VKConstantArray    _push_consts;
+    SmartPtr<VKDescriptor::Pool>     _pool;
+};
+
+class VKComputePipeline
+    : public VKPipeline
+{
+    friend class VKPipeline;
+
+public:
+    static VkComputePipelineCreateInfo
+    get_compute_create_info (const SmartPtr<VKShader> &shader, VkPipelineLayout &layout);
+
+    ~VKComputePipeline ();
+
+    //inherit from VKPipeline
+    XCamReturn update_bindings (const VKDescriptor::SetBindInfoArray &bind_array);
+
+protected:
+    explicit VKComputePipeline (
+        const SmartPtr<VKDevice> dev,
+        const ShaderVec &shaders,
+        const VKDescriptor::BindingArray &bindings,
+        const VKConstRange::VKConstantArray &consts);
+
+    //virtual functions from VKPipeline
+    XCamReturn ensure_layouts ();
+    XCamReturn ensure_pipeline ();
+    XCamReturn bind_by (VKCmdBuf &cmd_buf);
+    XCamReturn push_consts_by (
+        VKCmdBuf &cmd_buf, const SmartPtr<VKConstRange::VKPushConstArg> &push_const);
+
+private:
+    VkPipelineLayout                 _pipe_layout;
+    VkDescriptorSetLayout            _desc_layout;
+    SmartPtr<VKDescriptor::Set>      _desc_set;
+};
+
+}
+
+#endif  //XCAM_VK_PIPELINE_H
diff --git a/modules/vulkan/vk_shader.cpp b/modules/vulkan/vk_shader.cpp
new file mode 100644
index 0000000..96e0427
--- /dev/null
+++ b/modules/vulkan/vk_shader.cpp
@@ -0,0 +1,60 @@
+/*
+ * vk_shader.cpp - vulkan shader module
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_shader.h"
+#include "vk_device.h"
+#include "file_handle.h"
+
+namespace XCam {
+
+VKShader::VKShader (SmartPtr<VKDevice> dev, VkShaderModule id, const char *name)
+    : _device (dev)
+    , _shader_id (id)
+    , _shader_stage (VK_SHADER_STAGE_COMPUTE_BIT)
+{
+    XCAM_IS_VALID_VK_ID (id);
+    xcam_mem_clear (_name);
+    if (name)
+        strncpy (_name, name, XCAM_VK_NAME_LENGTH - 1);
+    strncpy (_func_name, "main", XCAM_VK_NAME_LENGTH - 1);
+}
+
+VKShader::~VKShader ()
+{
+    if (XCAM_IS_VALID_VK_ID (_shader_id))
+        _device->destroy_shader_id (_shader_id);
+}
+
+void
+VKShader::set_func_name (const char *name)
+{
+    XCAM_ASSERT (name);
+    strncpy (_func_name, name, XCAM_VK_NAME_LENGTH - 1);
+}
+
+void
+VKShader::set_name (const char *name)
+{
+    XCAM_ASSERT (name);
+    strncpy (_name, name, XCAM_VK_NAME_LENGTH - 1);
+}
+
+
+}
diff --git a/modules/vulkan/vk_shader.h b/modules/vulkan/vk_shader.h
new file mode 100644
index 0000000..fd243bb
--- /dev/null
+++ b/modules/vulkan/vk_shader.h
@@ -0,0 +1,71 @@
+/*
+ * vk_shader.h - Vulkan shader module
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_SHADER_H
+#define XCAM_VK_SHADER_H
+
+#include <vulkan/vulkan_std.h>
+
+namespace XCam {
+
+class VKDevice;
+
+class VKShader
+{
+    friend class VKDevice;
+public:
+    ~VKShader ();
+
+    VkShaderModule get_shader_id () const {
+        return _shader_id;
+    }
+    VkShaderStageFlagBits get_shader_stage_flags () const {
+        return _shader_stage;
+    }
+    void set_func_name (const char *name);
+    void set_name (const char *name);
+    const char *get_func_name () const {
+        return _func_name;
+    }
+    const char *get_name () const {
+        return _name;
+    }
+
+private:
+    explicit VKShader (SmartPtr<VKDevice> dev, VkShaderModule id, const char *name = "null");
+
+private:
+    XCAM_DEAD_COPY (VKShader);
+
+private:
+    //static ShaderTable               _shader_cache;
+    //static Mutex                     _cache_mutex;
+    SmartPtr<VKDevice>               _device;
+    VkShaderModule                   _shader_id;
+    VkShaderStageFlagBits            _shader_stage;
+    char                             _func_name [XCAM_VK_NAME_LENGTH];
+    char                             _name [XCAM_VK_NAME_LENGTH];
+};
+
+typedef std::vector<SmartPtr<VKShader>> ShaderVec;
+
+}
+
+#endif  //XCAM_VK_SHADER_H
diff --git a/modules/vulkan/vk_stitcher.cpp b/modules/vulkan/vk_stitcher.cpp
new file mode 100644
index 0000000..f074e48
--- /dev/null
+++ b/modules/vulkan/vk_stitcher.cpp
@@ -0,0 +1,824 @@
+/*
+ * vk_stitcher.cpp - Vulkan stitcher implementation
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "surview_fisheye_dewarp.h"
+#include "vk_video_buf_allocator.h"
+#include "vk_geomap_handler.h"
+#include "vk_blender.h"
+#include "vk_copy_handler.h"
+#include "vk_stitcher.h"
+#include "interface/feature_match.h"
+
+#define DUMP_BUFFER 0
+
+#define GEOMAP_POOL_SIZE 1
+
+#define VK_STITCHER_ALIGNMENT_X 16
+#define VK_STITCHER_ALIGNMENT_Y 4
+
+#define MAP_FACTOR_X 16
+#define MAP_FACTOR_Y 16
+
+#define CHECK_RET(ret, format, ...) \
+    if (!xcam_ret_is_ok (ret)) { \
+        XCAM_LOG_ERROR (format, ## __VA_ARGS__); \
+    }
+
+namespace XCam {
+
+#if DUMP_BUFFER
+static void
+dump_buf (const SmartPtr<VideoBuffer> &buf, uint32_t idx, const char *prefix)
+{
+    XCAM_ASSERT (buf.ptr () && prefix);
+
+    char name[256];
+    snprintf (name, 256, "%s-%d", prefix, idx);
+    dump_buf_perfix_path (buf, name);
+}
+#endif
+
+namespace VKSitcherPriv {
+
+DECLARE_HANDLER_CALLBACK (CbGeoMap, VKStitcher, geomap_done);
+
+struct GeoMapParam
+    : ImageHandler::Parameters
+{
+    SmartPtr<VKStitcher::StitcherParam>    stitch_param;
+    uint32_t                               idx;
+
+    GeoMapParam (uint32_t i)
+        : idx (i)
+    {}
+};
+
+struct Factor {
+    float x, y;
+
+    Factor () : x (1.0f), y (1.0f) {}
+    void reset () {
+        x = 1.0f;
+        y = 1.0f;
+    }
+};
+
+struct GeoMapFactors {
+    Factor left;
+    Factor right;
+};
+
+typedef std::vector<SmartPtr<VKCopyHandler>> Copiers;
+
+struct StitcherResource {
+    SmartPtr<VKBlender::Sync>             blender_sync[XCAM_STITCH_MAX_CAMERAS];
+    SmartPtr<BufferPool>                  mapper_pool[XCAM_STITCH_MAX_CAMERAS];
+
+    SmartPtr<GeoMapParam>                 mapper_param[XCAM_STITCH_MAX_CAMERAS];
+    SmartPtr<VKBlender::BlenderParam>     blender_param[XCAM_STITCH_MAX_CAMERAS];
+    SmartPtr<ImageHandler::Parameters>    copier_param[XCAM_STITCH_MAX_CAMERAS];
+
+    SmartPtr<VKGeoMapHandler>             mapper[XCAM_STITCH_MAX_CAMERAS];
+    SmartPtr<VKBlender>                   blender[XCAM_STITCH_MAX_CAMERAS];
+    Copiers                               copiers;
+
+    SmartPtr<FeatureMatch>                matcher[XCAM_STITCH_MAX_CAMERAS];
+    GeoMapFactors                         mapper_factors[XCAM_STITCH_MAX_CAMERAS];
+
+    StitcherResource ();
+};
+
+class StitcherImpl {
+    friend class XCam::VKStitcher;
+
+public:
+    StitcherImpl (VKStitcher *handler)
+        : _stitcher (handler)
+    {}
+
+    XCamReturn init_resource ();
+
+    XCamReturn start_geo_mappers (const SmartPtr<VKStitcher::StitcherParam> &param);
+    XCamReturn start_blenders (const SmartPtr<VKStitcher::StitcherParam> &param, uint32_t idx);
+    XCamReturn start_copier (const SmartPtr<VKStitcher::StitcherParam> &param, uint32_t idx);
+    XCamReturn start_feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, uint32_t idx);
+
+    XCamReturn stop ();
+
+private:
+    SmartPtr<VKGeoMapHandler> create_geo_mapper (
+        const SmartPtr<VKDevice> &dev, const Stitcher::RoundViewSlice &view_slice);
+
+    XCamReturn init_geo_mappers (const SmartPtr<VKDevice> &dev);
+    XCamReturn init_blenders (const SmartPtr<VKDevice> &dev);
+    XCamReturn init_copiers (const SmartPtr<VKDevice> &dev);
+    void init_feature_matchers ();
+
+    void calc_geomap_factors (
+        uint32_t idx, const Factor &last_left_factor, const Factor &last_right_factor,
+        Factor &cur_left, Factor &cur_right);
+    bool update_geomap_factors (uint32_t idx);
+    XCamReturn create_geomap_pool (const SmartPtr<VKDevice> &dev, uint32_t idx);
+    XCamReturn set_geomap_table (
+        const SmartPtr<VKGeoMapHandler> &mapper, const CameraInfo &cam_info,
+        const Stitcher::RoundViewSlice &view_slice, const BowlDataConfig &bowl);
+    XCamReturn generate_geomap_table (const SmartPtr<VKGeoMapHandler> &mapper, uint32_t idx);
+
+    void update_blender_sync (uint32_t idx);
+    XCamReturn start_blender (const SmartPtr<VKStitcher::StitcherParam> &param, uint32_t idx);
+
+private:
+    StitcherResource              _res;
+    VKStitcher                   *_stitcher;
+};
+
+StitcherResource::StitcherResource ()
+{
+}
+
+SmartPtr<VKGeoMapHandler>
+StitcherImpl::create_geo_mapper (
+    const SmartPtr<VKDevice> &dev, const Stitcher::RoundViewSlice &view_slice)
+{
+    XCAM_UNUSED (view_slice);
+
+    SmartPtr<VKGeoMapHandler> mapper;
+    if (_stitcher->get_scale_mode () == ScaleSingleConst) {
+        mapper = new VKGeoMapHandler (dev, "sitcher_singleconst_remapper");
+    } else {
+        XCAM_LOG_ERROR (
+            "vk-stitcher(%s) unsupported scale mode:%d",
+            XCAM_STR (_stitcher->get_name ()), _stitcher->get_scale_mode ());
+    }
+    XCAM_ASSERT (mapper.ptr ());
+
+    return mapper;
+}
+
+void
+StitcherImpl::update_blender_sync (uint32_t idx)
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    uint32_t pre_idx = (idx + cam_num - 1) % cam_num;
+
+    _res.blender_sync[pre_idx]->increment ();
+    _res.blender_sync[idx]->increment ();
+}
+
+void
+StitcherImpl::calc_geomap_factors (
+    uint32_t idx, const Factor &last_left_factor, const Factor &last_right_factor,
+    Factor &cur_left, Factor &cur_right)
+{
+    const Factor &fm_left_factor = _res.mapper_factors[idx].left;
+    const Factor &fm_right_factor = _res.mapper_factors[idx].right;
+
+    cur_left.x = last_left_factor.x * fm_left_factor.x;
+    cur_left.y = last_left_factor.y * fm_left_factor.y;
+    cur_right.x = last_right_factor.x * fm_right_factor.x;
+    cur_right.y = last_right_factor.y * fm_right_factor.y;
+
+    _res.mapper_factors[idx].left.reset ();
+    _res.mapper_factors[idx].right.reset ();
+}
+
+bool
+StitcherImpl::update_geomap_factors (uint32_t idx)
+{
+    SmartPtr<VKGeoMapHandler> &mapper = _res.mapper[idx];
+    XCAM_FAIL_RETURN (
+        ERROR, mapper.ptr (), false,
+        "vk-stitcher(%s) geomap handler is empty, idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
+
+    if (_stitcher->get_scale_mode () == ScaleSingleConst) {
+        Factor unify_factor, cur_left, cur_right;
+
+        mapper->get_factors (unify_factor.x, unify_factor.y);
+        if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) ||
+                XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started.
+            return true;
+        }
+
+        calc_geomap_factors (idx, unify_factor, unify_factor, cur_left, cur_right);
+        unify_factor.x = (cur_left.x + cur_right.x) / 2.0f;
+        unify_factor.y = (cur_left.y + cur_right.y) / 2.0f;
+
+        mapper->set_factors (unify_factor.x, unify_factor.y);
+    } else {
+        XCAM_LOG_ERROR (
+            "vk-stitcher(%s) unsupported scale mode:%d",
+            XCAM_STR (_stitcher->get_name ()), _stitcher->get_scale_mode ());
+        return false;
+    }
+
+    return true;
+}
+
+XCamReturn
+StitcherImpl::create_geomap_pool (const SmartPtr<VKDevice> &dev, uint32_t idx)
+{
+    uint32_t output_width, output_height;
+    _res.mapper[idx]->get_output_size (output_width, output_height);
+
+    VideoBufferInfo out_info;
+    out_info.init (
+        V4L2_PIX_FMT_NV12, output_width, output_height,
+        XCAM_ALIGN_UP (output_width, VK_STITCHER_ALIGNMENT_X),
+        XCAM_ALIGN_UP (output_height, VK_STITCHER_ALIGNMENT_Y));
+
+    SmartPtr<BufferPool> pool = create_vk_buffer_pool (dev);
+    XCAM_ASSERT (pool.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, pool->set_video_info (out_info) && pool->reserve (GEOMAP_POOL_SIZE),
+        XCAM_RETURN_ERROR_MEM,
+        "vk-stitcher(%s) create buffer pool failed, buffer size:%dx%d, idx:%d",
+        XCAM_STR (_stitcher->get_name ()), out_info.width, out_info.height, idx);
+
+    _res.mapper_pool[idx] = pool;
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::set_geomap_table (
+    const SmartPtr<VKGeoMapHandler> &mapper, const CameraInfo &cam_info,
+    const Stitcher::RoundViewSlice &view_slice, const BowlDataConfig &bowl)
+{
+    PolyFisheyeDewarp fd;
+    fd.set_intrinsic_param (cam_info.calibration.intrinsic);
+    fd.set_extrinsic_param (cam_info.calibration.extrinsic);
+
+    uint32_t table_width, table_height;
+    table_width = view_slice.width / MAP_FACTOR_X;
+    table_height = view_slice.height / MAP_FACTOR_Y;
+
+    SurViewFisheyeDewarp::MapTable map_table (table_width * table_height);
+    fd.fisheye_dewarp (
+        map_table, table_width, table_height,
+        view_slice.width, view_slice.height, bowl);
+
+    bool ret = mapper->set_lookup_table (map_table.data (), table_width, table_height);
+    XCAM_FAIL_RETURN (
+        ERROR, ret, XCAM_RETURN_ERROR_UNKNOWN,
+        "vk-stitcher(%s)  set geomap lookup table failed", XCAM_STR (_stitcher->get_name ()));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::generate_geomap_table (
+    const SmartPtr<VKGeoMapHandler> &mapper, uint32_t idx)
+{
+    CameraInfo cam_info;
+    _stitcher->get_camera_info (idx, cam_info);
+    Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (idx);
+
+    BowlDataConfig bowl = _stitcher->get_bowl_config ();
+    bowl.angle_start = view_slice.hori_angle_start;
+    bowl.angle_end = format_angle (view_slice.hori_angle_start + view_slice.hori_angle_range);
+    if (bowl.angle_end < bowl.angle_start)
+        bowl.angle_start -= 360.0f;
+
+    XCAM_LOG_DEBUG (
+        "vk-stitcher(%s) camera(idx:%d) info(angle start:%.2f, range:%.2f), bowl info(angle start:%.2f, end:%.2f)",
+        XCAM_STR (_stitcher->get_name ()), idx,
+        view_slice.hori_angle_start, view_slice.hori_angle_range,
+        bowl.angle_start, bowl.angle_end);
+
+    XCamReturn ret = set_geomap_table (mapper, cam_info, view_slice, bowl);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) set geometry map table failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::init_geo_mappers (const SmartPtr<VKDevice> &dev)
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    SmartPtr<ImageHandler::Callback> cb = new CbGeoMap (_stitcher);
+
+    for (uint32_t idx = 0; idx < cam_num; ++idx) {
+        Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (idx);
+
+        SmartPtr<VKGeoMapHandler> &mapper = _res.mapper[idx];
+        mapper = create_geo_mapper (dev, view_slice);
+        mapper->set_callback (cb);
+        mapper->set_output_size (view_slice.width, view_slice.height);
+
+        create_geomap_pool (dev, idx);
+
+        SmartPtr<GeoMapParam> &mapper_param = _res.mapper_param[idx];
+        mapper_param = new GeoMapParam (idx);
+        XCAM_ASSERT (mapper_param.ptr ());
+
+        mapper_param->out_buf = _res.mapper_pool[idx]->get_buffer ();
+        XCAM_ASSERT (mapper_param->out_buf.ptr ());
+
+        XCamReturn ret = generate_geomap_table (mapper, idx);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "vk-stitcher(%s) generate geomap table failed", XCAM_STR (_stitcher->get_name ()));
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::init_blenders (const SmartPtr<VKDevice> &dev)
+{
+    uint32_t out_width, out_height;
+    _stitcher->get_output_size (out_width, out_height);
+    uint32_t cam_num = _stitcher->get_camera_num ();
+
+    for (uint32_t idx = 0; idx < cam_num; ++idx) {
+        SmartPtr<VKBlender> &blender = _res.blender[idx];
+        blender = create_vk_blender (dev).dynamic_cast_ptr<VKBlender> ();
+        XCAM_ASSERT (blender.ptr ());
+
+        const Stitcher::ImageOverlapInfo &overlap = _stitcher->get_overlap (idx);
+        blender->set_output_size (out_width, out_height);
+        blender->set_merge_window (overlap.out_area);
+        blender->set_input_valid_area (overlap.left, 0);
+        blender->set_input_valid_area (overlap.right, 1);
+        blender->set_input_merge_area (overlap.left, 0);
+        blender->set_input_merge_area (overlap.right, 1);
+
+        SmartPtr<VKBlender::BlenderParam> &blender_param = _res.blender_param[idx];
+        blender_param = new VKBlender::BlenderParam (NULL, NULL, NULL);
+        XCAM_ASSERT (blender_param.ptr ());
+
+        uint32_t next_idx = (idx + 1) % cam_num;
+        blender_param->in_buf = _res.mapper_param[idx]->out_buf;
+        blender_param->in1_buf = _res.mapper_param[next_idx]->out_buf;
+        XCAM_ASSERT (blender_param->in_buf.ptr () && blender_param->in1_buf.ptr ());
+
+        _res.blender_sync[idx] = new VKBlender::Sync (2);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::init_copiers (const SmartPtr<VKDevice> &dev)
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    for (uint32_t idx = 0; idx < cam_num; ++idx) {
+        SmartPtr<ImageHandler::Parameters> &copier_param = _res.copier_param[idx];
+        copier_param = new ImageHandler::Parameters ();
+        XCAM_ASSERT (copier_param.ptr ());
+
+        copier_param->in_buf = _res.mapper_param[idx]->out_buf;
+        XCAM_ASSERT (copier_param->in_buf.ptr ());
+    }
+
+    Stitcher::CopyAreaArray areas = _stitcher->get_copy_area ();
+    uint32_t size = areas.size ();
+    for (uint32_t idx = 0; idx < size; ++idx) {
+        XCAM_ASSERT (areas[idx].in_idx < size);
+
+        SmartPtr<VKCopyHandler> copier = new VKCopyHandler (dev);
+        XCAM_ASSERT (copier.ptr ());
+        copier->enable_allocator (false);
+        copier->set_copy_area (areas[idx].in_idx, areas[idx].in_area, areas[idx].out_area);
+
+        _res.copiers.push_back (copier);
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void
+StitcherImpl::init_feature_matchers ()
+{
+#if HAVE_OPENCV
+    FeatureMatchMode fm_mode = _stitcher->get_fm_mode ();
+    if (fm_mode == FMNone)
+        return ;
+
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    for (uint32_t idx = 0; idx < cam_num; ++idx) {
+        SmartPtr<FeatureMatch> &matcher = _res.matcher[idx];
+#ifndef ANDROID
+        if (fm_mode == FMDefault)
+            matcher = FeatureMatch::create_default_feature_match ();
+        else if (fm_mode == FMCluster)
+            matcher = FeatureMatch::create_cluster_feature_match ();
+        else if (fm_mode == FMCapi)
+            matcher = FeatureMatch::create_capi_feature_match ();
+        else {
+            XCAM_LOG_ERROR (
+                "vk-stitcher(%s) unsupported FeatureMatchMode: %d",
+                XCAM_STR (_stitcher->get_name ()), fm_mode);
+        }
+#else
+        matcher = FeatureMatch::create_capi_feature_match ();
+#endif
+        XCAM_ASSERT (matcher.ptr ());
+
+        FMConfig config;
+        config.sitch_min_width = 136;
+        config.min_corners = 4;
+        config.offset_factor = 0.8f;
+        config.delta_mean_offset = 120.0f;
+        config.recur_offset_error = 8.0f;
+        config.max_adjusted_offset = 24.0f;
+        config.max_valid_offset_y = 20.0f;
+        config.max_track_error = 28.0f;
+#ifdef ANDROID
+        config.max_track_error = 3600.0f;
+#endif
+        matcher->set_config (config);
+        matcher->set_fm_index (idx);
+
+        const BowlDataConfig bowl = _stitcher->get_bowl_config ();
+        const Stitcher::ImageOverlapInfo &info = _stitcher->get_overlap (idx);
+        Rect left_ovlap = info.left;
+        Rect right_ovlap = info.right;
+        left_ovlap.pos_y = 0;
+        left_ovlap.height = int32_t (bowl.wall_height / (bowl.wall_height + bowl.ground_length) * left_ovlap.height);
+        right_ovlap.pos_y = 0;
+        right_ovlap.height = left_ovlap.height;
+        matcher->set_crop_rect (left_ovlap, right_ovlap);
+    }
+#else
+    XCAM_LOG_ERROR ("vk-stitcher(%s) feature match is unsupported", XCAM_STR (_stitcher->get_name ()));
+    XCAM_ASSERT (false);
+#endif
+}
+
+XCamReturn
+StitcherImpl::init_resource ()
+{
+    const SmartPtr<VKDevice> &dev = _stitcher->get_vk_device ();
+    XCAM_ASSERT (dev.ptr ());
+
+    XCamReturn ret = init_geo_mappers (dev);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) init dewarps failed", XCAM_STR (_stitcher->get_name ()));
+
+#if HAVE_OPENCV
+    init_feature_matchers ();
+#endif
+
+    ret = init_blenders (dev);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) init blenders failed", XCAM_STR (_stitcher->get_name ()));
+
+    ret = init_copiers (dev);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) init copiers failed", XCAM_STR (_stitcher->get_name ()));
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_geo_mappers (const SmartPtr<VKStitcher::StitcherParam> &param)
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+
+    for (uint32_t idx = 0; idx < cam_num; ++idx) {
+        if (_stitcher->get_fm_mode ())
+            update_geomap_factors (idx);
+
+        SmartPtr<GeoMapParam> &mapper_param = _res.mapper_param[idx];
+        mapper_param->in_buf = param->in_bufs[idx];
+        mapper_param->stitch_param = param;
+
+        XCamReturn ret = _res.mapper[idx]->execute_buffer (mapper_param, false);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "vk-stitcher(%s) execute geo mapper failed, idx:%d",
+            XCAM_STR (_stitcher->get_name ()), idx);
+
+#if DUMP_BUFFER
+        dump_buf (mapper_param->out_buf, idx, "stitcher-geomap");
+#endif
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_feature_match (
+    const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf, uint32_t idx)
+{
+#if HAVE_OPENCV
+    _res.matcher[idx]->reset_offsets ();
+    _res.matcher[idx]->feature_match (left_buf, right_buf);
+
+    Rect left_ovlap, right_ovlap;
+    _res.matcher[idx]->get_crop_rect (left_ovlap, right_ovlap);
+    float left_offsetx = _res.matcher[idx]->get_current_left_offset_x ();
+
+    uint32_t left_idx = idx;
+    Factor left_factor, right_factor;
+    float center_x = (float) _stitcher->get_center (left_idx).slice_center_x;
+    float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f);
+    float range = feature_center_x - center_x;
+    XCAM_ASSERT (range > 1.0f);
+    right_factor.x = (range + left_offsetx / 2.0f) / range;
+    right_factor.y = 1.0f;
+    XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f);
+
+    uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num ();
+    center_x = (float) _stitcher->get_center (right_idx).slice_center_x;
+    feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f);
+    range = center_x - feature_center_x;
+    XCAM_ASSERT (range > 1.0f);
+    left_factor.x = (range + left_offsetx / 2.0f) / range;
+    left_factor.y = 1.0f;
+    XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f);
+
+    _res.mapper_factors[left_idx].right = right_factor;
+    _res.mapper_factors[right_idx].left = left_factor;
+
+    return XCAM_RETURN_NO_ERROR;
+#else
+    XCAM_LOG_ERROR ("vk-stitcher(%s) feature match is unsupported", XCAM_STR (_stitcher->get_name ()));
+    return XCAM_RETURN_ERROR_PARAM;
+#endif
+}
+
+XCamReturn
+StitcherImpl::start_blender (
+    const SmartPtr<VKStitcher::StitcherParam> &param, uint32_t idx)
+{
+    SmartPtr<VKBlender::Sync> &sync = _res.blender_sync[idx];
+    if (!sync->is_synced ())
+        return XCAM_RETURN_NO_ERROR;
+    sync->reset ();
+
+    SmartPtr<VKBlender::BlenderParam> &blend_param = _res.blender_param[idx];
+    blend_param->out_buf = param->out_buf;
+
+    XCamReturn ret = _res.blender[idx]->execute_buffer (blend_param, false);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) execute blender failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
+
+#if DUMP_BUFFER
+        dump_buf (param->out_buf, idx, "stitcher-blend");
+#endif
+
+#if HAVE_OPENCV
+    if (_stitcher->get_fm_mode ()) {
+        ret = start_feature_match (blend_param->in_buf, blend_param->in1_buf, idx);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "vk-stitcher(%s) start feature match failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
+    }
+#endif
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_blenders (const SmartPtr<VKStitcher::StitcherParam> &param, uint32_t idx)
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    uint32_t pre_idx = (idx + cam_num - 1) % cam_num;
+
+    XCamReturn ret = start_blender (param, pre_idx);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) start blender failed, idx:%d", XCAM_STR (_stitcher->get_name ()), pre_idx);
+
+    ret = start_blender (param, idx);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) start blender failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::start_copier (
+    const SmartPtr<VKStitcher::StitcherParam> &param, uint32_t idx)
+{
+    uint32_t size = _stitcher->get_copy_area ().size ();
+
+    for (uint32_t i = 0; i < size; ++i) {
+        if(_res.copiers[i]->get_index () != idx)
+            continue;
+
+        SmartPtr<ImageHandler::Parameters> &copy_param = _res.copier_param[idx];
+        copy_param->out_buf = param->out_buf;
+
+        XCamReturn ret = _res.copiers[i]->execute_buffer (copy_param, false);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "vk-stitcher(%s) execute copier failed, i:%d idx:%d",
+            XCAM_STR (_stitcher->get_name ()), i, idx);
+
+#if DUMP_BUFFER
+        dump_buf (copy_param->out_buf, i, "stitcher-copy");
+#endif
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+StitcherImpl::stop ()
+{
+    uint32_t cam_num = _stitcher->get_camera_num ();
+    for (uint32_t i = 0; i < cam_num; ++i) {
+        if (_res.mapper[i].ptr ()) {
+            _res.mapper[i]->terminate ();
+            _res.mapper[i].release ();
+        }
+        if (_res.mapper_pool[i].ptr ()) {
+            _res.mapper_pool[i]->stop ();
+        }
+
+        if (_res.blender[i].ptr ()) {
+            _res.blender[i]->terminate ();
+            _res.blender[i].release ();
+        }
+    }
+
+    for (Copiers::iterator i = _res.copiers.begin (); i != _res.copiers.end (); ++i) {
+        SmartPtr<VKCopyHandler> &copier = *i;
+        if (copier.ptr ()) {
+            copier->terminate ();
+            copier.release ();
+        }
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+};
+
+VKStitcher::VKStitcher (const SmartPtr<VKDevice> &dev, const char *name)
+    : VKHandler (dev, name)
+    , Stitcher (VK_STITCHER_ALIGNMENT_X, VK_STITCHER_ALIGNMENT_X)
+{
+    SmartPtr<VKSitcherPriv::StitcherImpl> impl = new VKSitcherPriv::StitcherImpl (this);
+    XCAM_ASSERT (impl.ptr ());
+    _impl = impl;
+}
+
+VKStitcher::~VKStitcher ()
+{
+    _impl.release ();
+}
+
+XCamReturn
+VKStitcher::terminate ()
+{
+    _impl->stop ();
+    return VKHandler::terminate ();
+}
+
+XCamReturn
+VKStitcher::stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, !in_bufs.empty (), XCAM_RETURN_ERROR_PARAM,
+        "vk-stitcher(%s) input buffers is empty", XCAM_STR (get_name ()));
+
+    SmartPtr<StitcherParam> param = new StitcherParam ();
+    XCAM_ASSERT (param.ptr ());
+
+    uint32_t buf_num = 0;
+    for (VideoBufferList::const_iterator iter = in_bufs.begin(); iter != in_bufs.end (); ++iter) {
+        XCAM_ASSERT ((*iter).ptr ());
+        param->in_bufs[buf_num++] = *iter;
+    }
+    param->in_buf_num = buf_num;
+    param->out_buf = out_buf;
+
+    XCamReturn ret = execute_buffer (param, false);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) execute buffer failed", XCAM_STR (get_name ()));
+
+    finish ();
+    if (!out_buf.ptr ()) {
+        out_buf = param->out_buf;
+    }
+
+    return ret;
+}
+
+XCamReturn
+VKStitcher::configure_resource (const SmartPtr<Parameters> &param)
+{
+    XCAM_UNUSED (param);
+    XCAM_ASSERT (_impl.ptr ());
+
+    XCamReturn ret = estimate_round_slices ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) estimate round view slices failed", XCAM_STR (get_name ()));
+
+    ret = estimate_coarse_crops ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) estimate coarse crops failed", XCAM_STR (get_name ()));
+
+    ret = mark_centers ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) mark centers failed", XCAM_STR (get_name ()));
+
+    ret = estimate_overlap ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) estimake coarse overlap failed", XCAM_STR (get_name ()));
+
+    ret = update_copy_areas ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) update copy areas failed", XCAM_STR (get_name ()));
+
+    ret = _impl->init_resource ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk-stitcher(%s) initialize private config failed", XCAM_STR (get_name ()));
+
+    VideoBufferInfo out_info;
+    uint32_t out_width, out_height;
+    get_output_size (out_width, out_height);
+    XCAM_FAIL_RETURN (
+        ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
+        "vk-stitcher(%s) output size was not set", XCAM_STR (get_name ()));
+
+    out_info.init (
+        V4L2_PIX_FMT_NV12, out_width, out_height,
+        XCAM_ALIGN_UP (out_width, VK_STITCHER_ALIGNMENT_X),
+        XCAM_ALIGN_UP (out_height, VK_STITCHER_ALIGNMENT_Y));
+    set_out_video_info (out_info);
+
+    return ret;
+}
+
+XCamReturn
+VKStitcher::start_work (const SmartPtr<Parameters> &base)
+{
+    XCAM_ASSERT (base.ptr ());
+
+    SmartPtr<StitcherParam> param = base.dynamic_cast_ptr<StitcherParam> ();
+    XCAM_ASSERT (param.ptr () && param->in_buf_num > 0);
+
+    XCamReturn ret = _impl->start_geo_mappers (param);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM,
+        "vk_stitcher(%s) start geometry map failed", XCAM_STR (get_name ()));
+
+    return ret;
+}
+
+void
+VKStitcher::geomap_done (
+    const SmartPtr<ImageHandler> &handler,
+    const SmartPtr<ImageHandler::Parameters> &base, const XCamReturn error)
+{
+    XCAM_UNUSED (handler);
+    XCAM_UNUSED (error);
+
+    SmartPtr<VKSitcherPriv::GeoMapParam> param = base.dynamic_cast_ptr<VKSitcherPriv::GeoMapParam> ();
+    XCAM_ASSERT (param.ptr ());
+    SmartPtr<VKStitcher::StitcherParam> &stitch_param = param->stitch_param;
+    XCAM_ASSERT (stitch_param.ptr ());
+
+    _impl->update_blender_sync (param->idx);
+
+    XCamReturn ret = _impl->start_blenders (stitch_param, param->idx);
+    CHECK_RET (ret, "vk-stitcher(%s) start blenders failed, idx:%d", XCAM_STR (get_name ()), param->idx);
+
+    ret = _impl->start_copier (stitch_param, param->idx);
+    CHECK_RET (ret, "vk-stitcher(%s) start copier failed, idx:%d", XCAM_STR (get_name ()), param->idx);
+}
+
+SmartPtr<Stitcher>
+Stitcher::create_vk_stitcher (const SmartPtr<VKDevice> dev)
+{
+    return new VKStitcher (dev);
+}
+
+}
diff --git a/modules/vulkan/vk_stitcher.h b/modules/vulkan/vk_stitcher.h
new file mode 100644
index 0000000..c59f013
--- /dev/null
+++ b/modules/vulkan/vk_stitcher.h
@@ -0,0 +1,80 @@
+/*
+ * vk_stitcher.h - Vulkan stitcher class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_VK_STITCHER_H
+#define XCAM_VK_STITCHER_H
+
+#include <interface/stitcher.h>
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_handler.h>
+
+namespace XCam {
+
+namespace VKSitcherPriv {
+class StitcherImpl;
+class CbGeoMap;
+};
+
+class VKStitcher
+    : public VKHandler
+    , public Stitcher
+{
+    friend class VKSitcherPriv::StitcherImpl;
+    friend class VKSitcherPriv::CbGeoMap;
+
+public:
+    struct StitcherParam
+        : ImageHandler::Parameters
+    {
+        uint32_t in_buf_num;
+        SmartPtr<VideoBuffer> in_bufs[XCAM_STITCH_MAX_CAMERAS];
+
+        StitcherParam ()
+            : Parameters (NULL, NULL)
+            , in_buf_num (0)
+        {}
+    };
+
+public:
+    explicit VKStitcher (const SmartPtr<VKDevice> &dev, const char *name = "VKStitcher");
+    ~VKStitcher ();
+
+    // derived from VKHandler
+    virtual XCamReturn terminate ();
+
+protected:
+    // interface derive from Stitcher
+    XCamReturn stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf);
+
+    // derived from VKHandler
+    XCamReturn configure_resource (const SmartPtr<Parameters> &param);
+    XCamReturn start_work (const SmartPtr<Parameters> &param);
+
+private:
+    void geomap_done (
+        const SmartPtr<ImageHandler> &handler,
+        const SmartPtr<ImageHandler::Parameters> &param, const XCamReturn error);
+
+private:
+    SmartPtr<VKSitcherPriv::StitcherImpl>    _impl;
+};
+
+}
+#endif // XCAM_VK_STITCHER_H
diff --git a/modules/vulkan/vk_sync.cpp b/modules/vulkan/vk_sync.cpp
new file mode 100644
index 0000000..f5ea6c6
--- /dev/null
+++ b/modules/vulkan/vk_sync.cpp
@@ -0,0 +1,55 @@
+/*
+ * vk_sync.cpp - Vulkan sync
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_sync.h"
+#include "vk_device.h"
+
+namespace XCam {
+
+VKFence::~VKFence ()
+{
+    if (_dev.ptr () && XCAM_IS_VALID_VK_ID (_fence_id))
+        _dev->destroy_fence (_fence_id);
+}
+
+VKFence::VKFence (const SmartPtr<VKDevice> dev, VkFence id)
+    : _fence_id (id)
+    , _dev (dev)
+{
+}
+
+XCamReturn
+VKFence::reset ()
+{
+    XCAM_ASSERT (_dev.ptr ());
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_fence_id));
+
+    return _dev->reset_fence (_fence_id);
+}
+
+XCamReturn
+VKFence::wait (uint64_t timeout)
+{
+    XCAM_ASSERT (_dev.ptr ());
+    XCAM_ASSERT (XCAM_IS_VALID_VK_ID (_fence_id));
+    return _dev->wait_for_fence (_fence_id, timeout);
+}
+
+}
diff --git a/modules/vulkan/vk_sync.h b/modules/vulkan/vk_sync.h
new file mode 100644
index 0000000..e2a7d34
--- /dev/null
+++ b/modules/vulkan/vk_sync.h
@@ -0,0 +1,56 @@
+/*
+ * vk_sync.h - Vulkan sync
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_SYNC_H
+#define XCAM_VK_SYNC_H
+
+#include <vulkan/vulkan_std.h>
+
+namespace XCam {
+
+class VKDevice;
+
+class VKFence
+{
+    friend class VKDevice;
+public:
+    virtual ~VKFence ();
+
+    XCamReturn reset ();
+    XCamReturn wait (uint64_t timeout = UINT64_MAX);
+
+    VkFence get_fence_id () const {
+        return _fence_id;
+    }
+
+protected:
+    explicit VKFence (const SmartPtr<VKDevice> dev, VkFence id);
+
+private:
+    XCAM_DEAD_COPY (VKFence);
+
+protected:
+    VkFence                  _fence_id;
+    SmartPtr<VKDevice>       _dev;
+};
+
+}
+
+#endif  //XCAM_VK_SYNC_H
diff --git a/modules/vulkan/vk_video_buf_allocator.cpp b/modules/vulkan/vk_video_buf_allocator.cpp
new file mode 100644
index 0000000..c60476a
--- /dev/null
+++ b/modules/vulkan/vk_video_buf_allocator.cpp
@@ -0,0 +1,164 @@
+/*
+ * vk_video_buf_allocator.cpp - vulkan video buffer allocator implementation
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_video_buf_allocator.h"
+#include "vk_memory.h"
+#include "vk_device.h"
+
+namespace XCam {
+
+class VKVideoData
+    : public BufferData
+{
+    friend class VKVideoBuffer;
+public:
+    explicit VKVideoData (const SmartPtr<VKBuffer> vk_buf);
+    virtual ~VKVideoData ();
+
+    //derive from BufferData
+    virtual uint8_t *map ();
+    virtual bool unmap ();
+
+    bool is_valid ();
+
+private:
+    uint8_t            *_mem_ptr;
+    SmartPtr<VKBuffer>  _vk_buf;
+};
+
+VKVideoData::VKVideoData (const SmartPtr<VKBuffer> vk_buf)
+    : _mem_ptr (NULL)
+    , _vk_buf (vk_buf)
+{
+    XCAM_ASSERT (vk_buf.ptr ());
+}
+
+VKVideoData::~VKVideoData ()
+{
+}
+
+bool
+VKVideoData::is_valid ()
+{
+    return _vk_buf.ptr () && XCAM_IS_VALID_VK_ID (_vk_buf->get_buf_id ());
+}
+
+uint8_t *
+VKVideoData::map ()
+{
+    if (!_mem_ptr) {
+        _mem_ptr = (uint8_t *)_vk_buf->map ();
+    }
+    return _mem_ptr;
+}
+
+bool
+VKVideoData::unmap ()
+{
+    if (!_mem_ptr)
+        return false;
+
+    _mem_ptr = NULL;
+    _vk_buf->unmap ();
+    return true;
+}
+
+VKVideoBufAllocator::VKVideoBufAllocator (const SmartPtr<VKDevice> dev)
+    : _dev (dev)
+{
+}
+
+VKVideoBufAllocator::~VKVideoBufAllocator ()
+{
+}
+
+SmartPtr<BufferData>
+VKVideoBufAllocator::allocate_data (const VideoBufferInfo &buffer_info)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, buffer_info.size, NULL,
+        "VKVideoBufAllocator allocate data failed. buf_size is zero");
+
+    SmartPtr<VKBuffer> vk_buf =
+        VKBuffer::create_buffer (_dev, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, buffer_info.size);
+
+    XCAM_FAIL_RETURN (
+        ERROR, vk_buf.ptr (), NULL,
+        "VKVideoBufAllocator create vk memory failed. buf_size :%d", buffer_info.size);
+
+    VKBufInfo info;
+    info.format = buffer_info.format;
+    info.width = buffer_info.width;
+    info.height = buffer_info.height;
+    info.aligned_width = buffer_info.aligned_width;
+    info.aligned_height = buffer_info.aligned_height;
+    info.size = buffer_info.size;
+    info.strides[0] = buffer_info.strides[0];
+    info.strides[1] = buffer_info.strides[1];
+    info.offsets[0] = buffer_info.offsets[0];
+    info.offsets[1] = buffer_info.offsets[1];
+    info.slice_size[0] = buffer_info.strides[0] * buffer_info.aligned_height;
+    info.slice_size[1] = buffer_info.size - buffer_info.offsets[1];
+    vk_buf->set_buf_info (info);
+
+    SmartPtr<VKVideoData> data = new VKVideoData (vk_buf);
+    XCAM_FAIL_RETURN (
+        ERROR, data.ptr () && data->is_valid (), NULL,
+        "VKVideoBufAllocator allocate data failed. buf_size:%d", buffer_info.size);
+
+    return data;
+}
+
+SmartPtr<BufferProxy>
+VKVideoBufAllocator::create_buffer_from_data (SmartPtr<BufferData> &data)
+{
+    const VideoBufferInfo &info = get_video_info ();
+
+    XCAM_ASSERT (data.ptr ());
+    return new VKVideoBuffer (info, data);
+}
+
+VKVideoBuffer::VKVideoBuffer (const VideoBufferInfo &info, const SmartPtr<BufferData> &data)
+    : BufferProxy (info, data)
+{
+}
+
+SmartPtr<VKBuffer>
+VKVideoBuffer::get_vk_buf ()
+{
+    SmartPtr<BufferData> data = get_buffer_data ();
+    SmartPtr<VKVideoData> vk_data = data.dynamic_cast_ptr<VKVideoData> ();
+    XCAM_FAIL_RETURN (
+        ERROR, vk_data.ptr () && vk_data->_vk_buf.ptr (), VK_NULL_HANDLE,
+        "VKVideoBuffer get buf_id failed, data is empty");
+
+    return vk_data->_vk_buf;
+}
+
+SmartPtr<BufferPool>
+create_vk_buffer_pool (const SmartPtr<VKDevice> &dev)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, dev.ptr () && XCAM_IS_VALID_VK_ID(dev->get_dev_id()), NULL,
+        "create_vk_buffer_pool failed since vk device is invalid");
+    return new VKVideoBufAllocator (dev);
+}
+
+}
diff --git a/modules/vulkan/vk_video_buf_allocator.h b/modules/vulkan/vk_video_buf_allocator.h
new file mode 100644
index 0000000..af56f94
--- /dev/null
+++ b/modules/vulkan/vk_video_buf_allocator.h
@@ -0,0 +1,58 @@
+/*
+ * vk_video_buf_allocator.h - vulkan video buffer allocator class
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_VIDEO_BUF_ALLOCATOR_H
+#define XCAM_VK_VIDEO_BUF_ALLOCATOR_H
+
+#include <buffer_pool.h>
+
+namespace XCam {
+
+class VKDevice;
+class VKBuffer;
+
+class VKVideoBufAllocator
+    : public BufferPool
+{
+public:
+    explicit VKVideoBufAllocator (const SmartPtr<VKDevice> dev);
+    virtual ~VKVideoBufAllocator ();
+
+private:
+    //derive from BufferPool
+    virtual SmartPtr<BufferData> allocate_data (const VideoBufferInfo &buffer_info);
+    virtual SmartPtr<BufferProxy> create_buffer_from_data (SmartPtr<BufferData> &data);
+
+private:
+    SmartPtr<VKDevice>     _dev;
+};
+
+class VKVideoBuffer
+    : public BufferProxy
+{
+public:
+    explicit VKVideoBuffer (const VideoBufferInfo &info, const SmartPtr<BufferData> &data);
+    SmartPtr<VKBuffer> get_vk_buf ();
+};
+
+}
+
+#endif //XCAM_VK_VIDEO_BUF_ALLOCATOR_H
+
diff --git a/modules/vulkan/vk_worker.cpp b/modules/vulkan/vk_worker.cpp
new file mode 100644
index 0000000..f40a81a
--- /dev/null
+++ b/modules/vulkan/vk_worker.cpp
@@ -0,0 +1,218 @@
+/*
+ * vk_worker.cpp - vulkan worker class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vk_worker.h"
+#include "vk_sync.h"
+#include "vk_pipeline.h"
+#include "vk_cmdbuf.h"
+#include "vk_device.h"
+#include "vulkan_common.h"
+
+namespace XCam {
+
+XCamReturn
+VKWorker::VKArguments::prepare_bindings (
+    VKDescriptor::SetBindInfoArray &binding_array,
+    VKConstRange::VKPushConstArgs &push_consts)
+{
+    XCAM_ASSERT (_binding_bufs.size ());
+    XCAM_FAIL_RETURN (
+        ERROR, _binding_bufs.size (), XCAM_RETURN_ERROR_PARAM,
+        "VKArguments found bindings empty, please check settings or derive interface prepare_bindings");
+
+    binding_array = _binding_bufs;
+    push_consts = _push_consts;
+    return XCAM_RETURN_NO_ERROR;
+}
+
+bool
+VKWorker::VKArguments::set_bindings (const VKDescriptor::SetBindInfoArray &arr)
+{
+    _binding_bufs = arr;
+    return true;
+}
+
+bool
+VKWorker::VKArguments::add_binding (const VKDescriptor::SetBindInfo &info)
+{
+    _binding_bufs.push_back (info);
+    return true;
+}
+
+bool
+VKWorker::VKArguments::add_push_const (const SmartPtr<VKConstRange::VKPushConstArg> &push_const)
+{
+    _push_consts.push_back (push_const);
+    return true;
+}
+
+VKWorker::VKWorker (SmartPtr<VKDevice> dev, const char *name, const SmartPtr<Callback> &cb)
+    : Worker (name, cb)
+    , _device (dev)
+{
+}
+
+VKWorker::~VKWorker ()
+{
+}
+
+XCamReturn
+VKWorker::build (
+    const VKShaderInfo &info,
+    const VKDescriptor::BindingArray &bindings,
+    const VKConstRange::VKPushConstArgs &consts)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+    XCAM_FAIL_RETURN (
+        ERROR, _device.ptr (), XCAM_RETURN_ERROR_VULKAN,
+        "vk woker(%s) build failed since vk_device is null.", XCAM_STR (get_name ()));
+
+    SmartPtr<VKShader> shader;
+    if (info.type == VKSahderInfoSpirVPath) {
+        const char *dir_env = std::getenv (XCAM_VK_SHADER_PATH);
+        std::string vk_dir (dir_env, (dir_env ? strlen (dir_env) : 0));
+        if (vk_dir.empty () || !vk_dir.length())
+            vk_dir = XCAM_DEFAULT_VK_SHADER_PATH;
+        std::string spirv_path = vk_dir + "/" + info.spirv_path;
+        shader = _device->create_shader (spirv_path.c_str ());
+    } else if (info.type == VKSahderInfoSpirVBinary) {
+        shader = _device->create_shader (info.spirv_bin);
+    }
+    XCAM_FAIL_RETURN (
+        ERROR, shader.ptr (), XCAM_RETURN_ERROR_VULKAN,
+        "vk woker(%s) build failed when creating shader.", XCAM_STR (get_name ()));
+    shader->set_func_name (info.func_name.c_str ());
+
+    _desc_pool = new VKDescriptor::Pool (_device);
+    XCAM_ASSERT (_desc_pool.ptr ());
+    XCAM_FAIL_RETURN (
+        ERROR, _desc_pool->add_set_bindings (bindings), XCAM_RETURN_ERROR_VULKAN,
+        "vk woker(%s) build failed to add bindings to desc_pool", XCAM_STR (get_name ()));
+    ret = _desc_pool->create ();
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk woker(%s) build failed to craete bindings in desc_pool", XCAM_STR (get_name ()));
+
+    VKConstRange::VKConstantArray const_array;
+    for (size_t i = 0; i < consts.size(); ++i) {
+        VkPushConstantRange data_const = {0, 0, 0};
+        void *ptr = NULL;
+        consts[i]->get_const_data (data_const, ptr);
+        const_array.push_back (data_const);
+    }
+    _pipeline = VKPipeline::create_compute_pipeline (_device, shader, bindings, const_array);
+    XCAM_FAIL_RETURN (
+        ERROR, _pipeline.ptr (), XCAM_RETURN_ERROR_VULKAN,
+        "vk woker(%s) build failed when creating pipelines.", XCAM_STR (get_name ()));
+
+    _pipeline->set_desc_pool (_desc_pool);
+
+    _cmdbuf = VKCmdBuf::create_command_buffer (_device);
+    XCAM_FAIL_RETURN (
+        ERROR, _cmdbuf.ptr (), XCAM_RETURN_ERROR_VULKAN,
+        "vk woker(%s) build failed when creating command buffers.", XCAM_STR (get_name ()));
+
+    _fence = _device->create_fence (VK_FENCE_CREATE_SIGNALED_BIT);
+    XCAM_FAIL_RETURN (
+        ERROR, _fence.ptr (), XCAM_RETURN_ERROR_VULKAN,
+        "vk woker(%s) build failed when creating fence.", XCAM_STR (get_name ()));
+    return XCAM_RETURN_NO_ERROR;
+}
+
+// derived from Worker
+XCamReturn
+VKWorker::work (const SmartPtr<Worker::Arguments> &args)
+{
+    SmartPtr<VKArguments> vk_args = args.dynamic_cast_ptr<VKArguments>();
+    XCAM_FAIL_RETURN (
+        ERROR, vk_args.ptr(), XCAM_RETURN_ERROR_PARAM,
+        "vk woker(%s) work argements error.", XCAM_STR (get_name ()));
+
+    VKDescriptor::SetBindInfoArray binding_array;
+    VKConstRange::VKPushConstArgs push_consts;
+    XCamReturn ret = vk_args->prepare_bindings (binding_array, push_consts);
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk woker(%s) prepare argements failed.", XCAM_STR (get_name ()));
+
+    XCAM_FAIL_RETURN (
+        ERROR, !binding_array.empty (), XCAM_RETURN_ERROR_PARAM,
+        "vk woker(%s) binding_array is empty.", XCAM_STR (get_name ()));
+
+    ret = _pipeline->update_bindings (binding_array);
+
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk woker(%s) update binding argements failed.", XCAM_STR (get_name ()));
+
+    const WorkSize global = get_global_size ();
+    SmartPtr<VKCmdBuf::DispatchParam> dispatch  =
+        new VKCmdBuf::DispatchParam (_pipeline, global.value[0], global.value[1], global.value[2]);
+    if (!push_consts.empty()) {
+        XCAM_FAIL_RETURN (
+            ERROR, dispatch->update_push_consts (push_consts), XCAM_RETURN_ERROR_PARAM,
+            "vk woker(%s) update push-consts failed.", XCAM_STR (get_name ()));
+    }
+
+    ret = _cmdbuf->record (dispatch);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk woker(%s) record cmdbuf failed.", XCAM_STR (get_name ()));
+
+    ret = _device->compute_queue_submit (_cmdbuf, _fence);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "vk woker(%s) submit compute queue failed.", XCAM_STR (get_name ()));
+
+    status_check (args, ret);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKWorker::stop ()
+{
+    if (_pipeline.ptr () && _device.ptr ()) {
+        if (_fence.ptr ()) {
+            _fence->wait ();
+            _fence->reset ();
+        }
+        _device->compute_queue_wait_idle ();
+    }
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+VKWorker::wait_fence ()
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+    if (_fence.ptr ()) {
+        ret = _fence->wait ();
+        if (!xcam_ret_is_ok (ret)) {
+            XCAM_LOG_ERROR ("vk woker(%s) wait fence failed.", XCAM_STR (get_name ()));
+        }
+        _fence->reset ();
+    }
+
+    return ret;
+}
+
+}
diff --git a/modules/vulkan/vk_worker.h b/modules/vulkan/vk_worker.h
new file mode 100644
index 0000000..c23bd4d
--- /dev/null
+++ b/modules/vulkan/vk_worker.h
@@ -0,0 +1,112 @@
+/*
+ * vk_worker.h - vulkan worker class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_WORKER_H
+#define XCAM_VK_WORKER_H
+
+#include <vulkan/vulkan_std.h>
+#include <vulkan/vk_descriptor.h>
+#include <worker.h>
+#include <string>
+
+namespace XCam {
+
+class VKPipeline;
+class VKDevice;
+class VKFence;
+class VKCmdBuf;
+
+enum VKSahderInfoType {
+    VKSahderInfoSpirVBinary = 0,
+    VKSahderInfoSpirVPath   = 1,
+};
+
+struct VKShaderInfo {
+    VKSahderInfoType           type;
+    std::string                func_name;
+    std::string                spirv_path;
+    std::vector<uint32_t>      spirv_bin;
+
+    VKShaderInfo () {}
+    VKShaderInfo (const char *func, const char *path)
+        : type (VKSahderInfoSpirVPath)
+        , func_name (func)
+        , spirv_path (path)
+    {}
+    VKShaderInfo (const char *func, const std::vector<uint32_t> &binary)
+        : type (VKSahderInfoSpirVBinary)
+        , func_name (func)
+        , spirv_bin (binary)
+    {}
+};
+
+class VKWorker
+    : public Worker
+{
+public:
+    class VKArguments:
+        public Worker::Arguments
+    {
+        friend class VKWorker;
+    public:
+        VKArguments () {}
+        VKArguments (VKDescriptor::SetBindInfoArray &arr)
+            : _binding_bufs (arr)
+        {}
+        bool set_bindings (const VKDescriptor::SetBindInfoArray &arr);
+        bool add_binding (const VKDescriptor::SetBindInfo &info);
+        bool add_push_const (const SmartPtr<VKConstRange::VKPushConstArg> &push_const);
+
+    protected:
+        virtual XCamReturn prepare_bindings (
+            VKDescriptor::SetBindInfoArray &binding_array,
+            VKConstRange::VKPushConstArgs &push_consts);
+    private:
+        VKDescriptor::SetBindInfoArray       _binding_bufs;
+        VKConstRange::VKPushConstArgs        _push_consts;
+    };
+
+public:
+    explicit VKWorker (SmartPtr<VKDevice> dev, const char *name, const SmartPtr<Callback> &cb = NULL);
+    virtual ~VKWorker ();
+
+    XCamReturn build (
+        const VKShaderInfo &info,
+        const VKDescriptor::BindingArray &bindings,
+        const VKConstRange::VKPushConstArgs &consts);
+
+    // derived from Worker
+    virtual XCamReturn work (const SmartPtr<Arguments> &args);
+    virtual XCamReturn stop ();
+    XCamReturn wait_fence ();
+
+private:
+    XCAM_DEAD_COPY (VKWorker);
+
+private:
+    SmartPtr<VKDevice>             _device;
+    SmartPtr<VKDescriptor::Pool>   _desc_pool;
+    SmartPtr<VKPipeline>           _pipeline;
+    SmartPtr<VKFence>              _fence;
+    SmartPtr<VKCmdBuf>             _cmdbuf;
+};
+
+}
+#endif //XCAM_VK_WORKER_H
diff --git a/modules/vulkan/vulkan_common.cpp b/modules/vulkan/vulkan_common.cpp
new file mode 100644
index 0000000..6e7ec66
--- /dev/null
+++ b/modules/vulkan/vulkan_common.cpp
@@ -0,0 +1,77 @@
+/*
+ * vulkan_common.cpp - vulkan common
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "vulkan_common.h"
+#include <map>
+
+#define VK_STR_INSERT(ERR)    \
+    vk_errors.insert (VkErrorMap::value_type(VK_ ##ERR, #ERR))
+
+namespace XCam {
+
+typedef std::map <uint32_t, const char*> VkErrorMap;
+
+static VkErrorMap vk_errors;
+
+void vk_init_error_string ()
+{
+    if (!vk_errors.empty ())
+        return;
+
+    VK_STR_INSERT (SUCCESS);
+    VK_STR_INSERT (NOT_READY);
+    VK_STR_INSERT (TIMEOUT);
+    VK_STR_INSERT (EVENT_SET);
+    VK_STR_INSERT (EVENT_RESET);
+    VK_STR_INSERT (INCOMPLETE);
+    VK_STR_INSERT (ERROR_OUT_OF_HOST_MEMORY);
+    VK_STR_INSERT (ERROR_OUT_OF_DEVICE_MEMORY);
+    VK_STR_INSERT (ERROR_INITIALIZATION_FAILED);
+    VK_STR_INSERT (ERROR_DEVICE_LOST);
+    VK_STR_INSERT (ERROR_MEMORY_MAP_FAILED);
+    VK_STR_INSERT (ERROR_LAYER_NOT_PRESENT);
+    VK_STR_INSERT (ERROR_FEATURE_NOT_PRESENT);
+    VK_STR_INSERT (ERROR_INCOMPATIBLE_DRIVER);
+    VK_STR_INSERT (ERROR_TOO_MANY_OBJECTS);
+    VK_STR_INSERT (ERROR_FORMAT_NOT_SUPPORTED);
+    VK_STR_INSERT (ERROR_FRAGMENTED_POOL);
+}
+
+const char*
+vk_error_str(VkResult id)
+{
+    VkErrorMap::iterator i = vk_errors.find (id);
+    if (i == vk_errors.end ())
+        return "VkUnKnown";
+    return i->second;
+}
+
+const std::string
+xcam_default_shader_path ()
+{
+    std::string home = "~";
+    const char *env = std::getenv ("HOME");
+    if (env)
+        home.assign (env, strlen (env));
+
+    return home + "/.xcam/vk";
+}
+
+}
diff --git a/modules/vulkan/vulkan_common.h b/modules/vulkan/vulkan_common.h
new file mode 100644
index 0000000..8093029
--- /dev/null
+++ b/modules/vulkan/vulkan_common.h
@@ -0,0 +1,33 @@
+/*
+ * vulkan_common.h - vulkan common
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_COMMON_H
+#define XCAM_VK_COMMON_H
+
+#include <vulkan/vulkan_std.h>
+#include <string>
+
+namespace XCam {
+
+const char* vk_error_str(VkResult id);
+const std::string xcam_default_shader_path ();
+}
+
+#endif
diff --git a/modules/vulkan/vulkan_std.h b/modules/vulkan/vulkan_std.h
new file mode 100644
index 0000000..952645e
--- /dev/null
+++ b/modules/vulkan/vulkan_std.h
@@ -0,0 +1,43 @@
+/*
+ * vulkan_std.h - vulkan common
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#ifndef XCAM_VK_STD_H
+#define XCAM_VK_STD_H
+
+#include <xcam_std.h>
+#include <vulkan/vulkan.h>
+
+#define XCAM_VK_CHECK_RETURN(LEVEL, vk_exp, failed_value, format, ...) \
+    do {                                                               \
+        VkResult err = vk_exp;                                         \
+        XCAM_FAIL_RETURN (LEVEL, err == VK_SUCCESS, failed_value,      \
+                          format ", vk_error(%d:%s)", ## __VA_ARGS__,  \
+                          (int)err, vk_error_str(err));                \
+    } while (0)
+
+
+#define XCAM_VK_NAME_LENGTH 256
+
+#define XCAM_IS_VALID_VK_ID(id) (VK_NULL_HANDLE != (id))
+
+#define XCAM_VK_SHADER_PATH "XCAM_VK_SHADER_PATH"
+#define XCAM_DEFAULT_VK_SHADER_PATH xcam_default_shader_path()
+
+#endif
diff --git a/plugins/3a/Makefile.am b/plugins/3a/Makefile.am
index 63c148a..4dbfcba 100644
--- a/plugins/3a/Makefile.am
+++ b/plugins/3a/Makefile.am
@@ -1,15 +1,5 @@
-if ENABLE_IA_AIQ
-AIQ_DIR = aiq
-else
-AIQ_DIR =
-endif
-
-if ENABLE_IA_AIQ
 if HAVE_LIBCL
 HYBRID_DIR = hybrid
-else
-HYBRID_DIR =
-endif
 endif
 
-SUBDIRS = $(AIQ_DIR) $(HYBRID_DIR)
+SUBDIRS = aiq $(HYBRID_DIR)
diff --git a/plugins/3a/aiq/Makefile.am b/plugins/3a/aiq/Makefile.am
index c1ca926..b22febb 100644
--- a/plugins/3a/aiq/Makefile.am
+++ b/plugins/3a/aiq/Makefile.am
@@ -1,43 +1,44 @@
 plugin_LTLIBRARIES = libxcam_3a_aiq.la
 
-XCAMAIQ_CXXFLAGS = $(XCAM_CXXFLAGS)
-XCAMAIQ_LIBS = \
+XCAM_AIQ_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)               \
+    -I$(top_srcdir)/xcore          \
+    -I$(top_srcdir)/modules/isp    \
+    -I$(top_srcdir)/plugins/3a/aiq \
+    $(NULL)
+
+XCAM_AIQ_LIBS = \
+    $(top_builddir)/xcore/libxcam_core.la      \
+    $(top_builddir)/modules/isp/libxcam_isp.la \
     $(NULL)
 
 if HAVE_LIBDRM
-XCAMAIQ_CXXFLAGS += $(LIBDRM_CFLAGS)
-XCAMAIQ_LIBS += $(LIBDRM_LIBS)
+XCAM_AIQ_CXXFLAGS += $(LIBDRM_CFLAGS)
+XCAM_AIQ_LIBS += $(LIBDRM_LIBS)
 endif
 
 if USE_LOCAL_ATOMISP
-XCAMAIQ_CXXFLAGS += \
-    -I$(top_srcdir)/ext/atomisp  \
+XCAM_AIQ_CXXFLAGS += \
+    -I$(top_srcdir)/ext/atomisp \
     $(NULL)
 endif
 
 plugindir="$(libdir)/xcam/plugins/3a"
 
 libxcam_3a_aiq_la_SOURCES = \
-    aiq_wrapper.cpp  \
+    aiq_wrapper.cpp \
     $(NULL)
 
 libxcam_3a_aiq_la_CXXFLAGS = \
-    $(GST_CFLAGS) $(XCAMAIQ_CXXFLAGS)  \
-    -I$(top_srcdir)/xcore              \
-    -I$(top_srcdir)/modules/isp        \
-    -I$(top_srcdir)/plugins/3a/aiq     \
+    $(XCAM_AIQ_CXXFLAGS) \
     $(NULL)
 
 libxcam_3a_aiq_la_LIBADD = \
-    $(XCAMAIQ_LIBS)                             \
-    $(top_builddir)/modules/isp/libxcam_isp.la  \
-    $(top_builddir)/xcore/libxcam_core.la       \
+    $(XCAM_AIQ_LIBS) \
     $(NULL)
 
 libxcam_3a_aiq_la_LDFLAGS = \
-    -module -avoid-version                 \
-    $(top_builddir)/xcore/libxcam_core.la  \
-    $(PTHREAD_LDFLAGS)                     \
+    -module -avoid-version \
     $(NULL)
 
 libxcam_3a_aiq_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/plugins/3a/aiq/aiq_wrapper.cpp b/plugins/3a/aiq/aiq_wrapper.cpp
index e6feb20..c09d9df 100644
--- a/plugins/3a/aiq/aiq_wrapper.cpp
+++ b/plugins/3a/aiq/aiq_wrapper.cpp
@@ -24,7 +24,7 @@
 #include "x3a_statistics_queue.h"
 #include "aiq3a_utils.h"
 #include "x3a_result_factory.h"
-#include "x3a_analyze_tuner.h"
+#include "iq/x3a_analyze_tuner.h"
 
 #define DEFAULT_AIQ_CPF_FILE       "/etc/atomisp/imx185.cpf"
 
@@ -112,22 +112,22 @@
     VideoBufferInfo info;
     info.init (XCAM_PIX_FMT_SGRBG16, _video_width, _video_height);
 
-    _stats_pool = new X3aStatisticsQueue;
-    XCAM_ASSERT (_stats_pool.ptr ());
+    SmartPtr<X3aStatisticsQueue> pool = new X3aStatisticsQueue;
+    XCAM_ASSERT (pool.ptr ());
 
-    _stats_pool->set_bit_depth (bit_depth);
+    pool->set_bit_depth (bit_depth);
     XCAM_FAIL_RETURN (
         WARNING,
-        _stats_pool->set_video_info (info),
+        pool->set_video_info (info),
         false,
         "3a stats set video info failed");
 
-
-    if (!_stats_pool->reserve (6)) {
+    if (!pool->reserve (6)) {
         XCAM_LOG_WARNING ("init_3a_stats_pool failed to reserve stats buffer.");
         return false;
     }
 
+    _stats_pool = pool;
     return true;
 }
 
diff --git a/plugins/3a/hybrid/Makefile.am b/plugins/3a/hybrid/Makefile.am
index df23f61..e09aa57 100644
--- a/plugins/3a/hybrid/Makefile.am
+++ b/plugins/3a/hybrid/Makefile.am
@@ -1,30 +1,31 @@
 plugin_LTLIBRARIES = libxcam_3a_hybrid.la
 
-XCAMSRC_CXXFLAGS = $(XCAM_CXXFLAGS)
-XCAMSRC_LIBS = \
+XCAM_HYBRID_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)                  \
+    -I$(top_srcdir)/xcore             \
+    -I$(top_srcdir)/plugins/3a/hybrid \
+    $(NULL)
+
+XCAM_HYBRID_LIBS = \
+    $(top_builddir)/xcore/libxcam_core.la \
     $(NULL)
 
 plugindir="$(libdir)/xcam/plugins/3a"
 
 libxcam_3a_hybrid_la_SOURCES = \
-    sample.cpp        \
+    sample.cpp \
     $(NULL)
 
 libxcam_3a_hybrid_la_CXXFLAGS = \
-    $(GST_CFLAGS) $(XCAMSRC_CXXFLAGS)  \
-    -I$(top_srcdir)/xcore              \
-    -I$(top_srcdir)/plugins/3a/hybrid  \
+    $(XCAM_HYBRID_CXXFLAGS) \
     $(NULL)
 
 libxcam_3a_hybrid_la_LIBADD = \
-    $(XCAMSRC_LIBS)                        \
-    $(top_builddir)/xcore/libxcam_core.la  \
+    $(XCAM_HYBRID_LIBS) \
     $(NULL)
 
 libxcam_3a_hybrid_la_LDFLAGS = \
-    -module -avoid-version                 \
-    $(top_builddir)/xcore/libxcam_core.la  \
-    $(PTHREAD_LDFLAGS)                     \
+    -module -avoid-version \
     $(NULL)
 
 libxcam_3a_hybrid_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index e3e20f4..f46513e 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,13 +1,9 @@
 if ENABLE_3ALIB
 X3ALIB_DIR = 3a
-else
-X3ALIB_DIR =
 endif
 
 if ENABLE_SMART_LIB
 SMARTLIB_DIR = smart
-else
-SMARTLIB_DIR =
 endif
 
 SUBDIRS = $(X3ALIB_DIR) $(SMARTLIB_DIR)
diff --git a/plugins/smart/Makefile.am b/plugins/smart/Makefile.am
index 49cf033..ef1348d 100644
--- a/plugins/smart/Makefile.am
+++ b/plugins/smart/Makefile.am
@@ -1,13 +1,11 @@
-
 if ENABLE_DVS
 if HAVE_LIBCL
 DVS_DIR = dvs
-else
-DVS_DIR =
 endif
-else
-DVS_DIR =
 endif
 
-SUBDIRS = $(DVS_DIR) sample
+if ENABLE_IA_AIQ
+SAMPLE_DIR = sample
+endif
 
+SUBDIRS = $(DVS_DIR) $(SAMPLE_DIR)
\ No newline at end of file
diff --git a/plugins/smart/dvs/Makefile.am b/plugins/smart/dvs/Makefile.am
index 2675621..7b72a89 100644
--- a/plugins/smart/dvs/Makefile.am
+++ b/plugins/smart/dvs/Makefile.am
@@ -2,46 +2,41 @@
 
 noinst_LTLIBRARIES = libxcam_plugin_dvs.la
 
-XCAM_PLUGIN_DVS_CXXFLAGS = $(XCAM_CXXFLAGS)   \
-	-I$(top_srcdir)/xcore                     \
-	-I$(top_srcdir)/modules                   \
-	-I$(top_srcdir)/plugins/smart/dvs/libdvs  \
-	$(NULL)
+XCAM_PLUGIN_DVS_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)                         \
+    -I$(top_srcdir)/xcore                    \
+    -I$(top_srcdir)/modules                  \
+    -I$(top_srcdir)/plugins/smart/dvs/libdvs \
+    $(NULL)
+
+XCAM_PLUGIN_DVS_LIBS = \
+    $(OPENCV_LIBS)                                         \
+    $(top_builddir)/xcore/libxcam_core.la                  \
+    $(top_builddir)/modules/ocl/libxcam_ocl.la             \
+    $(top_builddir)/plugins/smart/dvs/libdvs/libxcam_dvs.a \
+    $(NULL)
 
 if HAVE_LIBDRM
 XCAM_PLUGIN_DVS_CXXFLAGS += $(LIBDRM_CFLAGS)
-endif
-
-XCAM_PLUGIN_DVS_LIBS =            \
-	$(top_builddir)/plugins/smart/dvs/libdvs/libxcam_dvs.a \
-	$(NULL)
-
-if HAVE_LIBDRM
 XCAM_PLUGIN_DVS_LIBS += $(LIBDRM_LIBS)
 endif
 
 plugindir="$(libdir)/xcam/plugins/smart"
 
-libxcam_plugin_dvs_la_SOURCES =   \
-	xcam_plugin_dvs.cpp           \
-	$(NULL)
-
-libxcam_plugin_dvs_la_CXXFLAGS =               \
-	$(GST_CFLAGS) $(XCAM_PLUGIN_DVS_CXXFLAGS)  \
-	$(NULL)
-
-libxcam_plugin_dvs_la_LIBADD =                  \
-    $(XCAM_PLUGIN_DVS_LIBS)                     \
-    $(top_builddir)/modules/ocl/libxcam_ocl.la  \
-    $(top_builddir)/xcore/libxcam_core.la       \
-    $(OPENCV_LIBS) \
+libxcam_plugin_dvs_la_SOURCES = \
+    xcam_plugin_dvs.cpp \
     $(NULL)
 
-libxcam_plugin_dvs_la_LDFLAGS =            \
-    -module -avoid-version                 \
-    $(top_builddir)/xcore/libxcam_core.la  \
-    $(PTHREAD_LDFLAGS)                     \
-    $(OPENCV_LIBS) \
+libxcam_plugin_dvs_la_CXXFLAGS = \
+    $(XCAM_PLUGIN_DVS_CXXFLAGS) \
+    $(NULL)
+
+libxcam_plugin_dvs_la_LIBADD = \
+    $(XCAM_PLUGIN_DVS_LIBS) \
+    $(NULL)
+
+libxcam_plugin_dvs_la_LDFLAGS = \
+    -module -avoid-version \
     $(NULL)
 
 libxcam_plugin_dvs_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/plugins/smart/dvs/libdvs/Makefile.am b/plugins/smart/dvs/libdvs/Makefile.am
index 6fba743..8ffcb8c 100644
--- a/plugins/smart/dvs/libdvs/Makefile.am
+++ b/plugins/smart/dvs/libdvs/Makefile.am
@@ -1,45 +1,32 @@
-noinst_LIBRARIES =  \
-	libxcam_dvs.a    \
-	$(NULL)
-
-XCAM_DVS_LIB_CXXFLAGS = \
-	$(XCAM_CXXFLAGS) \
-	$(OPENCV_CFLAGS) \
-	$(NULL)
-                             
-XCAM_DVS_LIBS =      \
-	$(OPENCV_LIBS)   \
-	$(NULL)
+noinst_LIBRARIES = libxcam_dvs.a
 
 libxcam_dvs_a_SOURCES = \
-	libdvs.cpp           \
-	stabilizer.cpp       \
-	$(NULL)
-
-libxcam_dvs_a_CXXFLAGS =                    \
-	$(GST_CFLAGS) $(XCAM_DVS_LIB_CXXFLAGS)  \
-	-I$(top_srcdir)/xcore                   \
-	$(NULL)
-
-libxcam_dvs_a_LIBADD =                    \
-    $(top_builddir)/xcore/libxcam_core.la  \
+    libdvs.cpp     \
+    stabilizer.cpp \
     $(NULL)
 
-noinst_PROGRAMS = \
-    test_image_stabilization \
+libxcam_dvs_a_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)      \
+    $(OPENCV_CFLAGS)      \
+    -I$(top_srcdir)/xcore \
     $(NULL)
 
+libxcam_dvs_a_LIBADD = \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
+
+noinst_PROGRAMS = test_image_stabilization
+
 test_image_stabilization_SOURCES = \
     test-image-stabilization.cpp \
     $(NULL)
 
 test_image_stabilization_CXXFLAGS = \
-    $(XCAM_CXXFLAGS) \
+    $(XCAM_CXXFLAGS)      \
     -I$(top_srcdir)/xcore \
     $(NULL)
 
 test_image_stabilization_LDADD = \
-    libxcam_dvs.a \
+    libxcam_dvs.a  \
     $(OPENCV_LIBS) \
     $(NULL)
-
diff --git a/plugins/smart/dvs/libdvs/stabilizer.cpp b/plugins/smart/dvs/libdvs/stabilizer.cpp
index 1dd4f66..ba660f9 100644
--- a/plugins/smart/dvs/libdvs/stabilizer.cpp
+++ b/plugins/smart/dvs/libdvs/stabilizer.cpp
@@ -377,13 +377,23 @@
 Mat
 VideoStabilizer::nextFrame()
 {
+    Mat frame;
+
     if (isTwoPass_) {
         Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
-        return stab->nextFrame();
+        if(!stab.empty())
+            frame = stab->nextFrame();
+        else
+            CV_Error (Error::StsNullPtr, "VideoStabilizer: cast stabilizer failed");
     } else {
         Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
-        return stab->nextFrame();
+        if(!stab.empty())
+            frame = stab->nextFrame();
+        else
+            CV_Error (Error::StsNullPtr, "VideoStabilizer: cast stabilizer failed");
     }
+
+    return frame;
 }
 
 Mat
@@ -393,10 +403,16 @@
 
     if (isTwoPass_) {
         Ptr<TwoPassVideoStabilizer> stab = stabilizer_.dynamicCast<TwoPassVideoStabilizer>();
-        HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
+        if(!stab.empty())
+            HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
+        else
+            CV_Error (Error::StsNullPtr, "VideoStabilizer: cast stabilizer failed");
     } else {
         Ptr<OnePassVideoStabilizer> stab = stabilizer_.dynamicCast<OnePassVideoStabilizer>();
-        HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
+        if(!stab.empty())
+            HMatrix = stab->nextStabilizedMotion(frame, stablizedPos);
+        else
+            CV_Error (Error::StsNullPtr, "VideoStabilizer: cast stabilizer failed");
     }
 
     return HMatrix;
diff --git a/plugins/smart/dvs/libdvs/test-image-stabilization.cpp b/plugins/smart/dvs/libdvs/test-image-stabilization.cpp
index 944ef12..c2549e5 100644
--- a/plugins/smart/dvs/libdvs/test-image-stabilization.cpp
+++ b/plugins/smart/dvs/libdvs/test-image-stabilization.cpp
@@ -86,7 +86,7 @@
             break;
         case 'e':
             usage (argv[0]);
-            return -1;
+            return 0;
         default:
             printf ("getopt_long return unknown value:%c \n", opt);
             usage (argv[0]);
diff --git a/plugins/smart/dvs/xcam_plugin_dvs.cpp b/plugins/smart/dvs/xcam_plugin_dvs.cpp
index d8e2365..c6f154a 100644
--- a/plugins/smart/dvs/xcam_plugin_dvs.cpp
+++ b/plugins/smart/dvs/xcam_plugin_dvs.cpp
@@ -136,7 +136,6 @@
     DvsBuffer* dvs_buf = new DvsBuffer(buffer, frame);
     //set default config
     DvsConfig config;
-    memset(&config, 0, sizeof(DvsConfig));
     config.use_ocl  = true;
     config.frame_width = buffer->info.width;
     config.frame_height = buffer->info.height;
@@ -158,6 +157,14 @@
         XCAM_LOG_WARNING ("dvs_analyze not ready! ");
     } else {
         XCamDVSResult *dvs_result = (XCamDVSResult *)malloc(sizeof(XCamDVSResult));
+        if (!dvs_result) {
+            XCAM_LOG_ERROR ("dvs_result: malloc failed!");
+            results[0] = NULL;
+            *res_count = 0;
+
+            return XCAM_RETURN_ERROR_MEM;
+        }
+
         memset(dvs_result, 0, sizeof(XCamDVSResult));
 
         dvs_result->head.type = XCAM_3A_RESULT_DVS;
diff --git a/plugins/smart/sample/Makefile.am b/plugins/smart/sample/Makefile.am
index 407d2dd3..2dc4b51 100644
--- a/plugins/smart/sample/Makefile.am
+++ b/plugins/smart/sample/Makefile.am
@@ -1,46 +1,38 @@
-noinst_LTLIBRARIES = \
+noinst_LTLIBRARIES = libxcam_sample_smart.la
+
+XCAM_SAMPLE_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)              \
+    -I$(top_srcdir)/xcore         \
+    -I$(top_srcdir)/modules/isp   \
+    -I$(top_srcdir)/plugins/smart \
     $(NULL)
 
-if ENABLE_IA_AIQ
-noinst_LTLIBRARIES += \
-    libxcam_sample_smart.la \
-    $(NULL)
-endif
-
-XCAMSMART_CXXFLAGS = $(XCAM_CXXFLAGS)
-XCAMSMART_LIBS = \
+XCAM_SAMPLE_LIBS = \
+    $(top_builddir)/xcore/libxcam_core.la \
     $(NULL)
 
 if USE_LOCAL_ATOMISP
-XCAMSMART_CXXFLAGS += \
-    -I$(top_srcdir)/ext/atomisp  \
+XCAM_SAMPLE_CXXFLAGS += \
+    -I$(top_srcdir)/ext/atomisp \
     $(NULL)
 endif
 
 plugindir="$(libdir)/xcam/plugins/smart"
 
-if ENABLE_IA_AIQ
 libxcam_sample_smart_la_SOURCES = \
-    sample_smart_analysis.cpp    \
+    sample_smart_analysis.cpp \
     $(NULL)
 
 libxcam_sample_smart_la_CXXFLAGS = \
-    $(GST_CFLAGS) $(XCAMSMART_CXXFLAGS)  \
-    -I$(top_srcdir)/xcore                \
-    -I$(top_srcdir)/modules/isp          \
-    -I$(top_srcdir)/plugins/smart        \
+    $(XCAM_SAMPLE_CXXFLAGS) \
     $(NULL)
 
 libxcam_sample_smart_la_LIBADD = \
-    $(XCAMSMART_LIBS)                      \
-    $(top_builddir)/xcore/libxcam_core.la  \
+    $(XCAM_SAMPLE_LIBS) \
     $(NULL)
 
 libxcam_sample_smart_la_LDFLAGS = \
-    -module -avoid-version                 \
-    $(top_builddir)/xcore/libxcam_core.la  \
-    $(PTHREAD_LDFLAGS)                     \
+    -module -avoid-version \
     $(NULL)
-endif
 
 libxcam_sample_smart_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/plugins/smart/sample/sample_smart_analysis.cpp b/plugins/smart/sample/sample_smart_analysis.cpp
index a144946..defcca4 100644
--- a/plugins/smart/sample/sample_smart_analysis.cpp
+++ b/plugins/smart/sample/sample_smart_analysis.cpp
@@ -228,10 +228,11 @@
 XCamReturn
 SampleHandler::analyze (XCamVideoBuffer *buffer)
 {
-    XCAM_LOG_DEBUG ("Smart SampleHandler::analyze on ts:" XCAM_TIMESTAMP_FORMAT, XCAM_TIMESTAMP_ARGS (buffer->timestamp));
     if (NULL == buffer) {
         return XCAM_RETURN_ERROR_PARAM;
     }
+    XCAM_LOG_DEBUG ("Smart SampleHandler::analyze on ts:" XCAM_TIMESTAMP_FORMAT, XCAM_TIMESTAMP_ARGS (buffer->timestamp));
+
     XCamReturn ret = XCAM_RETURN_NO_ERROR;
 
     XCAM_LOG_DEBUG ("format(0x%x), color_bits(%d)", buffer->info.format, buffer->info.color_bits);
diff --git a/shaders/Makefile.am b/shaders/Makefile.am
new file mode 100644
index 0000000..4e540d5
--- /dev/null
+++ b/shaders/Makefile.am
@@ -0,0 +1,9 @@
+if HAVE_LIBCL
+CLX_DIR = clx
+endif
+
+if HAVE_GLES
+GLSLX_DIR = glslx
+endif
+
+SUBDIRS = $(CLX_DIR) $(GLSLX_DIR)
diff --git a/cl_kernel/kernel_3d_denoise.cl b/shaders/cl/kernel_3d_denoise.cl
similarity index 100%
rename from cl_kernel/kernel_3d_denoise.cl
rename to shaders/cl/kernel_3d_denoise.cl
diff --git a/cl_kernel/kernel_3d_denoise_slm.cl b/shaders/cl/kernel_3d_denoise_slm.cl
similarity index 100%
rename from cl_kernel/kernel_3d_denoise_slm.cl
rename to shaders/cl/kernel_3d_denoise_slm.cl
diff --git a/cl_kernel/kernel_bayer_basic.cl b/shaders/cl/kernel_bayer_basic.cl
similarity index 100%
rename from cl_kernel/kernel_bayer_basic.cl
rename to shaders/cl/kernel_bayer_basic.cl
diff --git a/cl_kernel/kernel_bayer_pipe.cl b/shaders/cl/kernel_bayer_pipe.cl
similarity index 100%
rename from cl_kernel/kernel_bayer_pipe.cl
rename to shaders/cl/kernel_bayer_pipe.cl
diff --git a/cl_kernel/kernel_bi_filter.cl b/shaders/cl/kernel_bi_filter.cl
similarity index 100%
rename from cl_kernel/kernel_bi_filter.cl
rename to shaders/cl/kernel_bi_filter.cl
diff --git a/cl_kernel/kernel_csc.cl b/shaders/cl/kernel_csc.cl
similarity index 100%
rename from cl_kernel/kernel_csc.cl
rename to shaders/cl/kernel_csc.cl
diff --git a/cl_kernel/kernel_defog_dcp.cl b/shaders/cl/kernel_defog_dcp.cl
similarity index 100%
rename from cl_kernel/kernel_defog_dcp.cl
rename to shaders/cl/kernel_defog_dcp.cl
diff --git a/cl_kernel/kernel_demo.cl b/shaders/cl/kernel_demo.cl
similarity index 100%
rename from cl_kernel/kernel_demo.cl
rename to shaders/cl/kernel_demo.cl
diff --git a/cl_kernel/kernel_fisheye.cl b/shaders/cl/kernel_fisheye.cl
similarity index 100%
rename from cl_kernel/kernel_fisheye.cl
rename to shaders/cl/kernel_fisheye.cl
diff --git a/cl_kernel/kernel_gauss.cl b/shaders/cl/kernel_gauss.cl
similarity index 100%
rename from cl_kernel/kernel_gauss.cl
rename to shaders/cl/kernel_gauss.cl
diff --git a/cl_kernel/kernel_gauss_lap_pyramid.cl b/shaders/cl/kernel_gauss_lap_pyramid.cl
similarity index 100%
rename from cl_kernel/kernel_gauss_lap_pyramid.cl
rename to shaders/cl/kernel_gauss_lap_pyramid.cl
diff --git a/cl_kernel/kernel_geo_map.cl b/shaders/cl/kernel_geo_map.cl
similarity index 69%
rename from cl_kernel/kernel_geo_map.cl
rename to shaders/cl/kernel_geo_map.cl
index b696a40..40b191a 100644
--- a/cl_kernel/kernel_geo_map.cl
+++ b/shaders/cl/kernel_geo_map.cl
@@ -14,6 +14,10 @@
 #define ENABLE_LSC 0
 #endif
 
+#ifndef ENABLE_SCALE
+#define ENABLE_SCALE 0
+#endif
+
 #define CONST_DATA_Y 0.0f
 #define CONST_DATA_UV (float2)(0.5f, 0.5f)
 
@@ -66,6 +70,10 @@
 kernel_geo_map (
     __read_only image2d_t input_y, __read_only image2d_t input_uv,
     __read_only image2d_t geo_table, float2 table_scale_size,
+#if ENABLE_SCALE
+    float2 left_scale_factor, float2 right_scale_factor,
+    float stable_y_start,
+#endif
 #if ENABLE_LSC
     __read_only image2d_t lsc_table, float2 gray_threshold,
 #endif
@@ -79,11 +87,33 @@
     bool out_of_bound[8];
     float2 input_pos[8];
     // map to [-0.5, 0.5)
-    float2 table_scale_step = 1.0f / table_scale_size;
+    float2 scale = 1.0f;
+
+#if ENABLE_SCALE
+    float a, b, c;
+    float y_m = stable_y_start * 0.5f;
+
+    float2 scale_factor = (g_x * PIXEL_RES_STEP_X < out_size.x / 2.0f) ? left_scale_factor : right_scale_factor;
+    a = (1 - scale_factor.x) / ((stable_y_start - y_m) * (stable_y_start - y_m));
+    b = -2 * a * y_m;
+    c = 1 - a * stable_y_start * stable_y_start - b * stable_y_start;
+
+    scale.y = (g_y >= stable_y_start) ? 1.0f : ((right_scale_factor.y - left_scale_factor.y) /
+              (out_size.x - PIXEL_RES_STEP_X) * g_x * PIXEL_RES_STEP_X + left_scale_factor.y);
+    float y_scale = ((float)g_y - stable_y_start) * scale.y + stable_y_start;
+    scale.x = (y_scale >= stable_y_start) ? 1.0f : ((y_scale < y_m) ? scale_factor.x : (a * y_scale * y_scale + b * y_scale + c));
+#endif
+
+    float2 table_scale_step = 1.0f / (table_scale_size * scale);
     float2 out_map_pos;
     sampler_t sampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR;
 
+#if ENABLE_SCALE
+    out_map_pos.x = (g_x * PIXEL_RES_STEP_X - out_size.x / 2.0f) * table_scale_step.x + 0.5f;
+    out_map_pos.y = ((float)g_y - stable_y_start) * table_scale_step.y + stable_y_start / out_size.y;
+#else
     out_map_pos = (convert_float2((int2)(g_x * PIXEL_RES_STEP_X, g_y)) - out_size / 2.0f) * table_scale_step + 0.5f;
+#endif
 
     get_geo_mapped_y (input_y, geo_table, out_map_pos, table_scale_step.x, out_of_bound, input_pos, &output_data);
 
@@ -100,7 +130,21 @@
     output_data.s67 = out_of_bound[6] ? CONST_DATA_UV : read_imagef (input_uv, sampler, input_pos[6]).xy;
     write_imageui (output_uv, (int2)(g_x, g_y_uv), convert_uint4(as_ushort4(convert_uchar8(output_data * 255.0f))));
 
+#if ENABLE_SCALE
+    scale.y = (g_y + 1 >= stable_y_start) ? 1.0f : ((right_scale_factor.y - left_scale_factor.y) /
+              (out_size.x - PIXEL_RES_STEP_X) * g_x * PIXEL_RES_STEP_X + left_scale_factor.y);
+    y_scale = (g_y + 1 - stable_y_start) * scale.y + stable_y_start;
+    scale.x = (y_scale >= stable_y_start) ? 1.0f :
+              ((y_scale < y_m) ? scale_factor.x : (a * y_scale * y_scale + b * y_scale + c));
+
+    table_scale_step = 1.0f / (table_scale_size * scale);
+
+    out_map_pos.x = (g_x * PIXEL_RES_STEP_X - out_size.x / 2.0f) * table_scale_step.x + 0.5f;
+    out_map_pos.y = ((float)g_y + 1 - stable_y_start) * table_scale_step.y + stable_y_start / out_size.y;
+#else
     out_map_pos.y += table_scale_step.y;
+#endif
+
     get_geo_mapped_y (input_y, geo_table, out_map_pos, table_scale_step.x, out_of_bound, input_pos, &output_data);
 
 #if ENABLE_LSC
diff --git a/cl_kernel/kernel_image_scaler.cl b/shaders/cl/kernel_image_scaler.cl
similarity index 100%
rename from cl_kernel/kernel_image_scaler.cl
rename to shaders/cl/kernel_image_scaler.cl
diff --git a/cl_kernel/kernel_image_warp.cl b/shaders/cl/kernel_image_warp.cl
similarity index 100%
rename from cl_kernel/kernel_image_warp.cl
rename to shaders/cl/kernel_image_warp.cl
diff --git a/cl_kernel/kernel_min_filter.cl b/shaders/cl/kernel_min_filter.cl
similarity index 100%
rename from cl_kernel/kernel_min_filter.cl
rename to shaders/cl/kernel_min_filter.cl
diff --git a/cl_kernel/kernel_newtonemapping.cl b/shaders/cl/kernel_newtonemapping.cl
similarity index 100%
rename from cl_kernel/kernel_newtonemapping.cl
rename to shaders/cl/kernel_newtonemapping.cl
diff --git a/cl_kernel/kernel_retinex.cl b/shaders/cl/kernel_retinex.cl
similarity index 100%
rename from cl_kernel/kernel_retinex.cl
rename to shaders/cl/kernel_retinex.cl
diff --git a/cl_kernel/kernel_rgb_pipe.cl b/shaders/cl/kernel_rgb_pipe.cl
similarity index 100%
rename from cl_kernel/kernel_rgb_pipe.cl
rename to shaders/cl/kernel_rgb_pipe.cl
diff --git a/cl_kernel/kernel_tnr.cl b/shaders/cl/kernel_tnr.cl
similarity index 100%
rename from cl_kernel/kernel_tnr.cl
rename to shaders/cl/kernel_tnr.cl
diff --git a/cl_kernel/kernel_tonemapping.cl b/shaders/cl/kernel_tonemapping.cl
similarity index 100%
rename from cl_kernel/kernel_tonemapping.cl
rename to shaders/cl/kernel_tonemapping.cl
diff --git a/cl_kernel/kernel_wavelet_coeff.cl b/shaders/cl/kernel_wavelet_coeff.cl
similarity index 100%
rename from cl_kernel/kernel_wavelet_coeff.cl
rename to shaders/cl/kernel_wavelet_coeff.cl
diff --git a/cl_kernel/kernel_wavelet_denoise.cl b/shaders/cl/kernel_wavelet_denoise.cl
similarity index 100%
rename from cl_kernel/kernel_wavelet_denoise.cl
rename to shaders/cl/kernel_wavelet_denoise.cl
diff --git a/cl_kernel/kernel_wavelet_haar.cl b/shaders/cl/kernel_wavelet_haar.cl
similarity index 100%
rename from cl_kernel/kernel_wavelet_haar.cl
rename to shaders/cl/kernel_wavelet_haar.cl
diff --git a/cl_kernel/kernel_wire_frame.cl b/shaders/cl/kernel_wire_frame.cl
similarity index 100%
rename from cl_kernel/kernel_wire_frame.cl
rename to shaders/cl/kernel_wire_frame.cl
diff --git a/cl_kernel/kernel_yuv_pipe.cl b/shaders/cl/kernel_yuv_pipe.cl
similarity index 100%
rename from cl_kernel/kernel_yuv_pipe.cl
rename to shaders/cl/kernel_yuv_pipe.cl
diff --git a/clx_kernel/.gitignore b/shaders/clx/.gitignore
similarity index 100%
rename from clx_kernel/.gitignore
rename to shaders/clx/.gitignore
diff --git a/shaders/clx/Makefile.am b/shaders/clx/Makefile.am
new file mode 100644
index 0000000..b122b1b
--- /dev/null
+++ b/shaders/clx/Makefile.am
@@ -0,0 +1,39 @@
+clx_sources = \
+    kernel_csc.clx               \
+    kernel_demo.clx              \
+    kernel_defog_dcp.clx         \
+    kernel_min_filter.clx        \
+    kernel_bi_filter.clx         \
+    kernel_tnr.clx               \
+    kernel_bayer_pipe.clx        \
+    kernel_bayer_basic.clx       \
+    kernel_fisheye.clx           \
+    kernel_rgb_pipe.clx          \
+    kernel_yuv_pipe.clx          \
+    kernel_tonemapping.clx       \
+    kernel_newtonemapping.clx    \
+    kernel_image_scaler.clx      \
+    kernel_retinex.clx           \
+    kernel_gauss.clx             \
+    kernel_gauss_lap_pyramid.clx \
+    kernel_geo_map.clx           \
+    kernel_wavelet_denoise.clx   \
+    kernel_wavelet_haar.clx      \
+    kernel_wavelet_coeff.clx     \
+    kernel_wire_frame.clx        \
+    kernel_3d_denoise.clx        \
+    kernel_3d_denoise_slm.clx    \
+    kernel_image_warp.clx        \
+    $(NULL)
+
+add_quotation_marks_sh = \
+    $(top_srcdir)/tools/add-quotation-marks.sh
+
+cl_dir = $(top_srcdir)/shaders/cl
+
+all-local: $(clx_sources)
+
+$(clx_sources): %.clx: $(cl_dir)/%.cl
+	@$(add_quotation_marks_sh) $< $@
+
+CLEANFILES = $(clx_sources)
diff --git a/shaders/glsl/shader_blend_pyr.comp.sl b/shaders/glsl/shader_blend_pyr.comp.sl
new file mode 100644
index 0000000..dd1fb0f
--- /dev/null
+++ b/shaders/glsl/shader_blend_pyr.comp.sl
@@ -0,0 +1,91 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer In0BufY {
+    uvec2 data[];
+} in0_buf_y;
+
+layout (binding = 1) readonly buffer In0BufUV {
+    uvec2 data[];
+} in0_buf_uv;
+
+layout (binding = 2) readonly buffer In1BufY {
+    uvec2 data[];
+} in1_buf_y;
+
+layout (binding = 3) readonly buffer In1BufUV {
+    uvec2 data[];
+} in1_buf_uv;
+
+layout (binding = 4) writeonly buffer OutBufY {
+    uvec2 data[];
+} out_buf_y;
+
+layout (binding = 5) writeonly buffer OutBufUV {
+    uvec2 data[];
+} out_buf_uv;
+
+layout (binding = 6) readonly buffer MaskBuf {
+    uvec2 data[];
+} mask_buf;
+
+uniform uint in_img_width;
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+    g_id.x = clamp (g_id.x, 0u, in_img_width - 1u);
+
+    uvec2 mask = mask_buf.data[g_id.x];
+    vec4 mask0 = unpackUnorm4x8 (mask.x);
+    vec4 mask1 = unpackUnorm4x8 (mask.y);
+
+    uint y_idx = g_id.y * 2u * in_img_width + g_id.x;
+    uvec2 in0_y = in0_buf_y.data[y_idx];
+    vec4 in0_y0 = unpackUnorm4x8 (in0_y.x);
+    vec4 in0_y1 = unpackUnorm4x8 (in0_y.y);
+
+    uvec2 in1_y = in1_buf_y.data[y_idx];
+    vec4 in1_y0 = unpackUnorm4x8 (in1_y.x);
+    vec4 in1_y1 = unpackUnorm4x8 (in1_y.y);
+
+    vec4 out_y0 = (in0_y0 - in1_y0) * mask0 + in1_y0;
+    vec4 out_y1 = (in0_y1 - in1_y1) * mask1 + in1_y1;
+    out_y0 = clamp (out_y0, 0.0f, 1.0f);
+    out_y1 = clamp (out_y1, 0.0f, 1.0f);
+    out_buf_y.data[y_idx] = uvec2 (packUnorm4x8 (out_y0), packUnorm4x8 (out_y1));
+
+    y_idx += in_img_width;
+    in0_y = in0_buf_y.data[y_idx];
+    in0_y0 = unpackUnorm4x8 (in0_y.x);
+    in0_y1 = unpackUnorm4x8 (in0_y.y);
+
+    in1_y = in1_buf_y.data[y_idx];
+    in1_y0 = unpackUnorm4x8 (in1_y.x);
+    in1_y1 = unpackUnorm4x8 (in1_y.y);
+
+    out_y0 = (in0_y0 - in1_y0) * mask0 + in1_y0;
+    out_y1 = (in0_y1 - in1_y1) * mask1 + in1_y1;
+    out_y0 = clamp (out_y0, 0.0f, 1.0f);
+    out_y1 = clamp (out_y1, 0.0f, 1.0f);
+    out_buf_y.data[y_idx] = uvec2 (packUnorm4x8 (out_y0), packUnorm4x8 (out_y1));
+
+    uint uv_idx = g_id.y * in_img_width + g_id.x;
+    uvec2 in0_uv = in0_buf_uv.data[uv_idx];
+    vec4 in0_uv0 = unpackUnorm4x8 (in0_uv.x);
+    vec4 in0_uv1 = unpackUnorm4x8 (in0_uv.y);
+
+    uvec2 in1_uv = in1_buf_uv.data[uv_idx];
+    vec4 in1_uv0 = unpackUnorm4x8 (in1_uv.x);
+    vec4 in1_uv1 = unpackUnorm4x8 (in1_uv.y);
+
+    mask0.yw = mask0.xz;
+    mask1.yw = mask1.xz;
+    vec4 out_uv0 = (in0_uv0 - in1_uv0) * mask0 + in1_uv0;
+    vec4 out_uv1 = (in0_uv1 - in1_uv1) * mask1 + in1_uv1;
+
+    out_uv0 = clamp (out_uv0, 0.0f, 1.0f);
+    out_uv1 = clamp (out_uv1, 0.0f, 1.0f);
+    out_buf_uv.data[uv_idx] = uvec2 (packUnorm4x8 (out_uv0), packUnorm4x8 (out_uv1));
+}
diff --git a/shaders/glsl/shader_copy.comp.sl b/shaders/glsl/shader_copy.comp.sl
new file mode 100644
index 0000000..ced6c91
--- /dev/null
+++ b/shaders/glsl/shader_copy.comp.sl
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBuf {
+    uvec4 data[];
+} in_buf;
+
+layout (binding = 1) writeonly buffer OutBuf {
+    uvec4 data[];
+} out_buf;
+
+uniform uint in_img_width;
+uniform uint in_x_offset;
+
+uniform uint out_img_width;
+uniform uint out_x_offset;
+
+uniform uint copy_width;
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+    g_id.x = min (g_id.x, copy_width - 1u);
+
+    out_buf.data[g_id.y * out_img_width + out_x_offset + g_id.x] =
+        in_buf.data[g_id.y * in_img_width + in_x_offset + g_id.x];
+}
diff --git a/shaders/glsl/shader_gauss_scale_pyr.comp.sl b/shaders/glsl/shader_gauss_scale_pyr.comp.sl
new file mode 100644
index 0000000..1fbdd8f
--- /dev/null
+++ b/shaders/glsl/shader_gauss_scale_pyr.comp.sl
@@ -0,0 +1,174 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBufY {
+    uint data[];
+} in_buf_y;
+
+layout (binding = 1) readonly buffer InBufUV {
+    uint data[];
+} in_buf_uv;
+
+layout (binding = 2) writeonly buffer OutBufY {
+    uint data[];
+} out_buf_y;
+
+layout (binding = 3) writeonly buffer OutBufUV {
+    uint data[];
+} out_buf_uv;
+
+uniform uint in_img_width;
+uniform uint in_img_height;
+uniform uint in_offset_x;
+
+uniform uint out_img_width;
+
+uniform uint merge_width;
+
+const float coeffs[5] = float[] (0.152f, 0.222f, 0.252f, 0.222f, 0.152f);
+
+#define unpack_unorm(buf, pixel, idx) \
+    { \
+        pixel[0] = unpackUnorm4x8 (buf.data[idx]); \
+        pixel[1] = unpackUnorm4x8 (buf.data[idx + 1u]); \
+        pixel[2] = unpackUnorm4x8 (buf.data[idx + 2u]); \
+        pixel[3] = unpackUnorm4x8 (buf.data[idx + 3u]); \
+    }
+
+#define multiply_coeff(sum, pixel, idx) \
+    { \
+        sum[0] += pixel[0] * coeffs[idx]; \
+        sum[1] += pixel[1] * coeffs[idx]; \
+        sum[2] += pixel[2] * coeffs[idx]; \
+        sum[3] += pixel[3] * coeffs[idx]; \
+    }
+
+void gauss_scale_y (uvec2 y_id);
+void gauss_scale_uv (uvec2 uv_id);
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+    g_id.x = clamp (g_id.x, 0u, merge_width - 1u);
+
+    uvec2 y_id = g_id * uvec2 (1u, 2u);
+    gauss_scale_y (y_id);
+
+    gauss_scale_uv (g_id);
+}
+
+void gauss_scale_y (uvec2 y_id)
+{
+    uvec2 in_id = y_id * 2u;
+    uvec2 gauss_start = in_id - uvec2 (1u, 2u);
+    gauss_start.y = clamp (gauss_start.y, 0u, in_img_height - 7u);
+
+    vec4 sum0[4] = vec4[] (vec4 (0.0f), vec4 (0.0f), vec4 (0.0f), vec4 (0.0f));
+    vec4 sum1[4] = vec4[] (vec4 (0.0f), vec4 (0.0f), vec4 (0.0f), vec4 (0.0f));
+
+    vec4 pixel_y[4];
+    uint in_idx = (in_id.y == 0u) ? (in_id.x - 1u) : (gauss_start.y * in_img_width + gauss_start.x);
+    in_idx += in_offset_x;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 0u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + in_img_width);
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 1u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + in_img_width);
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 2u);
+    multiply_coeff (sum1, pixel_y, 0u);
+
+    in_idx += in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 3u);
+    multiply_coeff (sum1, pixel_y, 1u);
+
+    in_idx += in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 4u);
+    multiply_coeff (sum1, pixel_y, 2u);
+
+    in_idx += in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum1, pixel_y, 3u);
+
+    in_idx += in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum1, pixel_y, 4u);
+
+    sum0[0] = (in_id.x == 0u) ? vec4 (sum0[1].x) : sum0[0];
+    sum1[0] = (in_id.x == 0u) ? vec4 (sum1[1].x) : sum1[0];
+    sum0[3] = (in_id.x == merge_width - 2u) ? vec4 (sum0[2].w) : sum0[3];
+    sum1[3] = (in_id.x == merge_width - 2u) ? vec4 (sum1[2].w) : sum1[3];
+
+    vec4 out_data0 =
+        vec4 (sum0[0].z, sum0[1].x, sum0[1].z, sum0[2].x) * coeffs[0] +
+        vec4 (sum0[0].w, sum0[1].y, sum0[1].w, sum0[2].y) * coeffs[1] +
+        vec4 (sum0[1].x, sum0[1].z, sum0[2].x, sum0[2].z) * coeffs[2] +
+        vec4 (sum0[1].y, sum0[1].w, sum0[2].y, sum0[2].w) * coeffs[3] +
+        vec4 (sum0[1].z, sum0[2].x, sum0[2].z, sum0[3].x) * coeffs[4];
+
+    vec4 out_data1 =
+        vec4 (sum1[0].z, sum1[1].x, sum1[1].z, sum1[2].x) * coeffs[0] +
+        vec4 (sum1[0].w, sum1[1].y, sum1[1].w, sum1[2].y) * coeffs[1] +
+        vec4 (sum1[1].x, sum1[1].z, sum1[2].x, sum1[2].z) * coeffs[2] +
+        vec4 (sum1[1].y, sum1[1].w, sum1[2].y, sum1[2].w) * coeffs[3] +
+        vec4 (sum1[1].z, sum1[2].x, sum1[2].z, sum1[3].x) * coeffs[4];
+
+    out_data0 = clamp (out_data0, 0.0f, 1.0f);
+    out_data1 = clamp (out_data1, 0.0f, 1.0f);
+
+    y_id.x = clamp (y_id.x, 0u, out_img_width - 1u);
+    uint out_idx = y_id.y * out_img_width + y_id.x;
+    out_buf_y.data[out_idx] = packUnorm4x8 (out_data0);
+    out_buf_y.data[out_idx + out_img_width] = packUnorm4x8 (out_data1);
+}
+
+void gauss_scale_uv (uvec2 uv_id)
+{
+    uvec2 in_id = uv_id * 2u;
+    uvec2 gauss_start = in_id - uvec2 (1u, 2u);
+    gauss_start.y = clamp (gauss_start.y, 0u, in_img_height / 2u - 5u);
+
+    vec4 sum[4] = vec4[] (vec4 (0.0f), vec4 (0.0f), vec4 (0.0f), vec4 (0.0f));
+    uint in_idx = (in_id.y == 0u) ? (in_id.x - 1u) : (gauss_start.y * in_img_width + gauss_start.x);
+    in_idx += in_offset_x;
+
+    vec4 pixel_uv[4];
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 0u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + in_img_width);
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 1u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + in_img_width);
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 2u);
+
+    in_idx += in_img_width;
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 3u);
+
+    in_idx += in_img_width;
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 4u);
+
+    sum[0] = (in_id.x == 0u) ? vec4 (sum[1]) : sum[0];
+    sum[3] = (in_id.x == merge_width - 2u) ? vec4 (sum[2]) : sum[3];
+
+    vec4 out_data =
+        vec4 (sum[0].x, sum[0].y, sum[1].x, sum[1].y) * coeffs[0] +
+        vec4 (sum[0].z, sum[0].w, sum[1].z, sum[1].w) * coeffs[1] +
+        vec4 (sum[1].x, sum[1].y, sum[2].x, sum[2].y) * coeffs[2] +
+        vec4 (sum[1].z, sum[1].w, sum[2].z, sum[2].w) * coeffs[3] +
+        vec4 (sum[2].x, sum[2].y, sum[3].x, sum[3].y) * coeffs[4];
+
+    out_data = clamp (out_data, 0.0f, 1.0f);
+    uv_id.x = clamp (uv_id.x, 0u, out_img_width - 1u);
+    out_buf_uv.data[uv_id.y * out_img_width + uv_id.x] = packUnorm4x8 (out_data);
+}
diff --git a/shaders/glsl/shader_geomap.comp.sl b/shaders/glsl/shader_geomap.comp.sl
new file mode 100644
index 0000000..d2b5b70
--- /dev/null
+++ b/shaders/glsl/shader_geomap.comp.sl
@@ -0,0 +1,238 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBufY {
+    uint data[];
+} in_buf_y;
+
+layout (binding = 1) readonly buffer InBufUV {
+    uint data[];
+} in_buf_uv;
+
+layout (binding = 2) writeonly buffer OutBufY {
+    uint data[];
+} out_buf_y;
+
+layout (binding = 3) writeonly buffer OutBufUV {
+    uint data[];
+} out_buf_uv;
+
+layout (binding = 4) readonly buffer GeoMapTable {
+    vec2 data[];
+} lut;
+
+uniform uint in_img_width;
+uniform uint in_img_height;
+
+uniform uint out_img_width;
+uniform uint out_img_height;
+
+uniform uint lut_width;
+uniform uint lut_height;
+
+uniform vec4 lut_step;
+uniform vec2 lut_std_step;
+
+#define UNIT_SIZE 4u
+
+#define unpack_unorm_y(index) \
+    { \
+        vec4 value = unpackUnorm4x8 (in_buf_y.data[index00[index]]); \
+        out_y00[index] = value[x00_fract[index]]; \
+        value = unpackUnorm4x8 (in_buf_y.data[index01[index]]); \
+        out_y01[index] = value[x01_fract[index]]; \
+        value = unpackUnorm4x8 (in_buf_y.data[index10[index]]); \
+        out_y10[index] = value[x10_fract[index]]; \
+        value = unpackUnorm4x8 (in_buf_y.data[index11[index]]); \
+        out_y11[index] = value[x11_fract[index]]; \
+    }
+
+void geomap_y (vec4 lut_x, vec4 lut_y, out vec4 in_img_x, out vec4 in_img_y, out bvec4 out_bound, out uint out_data);
+void geomap_uv (vec2 in_uv_x, vec2 in_uv_y, bvec4 out_bound_uv, out uint out_data);
+
+void main ()
+{
+    uint g_x = gl_GlobalInvocationID.x;
+    uint g_y = gl_GlobalInvocationID.y * 2u;
+
+    vec2 cent = (vec2 (out_img_width, out_img_height) - 1.0f) / 2.0f;
+    vec2 step = g_x < uint (cent.x) ? lut_step.xy : lut_step.zw;
+
+    vec2 start = (vec2 (g_x, g_y) - cent) * step + cent * lut_std_step;
+    vec4 lut_x = start.x * float (UNIT_SIZE) + vec4 (0.0f, step.x, step.x * 2.0f, step.x * 3.0f);
+    vec4 lut_y = start.yyyy;
+    lut_x = clamp (lut_x, 0.0f, float (lut_width) - 1.0f);
+    lut_y = clamp (lut_y, 0.0f, float (lut_height) - 1.0f - step.y);
+
+    uint out_data;
+    vec4 in_img_x, in_img_y;
+    bvec4 out_bound;
+    geomap_y (lut_x, lut_y, in_img_x, in_img_y, out_bound, out_data);
+    out_buf_y.data[g_y * out_img_width + g_x] = out_data;
+
+    bvec4 out_bound_uv = out_bound.xxzz;
+    if (all (out_bound_uv)) {
+        out_data = packUnorm4x8 (vec4 (0.5f));
+    } else {
+        vec2 in_uv_x = in_img_x.xz;
+        vec2 in_uv_y = in_img_y.xz / 2.0f;
+        in_uv_y = clamp (in_uv_y, 0.0f, float (in_img_height / 2u - 1u));
+        geomap_uv (in_uv_x, in_uv_y, out_bound_uv, out_data);
+    }
+    out_buf_uv.data[g_y / 2u * out_img_width + g_x] = out_data;
+
+    lut_y += step.y;
+    geomap_y (lut_x, lut_y, in_img_x, in_img_y, out_bound, out_data);
+    out_buf_y.data[(g_y + 1u) * out_img_width + g_x] = out_data;
+}
+
+void geomap_y (vec4 lut_x, vec4 lut_y, out vec4 in_img_x, out vec4 in_img_y, out bvec4 out_bound, out uint out_data)
+{
+    uvec4 x00 = uvec4 (lut_x);
+    uvec4 y00 = uvec4 (lut_y);
+    uvec4 x01 = x00 + 1u;
+    uvec4 y01 = y00;
+    uvec4 x10 = x00;
+    uvec4 y10 = y00 + 1u;
+    uvec4 x11 = x01;
+    uvec4 y11 = y10;
+
+    vec4 fract_x = fract (lut_x);
+    vec4 fract_y = fract (lut_y);
+    vec4 weight00 = (1.0f - fract_x) * (1.0f - fract_y);
+    vec4 weight01 = fract_x * (1.0f - fract_y);
+    vec4 weight10 = (1.0f - fract_x) * fract_y;
+    vec4 weight11 = fract_x * fract_y;
+
+    uvec4 index00 = y00 * lut_width + x00;
+    uvec4 index01 = y01 * lut_width + x01;
+    uvec4 index10 = y10 * lut_width + x10;
+    uvec4 index11 = y11 * lut_width + x11;
+
+    vec4 in_img_x00, in_img_x01, in_img_x10, in_img_x11;
+    vec4 in_img_y00, in_img_y01, in_img_y10, in_img_y11;
+    for (uint i = 0u; i < UNIT_SIZE; ++i) {
+        vec2 value = lut.data[index00[i]];
+        in_img_x00[i] = value.x;
+        in_img_y00[i] = value.y;
+        value = lut.data[index01[i]];
+        in_img_x01[i] = value.x;
+        in_img_y01[i] = value.y;
+        value = lut.data[index10[i]];
+        in_img_x10[i] = value.x;
+        in_img_y10[i] = value.y;
+        value = lut.data[index11[i]];
+        in_img_x11[i] = value.x;
+        in_img_y11[i] = value.y;
+    }
+    in_img_x = in_img_x00 * weight00 + in_img_x01 * weight01 + in_img_x10 * weight10 + in_img_x11 * weight11;
+    in_img_y = in_img_y00 * weight00 + in_img_y01 * weight01 + in_img_y10 * weight10 + in_img_y11 * weight11;
+
+    for (uint i = 0u; i < UNIT_SIZE; ++i) {
+        out_bound[i] = in_img_x[i] < 0.0f || in_img_x[i] > float (in_img_width * UNIT_SIZE - 1u) ||
+                       in_img_y[i] < 0.0f || in_img_y[i] > float (in_img_height - 1u);
+    }
+    if (all (out_bound)) {
+        out_data = 0u;
+        return;
+    }
+
+    x00 = uvec4 (in_img_x);
+    y00 = uvec4 (in_img_y);
+    x01 = x00 + 1u;
+    y01 = y00;
+    x10 = x00;
+    y10 = y00 + 1u;
+    x11 = x01;
+    y11 = y10;
+
+    fract_x = fract (in_img_x);
+    fract_y = fract (in_img_y);
+    weight00 = (1.0f - fract_x) * (1.0f - fract_y);
+    weight01 = fract_x * (1.0f - fract_y);
+    weight10 = (1.0f - fract_x) * fract_y;
+    weight11 = fract_x * fract_y;
+
+    uvec4 x00_floor = x00 / UNIT_SIZE;
+    uvec4 x01_floor = x01 / UNIT_SIZE;
+    uvec4 x10_floor = x10 / UNIT_SIZE;
+    uvec4 x11_floor = x11 / UNIT_SIZE;
+    uvec4 x00_fract = x00 % UNIT_SIZE;
+    uvec4 x01_fract = x01 % UNIT_SIZE;
+    uvec4 x10_fract = x10 % UNIT_SIZE;
+    uvec4 x11_fract = x11 % UNIT_SIZE;
+
+    index00 = y00 * in_img_width + x00_floor;
+    index01 = y01 * in_img_width + x01_floor;
+    index10 = y10 * in_img_width + x10_floor;
+    index11 = y11 * in_img_width + x11_floor;
+
+    // pixel Y-value
+    vec4 out_y00, out_y01, out_y10, out_y11;
+    unpack_unorm_y (0);
+    unpack_unorm_y (1);
+    unpack_unorm_y (2);
+    unpack_unorm_y (3);
+
+    vec4 inter_y = out_y00 * weight00 + out_y01 * weight01 + out_y10 * weight10 + out_y11 * weight11;
+    out_data = packUnorm4x8 (inter_y * vec4 (not (out_bound)));
+}
+
+void geomap_uv (vec2 in_uv_x, vec2 in_uv_y, bvec4 out_bound_uv, out uint out_data)
+{
+    uvec2 x00 = uvec2 (in_uv_x);
+    uvec2 y00 = uvec2 (in_uv_y);
+    uvec2 x01 = x00 + 1u;
+    uvec2 y01 = y00;
+    uvec2 x10 = x00;
+    uvec2 y10 = y00 + 1u;
+    uvec2 x11 = x01;
+    uvec2 y11 = y10;
+
+    vec2 fract_x = fract (in_uv_x);
+    vec2 fract_y = fract (in_uv_y);
+    vec2 weight00 = (1.0f - fract_x) * (1.0f - fract_y);
+    vec2 weight01 = fract_x * (1.0f - fract_y);
+    vec2 weight10 = (1.0f - fract_x) * fract_y;
+    vec2 weight11 = fract_x * fract_y;
+
+    uvec2 x00_floor = x00 / UNIT_SIZE;
+    uvec2 x01_floor = x01 / UNIT_SIZE;
+    uvec2 x10_floor = x10 / UNIT_SIZE;
+    uvec2 x11_floor = x11 / UNIT_SIZE;
+    uvec2 x00_fract = (x00 % UNIT_SIZE) / 2u;
+    uvec2 x01_fract = (x01 % UNIT_SIZE) / 2u;
+    uvec2 x10_fract = (x10 % UNIT_SIZE) / 2u;
+    uvec2 x11_fract = (x11 % UNIT_SIZE) / 2u;
+
+    uvec2 index00 = y00 * in_img_width + x00_floor;
+    uvec2 index01 = y01 * in_img_width + x01_floor;
+    uvec2 index10 = y10 * in_img_width + x10_floor;
+    uvec2 index11 = y11 * in_img_width + x11_floor;
+
+    // pixel UV-value
+    vec4 out_uv00, out_uv01, out_uv10, out_uv11;
+    vec4 value = unpackUnorm4x8 (in_buf_uv.data[index00.x]);
+    out_uv00.xy = x00_fract.x == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index01.x]);
+    out_uv01.xy = x01_fract.x == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index10.x]);
+    out_uv10.xy = x10_fract.x == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index11.x]);
+    out_uv11.xy = x11_fract.x == 0u ? value.xy : value.zw;
+
+    value = unpackUnorm4x8 (in_buf_uv.data[index00.y]);
+    out_uv00.zw = x00_fract.y == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index01.y]);
+    out_uv01.zw = x01_fract.y == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index10.y]);
+    out_uv10.zw = x10_fract.y == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index11.y]);
+    out_uv11.zw = x11_fract.y == 0u ? value.xy : value.zw;
+
+    vec4 inter_uv = out_uv00 * weight00.xxyy + out_uv01 * weight01.xxyy +
+                    out_uv10 * weight10.xxyy + out_uv11 * weight11.xxyy;
+    inter_uv = inter_uv * vec4 (not (out_bound_uv)) + vec4 (out_bound_uv) * 0.5f;
+    out_data = packUnorm4x8 (inter_uv);
+}
diff --git a/shaders/glsl/shader_lap_trans_pyr.comp.sl b/shaders/glsl/shader_lap_trans_pyr.comp.sl
new file mode 100644
index 0000000..128a3a2
--- /dev/null
+++ b/shaders/glsl/shader_lap_trans_pyr.comp.sl
@@ -0,0 +1,162 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBufY {
+    uvec2 data[];
+} in_buf_y;
+
+layout (binding = 1) readonly buffer InBufUV {
+    uvec2 data[];
+} in_buf_uv;
+
+layout (binding = 2) readonly buffer GaussScaleBufY {
+    uint data[];
+} gaussscale_buf_y;
+
+layout (binding = 3) readonly buffer GaussScaleBufUV {
+    uint data[];
+} gaussscale_buf_uv;
+
+layout (binding = 4) writeonly buffer OutBufY {
+    uvec2 data[];
+} out_buf_y;
+
+layout (binding = 5) writeonly buffer OutBufUV {
+    uvec2 data[];
+} out_buf_uv;
+
+uniform uint in_img_width;
+uniform uint in_img_height;
+uniform uint in_offset_x;
+
+uniform uint gaussscale_img_width;
+uniform uint gaussscale_img_height;
+
+uniform uint merge_width;
+
+// normalization of half gray level
+const float norm_half_gl = 128.0f / 255.0f;
+
+void lap_trans_y (uvec2 y_id, uvec2 gs_id);
+void lap_trans_uv (uvec2 uv_id, uvec2 gs_id);
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+
+    uvec2 y_id = uvec2 (g_id.x, g_id.y * 4u);
+    y_id.x = clamp (y_id.x, 0u, merge_width - 1u);
+
+    uvec2 gs_id = uvec2 (g_id.x, g_id.y * 2u);
+    gs_id.x = clamp (gs_id.x, 0u, gaussscale_img_width - 1u);
+    lap_trans_y (y_id, gs_id);
+
+    y_id.y += 2u;
+    gs_id.y += 1u;
+    lap_trans_y (y_id, gs_id);
+
+    uvec2 uv_id = uvec2 (y_id.x, g_id.y * 2u);
+    gs_id.y = g_id.y;
+    lap_trans_uv (uv_id, gs_id);
+}
+
+void lap_trans_y (uvec2 y_id, uvec2 gs_id)
+{
+    y_id.y = clamp (y_id.y, 0u, in_img_height - 1u);
+    gs_id.y = clamp (gs_id.y, 0u, gaussscale_img_height - 1u);
+
+    uint y_idx = y_id.y * in_img_width + in_offset_x + y_id.x;
+    uvec2 in_pack = in_buf_y.data[y_idx];
+    vec4 in0 = unpackUnorm4x8 (in_pack.x);
+    vec4 in1 = unpackUnorm4x8 (in_pack.y);
+
+    uint gs_idx = gs_id.y * gaussscale_img_width + gs_id.x;
+    vec4 gs0 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx]);
+    vec4 gs1 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == gaussscale_img_width - 1u) ? gs0.wwww : gs1;
+
+    vec4 inter = (gs0 + vec4 (gs0.yzw, gs1.x)) * 0.5f;
+    vec4 inter00 = vec4 (gs0.x, inter.x, gs0.y, inter.y);
+    vec4 inter01 = vec4 (gs0.z, inter.z, gs0.w, inter.w);
+
+    vec4 lap0 = (in0 - inter00) * 0.5f + norm_half_gl;
+    vec4 lap1 = (in1 - inter01) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    uint out_idx = y_id.y * merge_width + y_id.x;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+
+    y_idx = (y_id.y >= in_img_height - 1u) ? y_idx : y_idx + in_img_width;
+    in_pack = in_buf_y.data[y_idx];
+    in0 = unpackUnorm4x8 (in_pack.x);
+    in1 = unpackUnorm4x8 (in_pack.y);
+
+    gs_idx = (gs_id.y >= gaussscale_img_height - 1u) ? gs_idx : gs_idx + gaussscale_img_width;
+    gs0 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx]);
+    gs1 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == gaussscale_img_width - 1u) ? gs0.wwww : gs1;
+
+    inter = (gs0 + vec4 (gs0.yzw, gs1.x)) * 0.5f;
+    vec4 inter10 = (inter00 + vec4 (gs0.x, inter.x, gs0.y, inter.y)) * 0.5f;
+    vec4 inter11 = (inter01 + vec4 (gs0.z, inter.z, gs0.w, inter.w)) * 0.5f;
+
+    lap0 = (in0 - inter10) * 0.5f + norm_half_gl;
+    lap1 = (in1 - inter11) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    out_idx += merge_width;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+}
+
+void lap_trans_uv (uvec2 uv_id, uvec2 gs_id)
+{
+    uv_id.y = clamp (uv_id.y, 0u, in_img_height / 2u - 1u);
+    gs_id.y = clamp (gs_id.y, 0u, gaussscale_img_height / 2u - 1u);
+
+    uint uv_idx = uv_id.y * in_img_width + in_offset_x + uv_id.x;
+    uvec2 in_pack = in_buf_uv.data[uv_idx];
+    vec4 in0 = unpackUnorm4x8 (in_pack.x);
+    vec4 in1 = unpackUnorm4x8 (in_pack.y);
+
+    uint gs_idx = gs_id.y * gaussscale_img_width + gs_id.x;
+    vec4 gs0 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx]);
+    vec4 gs1 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == gaussscale_img_width - 1u) ? gs0.zwzw : gs1;
+
+    vec4 inter = (gs0 + vec4 (gs0.zw, gs1.xy)) * 0.5f;
+    vec4 inter00 = vec4 (gs0.xy, inter.xy);
+    vec4 inter01 = vec4 (gs0.zw, inter.zw);
+
+    vec4 lap0 = (in0 - inter00) * 0.5f + norm_half_gl;
+    vec4 lap1 = (in1 - inter01) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    uint out_idx = uv_id.y * merge_width + uv_id.x;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+
+    uv_idx = (uv_id.y >= (in_img_height / 2u - 1u)) ? uv_idx : uv_idx + in_img_width;
+    in_pack = in_buf_uv.data[uv_idx];
+    in0 = unpackUnorm4x8 (in_pack.x);
+    in1 = unpackUnorm4x8 (in_pack.y);
+
+    gs_idx = (gs_id.y >= (gaussscale_img_height / 2u - 1u)) ? gs_idx : gs_idx + gaussscale_img_width;
+    gs0 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx]);
+    gs1 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == gaussscale_img_width - 1u) ? gs0.zwzw : gs1;
+
+    inter = (gs0 + vec4 (gs0.zw, gs1.xy)) * 0.5f;
+    vec4 inter10 = (inter00 + vec4 (gs0.xy, inter.xy)) * 0.5f;
+    vec4 inter11 = (inter01 + vec4 (gs0.zw, inter.zw)) * 0.5f;
+
+    lap0 = (in0 - inter10) * 0.5f + norm_half_gl;
+    lap1 = (in1 - inter11) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    out_idx += merge_width;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+}
diff --git a/shaders/glsl/shader_reconstruct_pyr.comp.sl b/shaders/glsl/shader_reconstruct_pyr.comp.sl
new file mode 100644
index 0000000..d5537b9
--- /dev/null
+++ b/shaders/glsl/shader_reconstruct_pyr.comp.sl
@@ -0,0 +1,219 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer Lap0BufY {
+    uvec2 data[];
+} lap0_buf_y;
+
+layout (binding = 1) readonly buffer Lap0BufUV {
+    uvec2 data[];
+} lap0_buf_uv;
+
+layout (binding = 2) readonly buffer Lap1BufY {
+    uvec2 data[];
+} lap1_buf_y;
+
+layout (binding = 3) readonly buffer Lap1BufUV {
+    uvec2 data[];
+} lap1_buf_uv;
+
+layout (binding = 4) writeonly buffer OutBufY {
+    uvec2 data[];
+} out_buf_y;
+
+layout (binding = 5) writeonly buffer OutBufUV {
+    uvec2 data[];
+} out_buf_uv;
+
+layout (binding = 6) readonly buffer PrevBlendBufY {
+    uint data[];
+} prev_blend_y;
+
+layout (binding = 7) readonly buffer PrevBlendBufUV {
+    uint data[];
+} prev_blend_uv;
+
+layout (binding = 8) readonly buffer MaskBuf {
+    uvec2 data[];
+} mask_buf;
+
+uniform uint lap_img_width;
+uniform uint lap_img_height;
+
+uniform uint out_img_width;
+uniform uint out_offset_x;
+
+uniform uint prev_blend_img_width;
+uniform uint prev_blend_img_height;
+
+// normalization of gray level
+const float norm_gl = 256.0f / 255.0f;
+
+void reconstruct_y (uvec2 y_id, uvec2 blend_id);
+void reconstruct_uv (uvec2 uv_id, uvec2 blend_id);
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+
+    uvec2 y_id = uvec2 (g_id.x, g_id.y * 4u);
+    y_id.x = clamp (y_id.x, 0u, lap_img_width - 1u);
+
+    uvec2 blend_id = uvec2 (g_id.x, g_id.y * 2u);
+    blend_id.x = clamp (blend_id.x, 0u, prev_blend_img_width - 1u);
+    reconstruct_y (y_id, blend_id);
+
+    y_id.y += 2u;
+    blend_id.y += 1u;
+    reconstruct_y (y_id, blend_id);
+
+    uvec2 uv_id = uvec2 (g_id.x, g_id.y * 2u);
+    uv_id.x = clamp (uv_id.x, 0u, lap_img_width - 1u);
+    blend_id = g_id;
+    blend_id.x = clamp (blend_id.x, 0u, prev_blend_img_width - 1u);
+    reconstruct_uv (uv_id, blend_id);
+}
+
+void reconstruct_y (uvec2 y_id, uvec2 blend_id)
+{
+    y_id.y = clamp (y_id.y, 0u, lap_img_height - 1u);
+    blend_id.y = clamp (blend_id.y, 0u, prev_blend_img_height - 1u);
+
+    uvec2 mask = mask_buf.data[y_id.x];
+    vec4 mask0 = unpackUnorm4x8 (mask.x);
+    vec4 mask1 = unpackUnorm4x8 (mask.y);
+
+    uint idx = y_id.y * lap_img_width + y_id.x;
+    uvec2 lap = lap0_buf_y.data[idx];
+    vec4 lap00 = unpackUnorm4x8 (lap.x);
+    vec4 lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_y.data[idx];
+    vec4 lap10 = unpackUnorm4x8 (lap.x);
+    vec4 lap11 = unpackUnorm4x8 (lap.y);
+
+    vec4 lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    vec4 lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    uint prev_blend_idx = blend_id.y * prev_blend_img_width + blend_id.x;
+    vec4 prev_blend0 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx]);
+    vec4 prev_blend1 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prev_blend_img_width - 1u) ? prev_blend0.wwww : prev_blend1;
+
+    vec4 inter = (prev_blend0 + vec4 (prev_blend0.yzw, prev_blend1.x)) * 0.5f;
+    vec4 prev_blend_inter00 = vec4 (prev_blend0.x, inter.x, prev_blend0.y, inter.y);
+    vec4 prev_blend_inter01 = vec4 (prev_blend0.z, inter.z, prev_blend0.w, inter.w);
+
+    vec4 out0 = prev_blend_inter00 + lap_blend0 * 2.0f - norm_gl;
+    vec4 out1 = prev_blend_inter01 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    uint out_idx = y_id.y * out_img_width + out_offset_x + y_id.x;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+
+    idx = (y_id.y >= lap_img_height - 1u) ? idx : idx + lap_img_width;
+    lap = lap0_buf_y.data[idx];
+    lap00 = unpackUnorm4x8 (lap.x);
+    lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_y.data[idx];
+    lap10 = unpackUnorm4x8 (lap.x);
+    lap11 = unpackUnorm4x8 (lap.y);
+
+    lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    prev_blend_idx = (blend_id.y >= prev_blend_img_height - 1u) ? prev_blend_idx : prev_blend_idx + prev_blend_img_width;
+    prev_blend0 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx]);
+    prev_blend1 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prev_blend_img_width - 1u) ? prev_blend0.wwww : prev_blend1;
+
+    inter = (prev_blend0 + vec4 (prev_blend0.yzw, prev_blend1.x)) * 0.5f;
+    vec4 prev_blend_inter10 = vec4 (prev_blend0.x, inter.x, prev_blend0.y, inter.y);
+    vec4 prev_blend_inter11 = vec4 (prev_blend0.z, inter.z, prev_blend0.w, inter.w);
+    prev_blend_inter10 = (prev_blend_inter00 + prev_blend_inter10) * 0.5f;
+    prev_blend_inter11 = (prev_blend_inter01 + prev_blend_inter11) * 0.5f;
+
+    out0 = prev_blend_inter10 + lap_blend0 * 2.0f - norm_gl;
+    out1 = prev_blend_inter11 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    out_idx += out_img_width;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+}
+
+void reconstruct_uv (uvec2 uv_id, uvec2 blend_id)
+{
+    uv_id.y = clamp (uv_id.y, 0u, lap_img_height / 2u - 1u);
+    blend_id.y = clamp (blend_id.y, 0u, prev_blend_img_height / 2u - 1u);
+
+    uvec2 mask = mask_buf.data[uv_id.x];
+    vec4 mask0 = unpackUnorm4x8 (mask.x);
+    vec4 mask1 = unpackUnorm4x8 (mask.y);
+
+    uint idx = uv_id.y * lap_img_width + uv_id.x;
+    uvec2 lap = lap0_buf_uv.data[idx];
+    vec4 lap00 = unpackUnorm4x8 (lap.x);
+    vec4 lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_uv.data[idx];
+    vec4 lap10 = unpackUnorm4x8 (lap.x);
+    vec4 lap11 = unpackUnorm4x8 (lap.y);
+
+    mask0.yw = mask0.xz;
+    mask1.yw = mask1.xz;
+    vec4 lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    vec4 lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    uint prev_blend_idx = blend_id.y * prev_blend_img_width + blend_id.x;
+    vec4 prev_blend0 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx]);
+    vec4 prev_blend1 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prev_blend_img_width - 1u) ? prev_blend0.zwzw : prev_blend1;
+
+    vec4 inter = (prev_blend0 + vec4 (prev_blend0.zw, prev_blend1.xy)) * 0.5f;
+    vec4 prev_blend_inter00 = vec4 (prev_blend0.xy, inter.xy);
+    vec4 prev_blend_inter01 = vec4 (prev_blend0.zw, inter.zw);
+
+    vec4 out0 = prev_blend_inter00 + lap_blend0 * 2.0f - norm_gl;
+    vec4 out1 = prev_blend_inter01 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    uint out_idx = uv_id.y * out_img_width + out_offset_x + uv_id.x;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+
+    idx = (uv_id.y >= (lap_img_height / 2u - 1u)) ? idx : idx + lap_img_width;
+    lap = lap0_buf_uv.data[idx];
+    lap00 = unpackUnorm4x8 (lap.x);
+    lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_uv.data[idx];
+    lap10 = unpackUnorm4x8 (lap.x);
+    lap11 = unpackUnorm4x8 (lap.y);
+
+    lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    prev_blend_idx = (blend_id.y >= (prev_blend_img_height / 2u - 1u)) ?
+                     prev_blend_idx : prev_blend_idx + prev_blend_img_width;
+    prev_blend0 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx]);
+    prev_blend1 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prev_blend_img_width - 1u) ? prev_blend0.zwzw : prev_blend1;
+
+    inter = (prev_blend0 + vec4 (prev_blend0.zw, prev_blend1.xy)) * 0.5f;
+    vec4 prev_blend_inter10 = vec4 (prev_blend0.xy, inter.xy);
+    vec4 prev_blend_inter11 = vec4 (prev_blend0.zw, inter.zw);
+    prev_blend_inter10 = (prev_blend_inter00 + prev_blend_inter10) * 0.5f;
+    prev_blend_inter11 = (prev_blend_inter01 + prev_blend_inter11) * 0.5f;
+
+    out0 = prev_blend_inter10 + lap_blend0 * 2.0f - norm_gl;
+    out1 = prev_blend_inter11 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    out_idx += out_img_width;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+}
diff --git a/shaders/glslx/.gitignore b/shaders/glslx/.gitignore
new file mode 100644
index 0000000..c161cb9
--- /dev/null
+++ b/shaders/glslx/.gitignore
@@ -0,0 +1 @@
+*.slx
diff --git a/shaders/glslx/Makefile.am b/shaders/glslx/Makefile.am
new file mode 100644
index 0000000..9be760e
--- /dev/null
+++ b/shaders/glslx/Makefile.am
@@ -0,0 +1,20 @@
+glslx_sources = \
+    shader_copy.comp.slx            \
+    shader_geomap.comp.slx          \
+    shader_gauss_scale_pyr.comp.slx \
+    shader_lap_trans_pyr.comp.slx   \
+    shader_blend_pyr.comp.slx       \
+    shader_reconstruct_pyr.comp.slx \
+    $(NULL)
+
+add_quotation_marks_sh = \
+    $(top_srcdir)/tools/add-quotation-marks.sh
+
+glsl_dir = $(top_srcdir)/shaders/glsl
+
+all-local: $(glslx_sources)
+
+$(glslx_sources): %.slx: $(glsl_dir)/%.sl
+	@$(add_quotation_marks_sh) $< $@
+
+CLEANFILES = $(glslx_sources)
diff --git a/shaders/spv/shader_blend_pyr.comp b/shaders/spv/shader_blend_pyr.comp
new file mode 100644
index 0000000..77ff1a9
--- /dev/null
+++ b/shaders/spv/shader_blend_pyr.comp
@@ -0,0 +1,93 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer In0BufY {
+    uvec2 data[];
+} in0_buf_y;
+
+layout (binding = 1) readonly buffer In0BufUV {
+    uvec2 data[];
+} in0_buf_uv;
+
+layout (binding = 2) readonly buffer In1BufY {
+    uvec2 data[];
+} in1_buf_y;
+
+layout (binding = 3) readonly buffer In1BufUV {
+    uvec2 data[];
+} in1_buf_uv;
+
+layout (binding = 4) writeonly buffer OutBufY {
+    uvec2 data[];
+} out_buf_y;
+
+layout (binding = 5) writeonly buffer OutBufUV {
+    uvec2 data[];
+} out_buf_uv;
+
+layout (binding = 6) readonly buffer MaskBuf {
+    uvec2 data[];
+} mask_buf;
+
+layout (push_constant) uniform PushConsts {
+    uint in_img_width;
+} prop;
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+    g_id.x = clamp (g_id.x, 0u, prop.in_img_width - 1u);
+
+    uvec2 mask = mask_buf.data[g_id.x];
+    vec4 mask0 = unpackUnorm4x8 (mask.x);
+    vec4 mask1 = unpackUnorm4x8 (mask.y);
+
+    uint y_idx = g_id.y * 2u * prop.in_img_width + g_id.x;
+    uvec2 in0_y = in0_buf_y.data[y_idx];
+    vec4 in0_y0 = unpackUnorm4x8 (in0_y.x);
+    vec4 in0_y1 = unpackUnorm4x8 (in0_y.y);
+
+    uvec2 in1_y = in1_buf_y.data[y_idx];
+    vec4 in1_y0 = unpackUnorm4x8 (in1_y.x);
+    vec4 in1_y1 = unpackUnorm4x8 (in1_y.y);
+
+    vec4 out_y0 = (in0_y0 - in1_y0) * mask0 + in1_y0;
+    vec4 out_y1 = (in0_y1 - in1_y1) * mask1 + in1_y1;
+    out_y0 = clamp (out_y0, 0.0f, 1.0f);
+    out_y1 = clamp (out_y1, 0.0f, 1.0f);
+    out_buf_y.data[y_idx] = uvec2 (packUnorm4x8 (out_y0), packUnorm4x8 (out_y1));
+
+    y_idx += prop.in_img_width;
+    in0_y = in0_buf_y.data[y_idx];
+    in0_y0 = unpackUnorm4x8 (in0_y.x);
+    in0_y1 = unpackUnorm4x8 (in0_y.y);
+
+    in1_y = in1_buf_y.data[y_idx];
+    in1_y0 = unpackUnorm4x8 (in1_y.x);
+    in1_y1 = unpackUnorm4x8 (in1_y.y);
+
+    out_y0 = (in0_y0 - in1_y0) * mask0 + in1_y0;
+    out_y1 = (in0_y1 - in1_y1) * mask1 + in1_y1;
+    out_y0 = clamp (out_y0, 0.0f, 1.0f);
+    out_y1 = clamp (out_y1, 0.0f, 1.0f);
+    out_buf_y.data[y_idx] = uvec2 (packUnorm4x8 (out_y0), packUnorm4x8 (out_y1));
+
+    uint uv_idx = g_id.y * prop.in_img_width + g_id.x;
+    uvec2 in0_uv = in0_buf_uv.data[uv_idx];
+    vec4 in0_uv0 = unpackUnorm4x8 (in0_uv.x);
+    vec4 in0_uv1 = unpackUnorm4x8 (in0_uv.y);
+
+    uvec2 in1_uv = in1_buf_uv.data[uv_idx];
+    vec4 in1_uv0 = unpackUnorm4x8 (in1_uv.x);
+    vec4 in1_uv1 = unpackUnorm4x8 (in1_uv.y);
+
+    mask0.yw = mask0.xz;
+    mask1.yw = mask1.xz;
+    vec4 out_uv0 = (in0_uv0 - in1_uv0) * mask0 + in1_uv0;
+    vec4 out_uv1 = (in0_uv1 - in1_uv1) * mask1 + in1_uv1;
+
+    out_uv0 = clamp (out_uv0, 0.0f, 1.0f);
+    out_uv1 = clamp (out_uv1, 0.0f, 1.0f);
+    out_buf_uv.data[uv_idx] = uvec2 (packUnorm4x8 (out_uv0), packUnorm4x8 (out_uv1));
+}
diff --git a/shaders/spv/shader_blend_pyr.comp.spv b/shaders/spv/shader_blend_pyr.comp.spv
new file mode 100644
index 0000000..9f1d33a
--- /dev/null
+++ b/shaders/spv/shader_blend_pyr.comp.spv
@@ -0,0 +1,228 @@
+	// 7.8.2870
+	0x07230203,0x00010000,0x00080007,0x0000010e,0x00000000,0x00020011,0x00000001,0x0006000b,
+	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x00060010,0x00000004,
+	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000001,0x00000136,0x00040005,
+	0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000009,0x64695f67,0x00000000,0x00080005,
+	0x0000000c,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00050005,
+	0x00000013,0x68737550,0x736e6f43,0x00007374,0x00070006,0x00000013,0x00000000,0x695f6e69,
+	0x775f676d,0x68746469,0x00000000,0x00040005,0x00000015,0x706f7270,0x00000000,0x00040005,
+	0x0000001f,0x6b73616d,0x00000000,0x00040005,0x00000021,0x6b73614d,0x00667542,0x00050006,
+	0x00000021,0x00000000,0x61746164,0x00000000,0x00050005,0x00000023,0x6b73616d,0x6675625f,
+	0x00000000,0x00040005,0x0000002c,0x6b73616d,0x00000030,0x00040005,0x00000030,0x6b73616d,
+	0x00000031,0x00040005,0x00000034,0x64695f79,0x00000078,0x00040005,0x0000003f,0x5f306e69,
+	0x00000079,0x00040005,0x00000041,0x42306e49,0x00596675,0x00050006,0x00000041,0x00000000,
+	0x61746164,0x00000000,0x00050005,0x00000043,0x5f306e69,0x5f667562,0x00000079,0x00040005,
+	0x00000047,0x5f306e69,0x00003079,0x00040005,0x0000004b,0x5f306e69,0x00003179,0x00040005,
+	0x0000004f,0x5f316e69,0x00000079,0x00040005,0x00000051,0x42316e49,0x00596675,0x00050006,
+	0x00000051,0x00000000,0x61746164,0x00000000,0x00050005,0x00000053,0x5f316e69,0x5f667562,
+	0x00000079,0x00040005,0x00000057,0x5f316e69,0x00003079,0x00040005,0x0000005b,0x5f316e69,
+	0x00003179,0x00040005,0x0000005f,0x5f74756f,0x00003079,0x00040005,0x00000067,0x5f74756f,
+	0x00003179,0x00040005,0x0000007a,0x4274754f,0x00596675,0x00050006,0x0000007a,0x00000000,
+	0x61746164,0x00000000,0x00050005,0x0000007c,0x5f74756f,0x5f667562,0x00000079,0x00040005,
+	0x000000b7,0x695f7675,0x00007864,0x00040005,0x000000c0,0x5f306e69,0x00007675,0x00050005,
+	0x000000c2,0x42306e49,0x56556675,0x00000000,0x00050006,0x000000c2,0x00000000,0x61746164,
+	0x00000000,0x00050005,0x000000c4,0x5f306e69,0x5f667562,0x00007675,0x00040005,0x000000c8,
+	0x5f306e69,0x00307675,0x00040005,0x000000cc,0x5f306e69,0x00317675,0x00040005,0x000000d0,
+	0x5f316e69,0x00007675,0x00050005,0x000000d2,0x42316e49,0x56556675,0x00000000,0x00050006,
+	0x000000d2,0x00000000,0x61746164,0x00000000,0x00050005,0x000000d4,0x5f316e69,0x5f667562,
+	0x00007675,0x00040005,0x000000d8,0x5f316e69,0x00307675,0x00040005,0x000000dc,0x5f316e69,
+	0x00317675,0x00040005,0x000000e9,0x5f74756f,0x00307675,0x00040005,0x000000f1,0x5f74756f,
+	0x00317675,0x00050005,0x00000102,0x4274754f,0x56556675,0x00000000,0x00050006,0x00000102,
+	0x00000000,0x61746164,0x00000000,0x00050005,0x00000104,0x5f74756f,0x5f667562,0x00007675,
+	0x00040047,0x0000000c,0x0000000b,0x0000001c,0x00050048,0x00000013,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x00000013,0x00000002,0x00040047,0x00000020,0x00000006,0x00000008,
+	0x00040048,0x00000021,0x00000000,0x00000018,0x00050048,0x00000021,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x00000021,0x00000003,0x00040047,0x00000023,0x00000022,0x00000000,
+	0x00040047,0x00000023,0x00000021,0x00000006,0x00040047,0x00000040,0x00000006,0x00000008,
+	0x00040048,0x00000041,0x00000000,0x00000018,0x00050048,0x00000041,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x00000041,0x00000003,0x00040047,0x00000043,0x00000022,0x00000000,
+	0x00040047,0x00000043,0x00000021,0x00000000,0x00040047,0x00000050,0x00000006,0x00000008,
+	0x00040048,0x00000051,0x00000000,0x00000018,0x00050048,0x00000051,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x00000051,0x00000003,0x00040047,0x00000053,0x00000022,0x00000000,
+	0x00040047,0x00000053,0x00000021,0x00000002,0x00040047,0x00000079,0x00000006,0x00000008,
+	0x00040048,0x0000007a,0x00000000,0x00000019,0x00050048,0x0000007a,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x0000007a,0x00000003,0x00040047,0x0000007c,0x00000022,0x00000000,
+	0x00040047,0x0000007c,0x00000021,0x00000004,0x00040047,0x000000c1,0x00000006,0x00000008,
+	0x00040048,0x000000c2,0x00000000,0x00000018,0x00050048,0x000000c2,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x000000c2,0x00000003,0x00040047,0x000000c4,0x00000022,0x00000000,
+	0x00040047,0x000000c4,0x00000021,0x00000001,0x00040047,0x000000d1,0x00000006,0x00000008,
+	0x00040048,0x000000d2,0x00000000,0x00000018,0x00050048,0x000000d2,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x000000d2,0x00000003,0x00040047,0x000000d4,0x00000022,0x00000000,
+	0x00040047,0x000000d4,0x00000021,0x00000003,0x00040047,0x00000101,0x00000006,0x00000008,
+	0x00040048,0x00000102,0x00000000,0x00000019,0x00050048,0x00000102,0x00000000,0x00000023,
+	0x00000000,0x00030047,0x00000102,0x00000003,0x00040047,0x00000104,0x00000022,0x00000000,
+	0x00040047,0x00000104,0x00000021,0x00000005,0x00040047,0x0000010d,0x0000000b,0x00000019,
+	0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,
+	0x00000000,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,
+	0x00000007,0x00040017,0x0000000a,0x00000006,0x00000003,0x00040020,0x0000000b,0x00000001,
+	0x0000000a,0x0004003b,0x0000000b,0x0000000c,0x00000001,0x0004002b,0x00000006,0x0000000f,
+	0x00000000,0x00040020,0x00000010,0x00000007,0x00000006,0x0003001e,0x00000013,0x00000006,
+	0x00040020,0x00000014,0x00000009,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000009,
+	0x00040015,0x00000016,0x00000020,0x00000001,0x0004002b,0x00000016,0x00000017,0x00000000,
+	0x00040020,0x00000018,0x00000009,0x00000006,0x0004002b,0x00000006,0x0000001b,0x00000001,
+	0x0003001d,0x00000020,0x00000007,0x0003001e,0x00000021,0x00000020,0x00040020,0x00000022,
+	0x00000002,0x00000021,0x0004003b,0x00000022,0x00000023,0x00000002,0x00040020,0x00000026,
+	0x00000002,0x00000007,0x00030016,0x00000029,0x00000020,0x00040017,0x0000002a,0x00000029,
+	0x00000004,0x00040020,0x0000002b,0x00000007,0x0000002a,0x0004002b,0x00000006,0x00000037,
+	0x00000002,0x0003001d,0x00000040,0x00000007,0x0003001e,0x00000041,0x00000040,0x00040020,
+	0x00000042,0x00000002,0x00000041,0x0004003b,0x00000042,0x00000043,0x00000002,0x0003001d,
+	0x00000050,0x00000007,0x0003001e,0x00000051,0x00000050,0x00040020,0x00000052,0x00000002,
+	0x00000051,0x0004003b,0x00000052,0x00000053,0x00000002,0x0004002b,0x00000029,0x00000070,
+	0x00000000,0x0004002b,0x00000029,0x00000071,0x3f800000,0x0003001d,0x00000079,0x00000007,
+	0x0003001e,0x0000007a,0x00000079,0x00040020,0x0000007b,0x00000002,0x0000007a,0x0004003b,
+	0x0000007b,0x0000007c,0x00000002,0x0003001d,0x000000c1,0x00000007,0x0003001e,0x000000c2,
+	0x000000c1,0x00040020,0x000000c3,0x00000002,0x000000c2,0x0004003b,0x000000c3,0x000000c4,
+	0x00000002,0x0003001d,0x000000d1,0x00000007,0x0003001e,0x000000d2,0x000000d1,0x00040020,
+	0x000000d3,0x00000002,0x000000d2,0x0004003b,0x000000d3,0x000000d4,0x00000002,0x00040017,
+	0x000000e0,0x00000029,0x00000002,0x0003001d,0x00000101,0x00000007,0x0003001e,0x00000102,
+	0x00000101,0x00040020,0x00000103,0x00000002,0x00000102,0x0004003b,0x00000103,0x00000104,
+	0x00000002,0x0004002b,0x00000006,0x0000010c,0x00000008,0x0006002c,0x0000000a,0x0000010d,
+	0x0000010c,0x0000010c,0x0000001b,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,
+	0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000008,
+	0x0000001f,0x00000007,0x0004003b,0x0000002b,0x0000002c,0x00000007,0x0004003b,0x0000002b,
+	0x00000030,0x00000007,0x0004003b,0x00000010,0x00000034,0x00000007,0x0004003b,0x00000008,
+	0x0000003f,0x00000007,0x0004003b,0x0000002b,0x00000047,0x00000007,0x0004003b,0x0000002b,
+	0x0000004b,0x00000007,0x0004003b,0x00000008,0x0000004f,0x00000007,0x0004003b,0x0000002b,
+	0x00000057,0x00000007,0x0004003b,0x0000002b,0x0000005b,0x00000007,0x0004003b,0x0000002b,
+	0x0000005f,0x00000007,0x0004003b,0x0000002b,0x00000067,0x00000007,0x0004003b,0x00000010,
+	0x000000b7,0x00000007,0x0004003b,0x00000008,0x000000c0,0x00000007,0x0004003b,0x0000002b,
+	0x000000c8,0x00000007,0x0004003b,0x0000002b,0x000000cc,0x00000007,0x0004003b,0x00000008,
+	0x000000d0,0x00000007,0x0004003b,0x0000002b,0x000000d8,0x00000007,0x0004003b,0x0000002b,
+	0x000000dc,0x00000007,0x0004003b,0x0000002b,0x000000e9,0x00000007,0x0004003b,0x0000002b,
+	0x000000f1,0x00000007,0x0004003d,0x0000000a,0x0000000d,0x0000000c,0x0007004f,0x00000007,
+	0x0000000e,0x0000000d,0x0000000d,0x00000000,0x00000001,0x0003003e,0x00000009,0x0000000e,
+	0x00050041,0x00000010,0x00000011,0x00000009,0x0000000f,0x0004003d,0x00000006,0x00000012,
+	0x00000011,0x00050041,0x00000018,0x00000019,0x00000015,0x00000017,0x0004003d,0x00000006,
+	0x0000001a,0x00000019,0x00050082,0x00000006,0x0000001c,0x0000001a,0x0000001b,0x0008000c,
+	0x00000006,0x0000001d,0x00000001,0x0000002c,0x00000012,0x0000000f,0x0000001c,0x00050041,
+	0x00000010,0x0000001e,0x00000009,0x0000000f,0x0003003e,0x0000001e,0x0000001d,0x00050041,
+	0x00000010,0x00000024,0x00000009,0x0000000f,0x0004003d,0x00000006,0x00000025,0x00000024,
+	0x00060041,0x00000026,0x00000027,0x00000023,0x00000017,0x00000025,0x0004003d,0x00000007,
+	0x00000028,0x00000027,0x0003003e,0x0000001f,0x00000028,0x00050041,0x00000010,0x0000002d,
+	0x0000001f,0x0000000f,0x0004003d,0x00000006,0x0000002e,0x0000002d,0x0006000c,0x0000002a,
+	0x0000002f,0x00000001,0x00000040,0x0000002e,0x0003003e,0x0000002c,0x0000002f,0x00050041,
+	0x00000010,0x00000031,0x0000001f,0x0000001b,0x0004003d,0x00000006,0x00000032,0x00000031,
+	0x0006000c,0x0000002a,0x00000033,0x00000001,0x00000040,0x00000032,0x0003003e,0x00000030,
+	0x00000033,0x00050041,0x00000010,0x00000035,0x00000009,0x0000001b,0x0004003d,0x00000006,
+	0x00000036,0x00000035,0x00050084,0x00000006,0x00000038,0x00000036,0x00000037,0x00050041,
+	0x00000018,0x00000039,0x00000015,0x00000017,0x0004003d,0x00000006,0x0000003a,0x00000039,
+	0x00050084,0x00000006,0x0000003b,0x00000038,0x0000003a,0x00050041,0x00000010,0x0000003c,
+	0x00000009,0x0000000f,0x0004003d,0x00000006,0x0000003d,0x0000003c,0x00050080,0x00000006,
+	0x0000003e,0x0000003b,0x0000003d,0x0003003e,0x00000034,0x0000003e,0x0004003d,0x00000006,
+	0x00000044,0x00000034,0x00060041,0x00000026,0x00000045,0x00000043,0x00000017,0x00000044,
+	0x0004003d,0x00000007,0x00000046,0x00000045,0x0003003e,0x0000003f,0x00000046,0x00050041,
+	0x00000010,0x00000048,0x0000003f,0x0000000f,0x0004003d,0x00000006,0x00000049,0x00000048,
+	0x0006000c,0x0000002a,0x0000004a,0x00000001,0x00000040,0x00000049,0x0003003e,0x00000047,
+	0x0000004a,0x00050041,0x00000010,0x0000004c,0x0000003f,0x0000001b,0x0004003d,0x00000006,
+	0x0000004d,0x0000004c,0x0006000c,0x0000002a,0x0000004e,0x00000001,0x00000040,0x0000004d,
+	0x0003003e,0x0000004b,0x0000004e,0x0004003d,0x00000006,0x00000054,0x00000034,0x00060041,
+	0x00000026,0x00000055,0x00000053,0x00000017,0x00000054,0x0004003d,0x00000007,0x00000056,
+	0x00000055,0x0003003e,0x0000004f,0x00000056,0x00050041,0x00000010,0x00000058,0x0000004f,
+	0x0000000f,0x0004003d,0x00000006,0x00000059,0x00000058,0x0006000c,0x0000002a,0x0000005a,
+	0x00000001,0x00000040,0x00000059,0x0003003e,0x00000057,0x0000005a,0x00050041,0x00000010,
+	0x0000005c,0x0000004f,0x0000001b,0x0004003d,0x00000006,0x0000005d,0x0000005c,0x0006000c,
+	0x0000002a,0x0000005e,0x00000001,0x00000040,0x0000005d,0x0003003e,0x0000005b,0x0000005e,
+	0x0004003d,0x0000002a,0x00000060,0x00000047,0x0004003d,0x0000002a,0x00000061,0x00000057,
+	0x00050083,0x0000002a,0x00000062,0x00000060,0x00000061,0x0004003d,0x0000002a,0x00000063,
+	0x0000002c,0x00050085,0x0000002a,0x00000064,0x00000062,0x00000063,0x0004003d,0x0000002a,
+	0x00000065,0x00000057,0x00050081,0x0000002a,0x00000066,0x00000064,0x00000065,0x0003003e,
+	0x0000005f,0x00000066,0x0004003d,0x0000002a,0x00000068,0x0000004b,0x0004003d,0x0000002a,
+	0x00000069,0x0000005b,0x00050083,0x0000002a,0x0000006a,0x00000068,0x00000069,0x0004003d,
+	0x0000002a,0x0000006b,0x00000030,0x00050085,0x0000002a,0x0000006c,0x0000006a,0x0000006b,
+	0x0004003d,0x0000002a,0x0000006d,0x0000005b,0x00050081,0x0000002a,0x0000006e,0x0000006c,
+	0x0000006d,0x0003003e,0x00000067,0x0000006e,0x0004003d,0x0000002a,0x0000006f,0x0000005f,
+	0x00070050,0x0000002a,0x00000072,0x00000070,0x00000070,0x00000070,0x00000070,0x00070050,
+	0x0000002a,0x00000073,0x00000071,0x00000071,0x00000071,0x00000071,0x0008000c,0x0000002a,
+	0x00000074,0x00000001,0x0000002b,0x0000006f,0x00000072,0x00000073,0x0003003e,0x0000005f,
+	0x00000074,0x0004003d,0x0000002a,0x00000075,0x00000067,0x00070050,0x0000002a,0x00000076,
+	0x00000070,0x00000070,0x00000070,0x00000070,0x00070050,0x0000002a,0x00000077,0x00000071,
+	0x00000071,0x00000071,0x00000071,0x0008000c,0x0000002a,0x00000078,0x00000001,0x0000002b,
+	0x00000075,0x00000076,0x00000077,0x0003003e,0x00000067,0x00000078,0x0004003d,0x00000006,
+	0x0000007d,0x00000034,0x0004003d,0x0000002a,0x0000007e,0x0000005f,0x0006000c,0x00000006,
+	0x0000007f,0x00000001,0x00000037,0x0000007e,0x0004003d,0x0000002a,0x00000080,0x00000067,
+	0x0006000c,0x00000006,0x00000081,0x00000001,0x00000037,0x00000080,0x00050050,0x00000007,
+	0x00000082,0x0000007f,0x00000081,0x00060041,0x00000026,0x00000083,0x0000007c,0x00000017,
+	0x0000007d,0x0003003e,0x00000083,0x00000082,0x00050041,0x00000018,0x00000084,0x00000015,
+	0x00000017,0x0004003d,0x00000006,0x00000085,0x00000084,0x0004003d,0x00000006,0x00000086,
+	0x00000034,0x00050080,0x00000006,0x00000087,0x00000086,0x00000085,0x0003003e,0x00000034,
+	0x00000087,0x0004003d,0x00000006,0x00000088,0x00000034,0x00060041,0x00000026,0x00000089,
+	0x00000043,0x00000017,0x00000088,0x0004003d,0x00000007,0x0000008a,0x00000089,0x0003003e,
+	0x0000003f,0x0000008a,0x00050041,0x00000010,0x0000008b,0x0000003f,0x0000000f,0x0004003d,
+	0x00000006,0x0000008c,0x0000008b,0x0006000c,0x0000002a,0x0000008d,0x00000001,0x00000040,
+	0x0000008c,0x0003003e,0x00000047,0x0000008d,0x00050041,0x00000010,0x0000008e,0x0000003f,
+	0x0000001b,0x0004003d,0x00000006,0x0000008f,0x0000008e,0x0006000c,0x0000002a,0x00000090,
+	0x00000001,0x00000040,0x0000008f,0x0003003e,0x0000004b,0x00000090,0x0004003d,0x00000006,
+	0x00000091,0x00000034,0x00060041,0x00000026,0x00000092,0x00000053,0x00000017,0x00000091,
+	0x0004003d,0x00000007,0x00000093,0x00000092,0x0003003e,0x0000004f,0x00000093,0x00050041,
+	0x00000010,0x00000094,0x0000004f,0x0000000f,0x0004003d,0x00000006,0x00000095,0x00000094,
+	0x0006000c,0x0000002a,0x00000096,0x00000001,0x00000040,0x00000095,0x0003003e,0x00000057,
+	0x00000096,0x00050041,0x00000010,0x00000097,0x0000004f,0x0000001b,0x0004003d,0x00000006,
+	0x00000098,0x00000097,0x0006000c,0x0000002a,0x00000099,0x00000001,0x00000040,0x00000098,
+	0x0003003e,0x0000005b,0x00000099,0x0004003d,0x0000002a,0x0000009a,0x00000047,0x0004003d,
+	0x0000002a,0x0000009b,0x00000057,0x00050083,0x0000002a,0x0000009c,0x0000009a,0x0000009b,
+	0x0004003d,0x0000002a,0x0000009d,0x0000002c,0x00050085,0x0000002a,0x0000009e,0x0000009c,
+	0x0000009d,0x0004003d,0x0000002a,0x0000009f,0x00000057,0x00050081,0x0000002a,0x000000a0,
+	0x0000009e,0x0000009f,0x0003003e,0x0000005f,0x000000a0,0x0004003d,0x0000002a,0x000000a1,
+	0x0000004b,0x0004003d,0x0000002a,0x000000a2,0x0000005b,0x00050083,0x0000002a,0x000000a3,
+	0x000000a1,0x000000a2,0x0004003d,0x0000002a,0x000000a4,0x00000030,0x00050085,0x0000002a,
+	0x000000a5,0x000000a3,0x000000a4,0x0004003d,0x0000002a,0x000000a6,0x0000005b,0x00050081,
+	0x0000002a,0x000000a7,0x000000a5,0x000000a6,0x0003003e,0x00000067,0x000000a7,0x0004003d,
+	0x0000002a,0x000000a8,0x0000005f,0x00070050,0x0000002a,0x000000a9,0x00000070,0x00000070,
+	0x00000070,0x00000070,0x00070050,0x0000002a,0x000000aa,0x00000071,0x00000071,0x00000071,
+	0x00000071,0x0008000c,0x0000002a,0x000000ab,0x00000001,0x0000002b,0x000000a8,0x000000a9,
+	0x000000aa,0x0003003e,0x0000005f,0x000000ab,0x0004003d,0x0000002a,0x000000ac,0x00000067,
+	0x00070050,0x0000002a,0x000000ad,0x00000070,0x00000070,0x00000070,0x00000070,0x00070050,
+	0x0000002a,0x000000ae,0x00000071,0x00000071,0x00000071,0x00000071,0x0008000c,0x0000002a,
+	0x000000af,0x00000001,0x0000002b,0x000000ac,0x000000ad,0x000000ae,0x0003003e,0x00000067,
+	0x000000af,0x0004003d,0x00000006,0x000000b0,0x00000034,0x0004003d,0x0000002a,0x000000b1,
+	0x0000005f,0x0006000c,0x00000006,0x000000b2,0x00000001,0x00000037,0x000000b1,0x0004003d,
+	0x0000002a,0x000000b3,0x00000067,0x0006000c,0x00000006,0x000000b4,0x00000001,0x00000037,
+	0x000000b3,0x00050050,0x00000007,0x000000b5,0x000000b2,0x000000b4,0x00060041,0x00000026,
+	0x000000b6,0x0000007c,0x00000017,0x000000b0,0x0003003e,0x000000b6,0x000000b5,0x00050041,
+	0x00000010,0x000000b8,0x00000009,0x0000001b,0x0004003d,0x00000006,0x000000b9,0x000000b8,
+	0x00050041,0x00000018,0x000000ba,0x00000015,0x00000017,0x0004003d,0x00000006,0x000000bb,
+	0x000000ba,0x00050084,0x00000006,0x000000bc,0x000000b9,0x000000bb,0x00050041,0x00000010,
+	0x000000bd,0x00000009,0x0000000f,0x0004003d,0x00000006,0x000000be,0x000000bd,0x00050080,
+	0x00000006,0x000000bf,0x000000bc,0x000000be,0x0003003e,0x000000b7,0x000000bf,0x0004003d,
+	0x00000006,0x000000c5,0x000000b7,0x00060041,0x00000026,0x000000c6,0x000000c4,0x00000017,
+	0x000000c5,0x0004003d,0x00000007,0x000000c7,0x000000c6,0x0003003e,0x000000c0,0x000000c7,
+	0x00050041,0x00000010,0x000000c9,0x000000c0,0x0000000f,0x0004003d,0x00000006,0x000000ca,
+	0x000000c9,0x0006000c,0x0000002a,0x000000cb,0x00000001,0x00000040,0x000000ca,0x0003003e,
+	0x000000c8,0x000000cb,0x00050041,0x00000010,0x000000cd,0x000000c0,0x0000001b,0x0004003d,
+	0x00000006,0x000000ce,0x000000cd,0x0006000c,0x0000002a,0x000000cf,0x00000001,0x00000040,
+	0x000000ce,0x0003003e,0x000000cc,0x000000cf,0x0004003d,0x00000006,0x000000d5,0x000000b7,
+	0x00060041,0x00000026,0x000000d6,0x000000d4,0x00000017,0x000000d5,0x0004003d,0x00000007,
+	0x000000d7,0x000000d6,0x0003003e,0x000000d0,0x000000d7,0x00050041,0x00000010,0x000000d9,
+	0x000000d0,0x0000000f,0x0004003d,0x00000006,0x000000da,0x000000d9,0x0006000c,0x0000002a,
+	0x000000db,0x00000001,0x00000040,0x000000da,0x0003003e,0x000000d8,0x000000db,0x00050041,
+	0x00000010,0x000000dd,0x000000d0,0x0000001b,0x0004003d,0x00000006,0x000000de,0x000000dd,
+	0x0006000c,0x0000002a,0x000000df,0x00000001,0x00000040,0x000000de,0x0003003e,0x000000dc,
+	0x000000df,0x0004003d,0x0000002a,0x000000e1,0x0000002c,0x0007004f,0x000000e0,0x000000e2,
+	0x000000e1,0x000000e1,0x00000000,0x00000002,0x0004003d,0x0000002a,0x000000e3,0x0000002c,
+	0x0009004f,0x0000002a,0x000000e4,0x000000e3,0x000000e2,0x00000000,0x00000004,0x00000002,
+	0x00000005,0x0003003e,0x0000002c,0x000000e4,0x0004003d,0x0000002a,0x000000e5,0x00000030,
+	0x0007004f,0x000000e0,0x000000e6,0x000000e5,0x000000e5,0x00000000,0x00000002,0x0004003d,
+	0x0000002a,0x000000e7,0x00000030,0x0009004f,0x0000002a,0x000000e8,0x000000e7,0x000000e6,
+	0x00000000,0x00000004,0x00000002,0x00000005,0x0003003e,0x00000030,0x000000e8,0x0004003d,
+	0x0000002a,0x000000ea,0x000000c8,0x0004003d,0x0000002a,0x000000eb,0x000000d8,0x00050083,
+	0x0000002a,0x000000ec,0x000000ea,0x000000eb,0x0004003d,0x0000002a,0x000000ed,0x0000002c,
+	0x00050085,0x0000002a,0x000000ee,0x000000ec,0x000000ed,0x0004003d,0x0000002a,0x000000ef,
+	0x000000d8,0x00050081,0x0000002a,0x000000f0,0x000000ee,0x000000ef,0x0003003e,0x000000e9,
+	0x000000f0,0x0004003d,0x0000002a,0x000000f2,0x000000cc,0x0004003d,0x0000002a,0x000000f3,
+	0x000000dc,0x00050083,0x0000002a,0x000000f4,0x000000f2,0x000000f3,0x0004003d,0x0000002a,
+	0x000000f5,0x00000030,0x00050085,0x0000002a,0x000000f6,0x000000f4,0x000000f5,0x0004003d,
+	0x0000002a,0x000000f7,0x000000dc,0x00050081,0x0000002a,0x000000f8,0x000000f6,0x000000f7,
+	0x0003003e,0x000000f1,0x000000f8,0x0004003d,0x0000002a,0x000000f9,0x000000e9,0x00070050,
+	0x0000002a,0x000000fa,0x00000070,0x00000070,0x00000070,0x00000070,0x00070050,0x0000002a,
+	0x000000fb,0x00000071,0x00000071,0x00000071,0x00000071,0x0008000c,0x0000002a,0x000000fc,
+	0x00000001,0x0000002b,0x000000f9,0x000000fa,0x000000fb,0x0003003e,0x000000e9,0x000000fc,
+	0x0004003d,0x0000002a,0x000000fd,0x000000f1,0x00070050,0x0000002a,0x000000fe,0x00000070,
+	0x00000070,0x00000070,0x00000070,0x00070050,0x0000002a,0x000000ff,0x00000071,0x00000071,
+	0x00000071,0x00000071,0x0008000c,0x0000002a,0x00000100,0x00000001,0x0000002b,0x000000fd,
+	0x000000fe,0x000000ff,0x0003003e,0x000000f1,0x00000100,0x0004003d,0x00000006,0x00000105,
+	0x000000b7,0x0004003d,0x0000002a,0x00000106,0x000000e9,0x0006000c,0x00000006,0x00000107,
+	0x00000001,0x00000037,0x00000106,0x0004003d,0x0000002a,0x00000108,0x000000f1,0x0006000c,
+	0x00000006,0x00000109,0x00000001,0x00000037,0x00000108,0x00050050,0x00000007,0x0000010a,
+	0x00000107,0x00000109,0x00060041,0x00000026,0x0000010b,0x00000104,0x00000017,0x00000105,
+	0x0003003e,0x0000010b,0x0000010a,0x000100fd,0x00010038
diff --git a/shaders/spv/shader_copy.comp b/shaders/spv/shader_copy.comp
new file mode 100644
index 0000000..876bdf7
--- /dev/null
+++ b/shaders/spv/shader_copy.comp
@@ -0,0 +1,28 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBuf {
+    uvec4 data[];
+} in_buf;
+
+layout (binding = 1) writeonly buffer OutBuf {
+    uvec4 data[];
+} out_buf;
+
+layout (push_constant) uniform PushConsts {
+    uint in_img_width;
+    uint in_x_offset;
+    uint out_img_width;
+    uint out_x_offset;
+    uint copy_width;
+} prop;
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+    g_id.x = min (g_id.x, prop.copy_width - 1u);
+
+    out_buf.data[g_id.y * prop.out_img_width + prop.out_x_offset + g_id.x] =
+        in_buf.data[g_id.y * prop.in_img_width + prop.in_x_offset + g_id.x];
+}
diff --git a/shaders/spv/shader_copy.comp.spv b/shaders/spv/shader_copy.comp.spv
new file mode 100644
index 0000000..240daab
--- /dev/null
+++ b/shaders/spv/shader_copy.comp.spv
@@ -0,0 +1,66 @@
+	// 7.8.2870
+	0x07230203,0x00010000,0x00080007,0x00000048,0x00000000,0x00020011,0x00000001,0x0006000b,
+	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000c,0x00060010,0x00000004,
+	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000001,0x00000136,0x00040005,
+	0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000009,0x64695f67,0x00000000,0x00080005,
+	0x0000000c,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00050005,
+	0x00000013,0x68737550,0x736e6f43,0x00007374,0x00070006,0x00000013,0x00000000,0x695f6e69,
+	0x775f676d,0x68746469,0x00000000,0x00060006,0x00000013,0x00000001,0x785f6e69,0x66666f5f,
+	0x00746573,0x00070006,0x00000013,0x00000002,0x5f74756f,0x5f676d69,0x74646977,0x00000068,
+	0x00070006,0x00000013,0x00000003,0x5f74756f,0x666f5f78,0x74657366,0x00000000,0x00060006,
+	0x00000013,0x00000004,0x79706f63,0x6469775f,0x00006874,0x00040005,0x00000015,0x706f7270,
+	0x00000000,0x00040005,0x00000021,0x4274754f,0x00006675,0x00050006,0x00000021,0x00000000,
+	0x61746164,0x00000000,0x00040005,0x00000023,0x5f74756f,0x00667562,0x00040005,0x00000033,
+	0x75426e49,0x00000066,0x00050006,0x00000033,0x00000000,0x61746164,0x00000000,0x00040005,
+	0x00000035,0x625f6e69,0x00006675,0x00040047,0x0000000c,0x0000000b,0x0000001c,0x00050048,
+	0x00000013,0x00000000,0x00000023,0x00000000,0x00050048,0x00000013,0x00000001,0x00000023,
+	0x00000004,0x00050048,0x00000013,0x00000002,0x00000023,0x00000008,0x00050048,0x00000013,
+	0x00000003,0x00000023,0x0000000c,0x00050048,0x00000013,0x00000004,0x00000023,0x00000010,
+	0x00030047,0x00000013,0x00000002,0x00040047,0x00000020,0x00000006,0x00000010,0x00040048,
+	0x00000021,0x00000000,0x00000019,0x00050048,0x00000021,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x00000021,0x00000003,0x00040047,0x00000023,0x00000022,0x00000000,0x00040047,
+	0x00000023,0x00000021,0x00000001,0x00040047,0x00000032,0x00000006,0x00000010,0x00040048,
+	0x00000033,0x00000000,0x00000018,0x00050048,0x00000033,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x00000033,0x00000003,0x00040047,0x00000035,0x00000022,0x00000000,0x00040047,
+	0x00000035,0x00000021,0x00000000,0x00040047,0x00000047,0x0000000b,0x00000019,0x00020013,
+	0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,
+	0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,
+	0x00040017,0x0000000a,0x00000006,0x00000003,0x00040020,0x0000000b,0x00000001,0x0000000a,
+	0x0004003b,0x0000000b,0x0000000c,0x00000001,0x0004002b,0x00000006,0x0000000f,0x00000000,
+	0x00040020,0x00000010,0x00000007,0x00000006,0x0007001e,0x00000013,0x00000006,0x00000006,
+	0x00000006,0x00000006,0x00000006,0x00040020,0x00000014,0x00000009,0x00000013,0x0004003b,
+	0x00000014,0x00000015,0x00000009,0x00040015,0x00000016,0x00000020,0x00000001,0x0004002b,
+	0x00000016,0x00000017,0x00000004,0x00040020,0x00000018,0x00000009,0x00000006,0x0004002b,
+	0x00000006,0x0000001b,0x00000001,0x00040017,0x0000001f,0x00000006,0x00000004,0x0003001d,
+	0x00000020,0x0000001f,0x0003001e,0x00000021,0x00000020,0x00040020,0x00000022,0x00000002,
+	0x00000021,0x0004003b,0x00000022,0x00000023,0x00000002,0x0004002b,0x00000016,0x00000024,
+	0x00000000,0x0004002b,0x00000016,0x00000027,0x00000002,0x0004002b,0x00000016,0x0000002b,
+	0x00000003,0x0003001d,0x00000032,0x0000001f,0x0003001e,0x00000033,0x00000032,0x00040020,
+	0x00000034,0x00000002,0x00000033,0x0004003b,0x00000034,0x00000035,0x00000002,0x0004002b,
+	0x00000016,0x0000003b,0x00000001,0x00040020,0x00000042,0x00000002,0x0000001f,0x0004002b,
+	0x00000006,0x00000046,0x00000008,0x0006002c,0x0000000a,0x00000047,0x00000046,0x00000046,
+	0x0000001b,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,
+	0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003d,0x0000000a,0x0000000d,0x0000000c,
+	0x0007004f,0x00000007,0x0000000e,0x0000000d,0x0000000d,0x00000000,0x00000001,0x0003003e,
+	0x00000009,0x0000000e,0x00050041,0x00000010,0x00000011,0x00000009,0x0000000f,0x0004003d,
+	0x00000006,0x00000012,0x00000011,0x00050041,0x00000018,0x00000019,0x00000015,0x00000017,
+	0x0004003d,0x00000006,0x0000001a,0x00000019,0x00050082,0x00000006,0x0000001c,0x0000001a,
+	0x0000001b,0x0007000c,0x00000006,0x0000001d,0x00000001,0x00000026,0x00000012,0x0000001c,
+	0x00050041,0x00000010,0x0000001e,0x00000009,0x0000000f,0x0003003e,0x0000001e,0x0000001d,
+	0x00050041,0x00000010,0x00000025,0x00000009,0x0000001b,0x0004003d,0x00000006,0x00000026,
+	0x00000025,0x00050041,0x00000018,0x00000028,0x00000015,0x00000027,0x0004003d,0x00000006,
+	0x00000029,0x00000028,0x00050084,0x00000006,0x0000002a,0x00000026,0x00000029,0x00050041,
+	0x00000018,0x0000002c,0x00000015,0x0000002b,0x0004003d,0x00000006,0x0000002d,0x0000002c,
+	0x00050080,0x00000006,0x0000002e,0x0000002a,0x0000002d,0x00050041,0x00000010,0x0000002f,
+	0x00000009,0x0000000f,0x0004003d,0x00000006,0x00000030,0x0000002f,0x00050080,0x00000006,
+	0x00000031,0x0000002e,0x00000030,0x00050041,0x00000010,0x00000036,0x00000009,0x0000001b,
+	0x0004003d,0x00000006,0x00000037,0x00000036,0x00050041,0x00000018,0x00000038,0x00000015,
+	0x00000024,0x0004003d,0x00000006,0x00000039,0x00000038,0x00050084,0x00000006,0x0000003a,
+	0x00000037,0x00000039,0x00050041,0x00000018,0x0000003c,0x00000015,0x0000003b,0x0004003d,
+	0x00000006,0x0000003d,0x0000003c,0x00050080,0x00000006,0x0000003e,0x0000003a,0x0000003d,
+	0x00050041,0x00000010,0x0000003f,0x00000009,0x0000000f,0x0004003d,0x00000006,0x00000040,
+	0x0000003f,0x00050080,0x00000006,0x00000041,0x0000003e,0x00000040,0x00060041,0x00000042,
+	0x00000043,0x00000035,0x00000024,0x00000041,0x0004003d,0x0000001f,0x00000044,0x00000043,
+	0x00060041,0x00000042,0x00000045,0x00000023,0x00000024,0x00000031,0x0003003e,0x00000045,
+	0x00000044,0x000100fd,0x00010038
diff --git a/shaders/spv/shader_gauss_scale_pyr.comp b/shaders/spv/shader_gauss_scale_pyr.comp
new file mode 100644
index 0000000..fa9f49d
--- /dev/null
+++ b/shaders/spv/shader_gauss_scale_pyr.comp
@@ -0,0 +1,176 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBufY {
+    uint data[];
+} in_buf_y;
+
+layout (binding = 1) readonly buffer InBufUV {
+    uint data[];
+} in_buf_uv;
+
+layout (binding = 2) writeonly buffer OutBufY {
+    uint data[];
+} out_buf_y;
+
+layout (binding = 3) writeonly buffer OutBufUV {
+    uint data[];
+} out_buf_uv;
+
+layout (push_constant) uniform PushConsts {
+    uint in_img_width;
+    uint in_img_height;
+    uint in_offset_x;
+    uint out_img_width;
+    uint out_img_height;
+    uint merge_width;
+} prop;
+
+const float coeffs[5] = float[] (0.152f, 0.222f, 0.252f, 0.222f, 0.152f);
+
+#define unpack_unorm(buf, pixel, idx) \
+    { \
+        pixel[0] = unpackUnorm4x8 (buf.data[idx]); \
+        pixel[1] = unpackUnorm4x8 (buf.data[idx + 1u]); \
+        pixel[2] = unpackUnorm4x8 (buf.data[idx + 2u]); \
+        pixel[3] = unpackUnorm4x8 (buf.data[idx + 3u]); \
+    }
+
+#define multiply_coeff(sum, pixel, idx) \
+    { \
+        sum[0] += pixel[0] * coeffs[idx]; \
+        sum[1] += pixel[1] * coeffs[idx]; \
+        sum[2] += pixel[2] * coeffs[idx]; \
+        sum[3] += pixel[3] * coeffs[idx]; \
+    }
+
+void gauss_scale_y (uvec2 y_id, uvec2 g_id);
+void gauss_scale_uv (uvec2 uv_id);
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+    g_id.x = clamp (g_id.x, 0u, prop.merge_width - 1u);
+
+    uvec2 y_id = g_id * uvec2 (1u, 2u);
+    gauss_scale_y (y_id, g_id);
+
+    gauss_scale_uv (g_id);
+}
+
+void gauss_scale_y (uvec2 y_id, uvec2 g_id)
+{
+    uvec2 in_id = y_id * 2u;
+    uvec2 gauss_start = in_id - uvec2 (1u, 2u);
+    gauss_start.y = clamp (gauss_start.y, 0u, prop.in_img_height - 7u);
+
+    vec4 sum0[4] = vec4[] (vec4 (0.0f), vec4 (0.0f), vec4 (0.0f), vec4 (0.0f));
+    vec4 sum1[4] = vec4[] (vec4 (0.0f), vec4 (0.0f), vec4 (0.0f), vec4 (0.0f));
+
+    vec4 pixel_y[4];
+    uint in_idx = (in_id.y == 0u) ? (in_id.x - 1u) : (gauss_start.y * prop.in_img_width + gauss_start.x);
+    in_idx += prop.in_offset_x;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 0u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + prop.in_img_width);
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 1u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + prop.in_img_width);
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 2u);
+    multiply_coeff (sum1, pixel_y, 0u);
+
+    in_idx += prop.in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 3u);
+    multiply_coeff (sum1, pixel_y, 1u);
+
+    in_idx += prop.in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum0, pixel_y, 4u);
+    multiply_coeff (sum1, pixel_y, 2u);
+
+    in_idx += prop.in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum1, pixel_y, 3u);
+
+    in_idx += prop.in_img_width;
+    unpack_unorm (in_buf_y, pixel_y, in_idx);
+    multiply_coeff (sum1, pixel_y, 4u);
+
+    sum0[0] = (in_id.x == 0u) ? vec4 (sum0[1].x) : sum0[0];
+    sum1[0] = (in_id.x == 0u) ? vec4 (sum1[1].x) : sum1[0];
+    sum0[3] = (in_id.x == prop.merge_width - 2u) ? vec4 (sum0[2].w) : sum0[3];
+    sum1[3] = (in_id.x == prop.merge_width - 2u) ? vec4 (sum1[2].w) : sum1[3];
+
+    vec4 out_data0 =
+        vec4 (sum0[0].z, sum0[1].x, sum0[1].z, sum0[2].x) * coeffs[0] +
+        vec4 (sum0[0].w, sum0[1].y, sum0[1].w, sum0[2].y) * coeffs[1] +
+        vec4 (sum0[1].x, sum0[1].z, sum0[2].x, sum0[2].z) * coeffs[2] +
+        vec4 (sum0[1].y, sum0[1].w, sum0[2].y, sum0[2].w) * coeffs[3] +
+        vec4 (sum0[1].z, sum0[2].x, sum0[2].z, sum0[3].x) * coeffs[4];
+
+    vec4 out_data1 =
+        vec4 (sum1[0].z, sum1[1].x, sum1[1].z, sum1[2].x) * coeffs[0] +
+        vec4 (sum1[0].w, sum1[1].y, sum1[1].w, sum1[2].y) * coeffs[1] +
+        vec4 (sum1[1].x, sum1[1].z, sum1[2].x, sum1[2].z) * coeffs[2] +
+        vec4 (sum1[1].y, sum1[1].w, sum1[2].y, sum1[2].w) * coeffs[3] +
+        vec4 (sum1[1].z, sum1[2].x, sum1[2].z, sum1[3].x) * coeffs[4];
+
+    out_data0 = clamp (out_data0, 0.0f, 1.0f);
+    out_data1 = clamp (out_data1, 0.0f, 1.0f);
+
+    y_id.x = clamp (y_id.x, 0u, prop.out_img_width - 1u);
+    y_id.y = clamp (y_id.y, 0u, prop.out_img_height - 2u);
+    uint out_idx = y_id.y * prop.out_img_width + y_id.x;
+    out_buf_y.data[out_idx] = packUnorm4x8 (out_data0);
+    out_buf_y.data[out_idx + prop.out_img_width] = packUnorm4x8 (out_data1);
+}
+
+void gauss_scale_uv (uvec2 uv_id)
+{
+    uvec2 in_id = uv_id * 2u;
+    uvec2 gauss_start = in_id - uvec2 (1u, 2u);
+    gauss_start.y = clamp (gauss_start.y, 0u, prop.in_img_height / 2u - 5u);
+
+    vec4 sum[4] = vec4[] (vec4 (0.0f), vec4 (0.0f), vec4 (0.0f), vec4 (0.0f));
+    uint in_idx = (in_id.y == 0u) ? (in_id.x - 1u) : (gauss_start.y * prop.in_img_width + gauss_start.x);
+    in_idx += prop.in_offset_x;
+
+    vec4 pixel_uv[4];
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 0u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + prop.in_img_width);
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 1u);
+
+    in_idx = (in_id.y == 0u) ? in_idx : (in_idx + prop.in_img_width);
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 2u);
+
+    in_idx += prop.in_img_width;
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 3u);
+
+    in_idx += prop.in_img_width;
+    unpack_unorm (in_buf_uv, pixel_uv, in_idx);
+    multiply_coeff (sum, pixel_uv, 4u);
+
+    sum[0] = (in_id.x == 0u) ? vec4 (sum[1]) : sum[0];
+    sum[3] = (in_id.x == prop.merge_width - 2u) ? vec4 (sum[2]) : sum[3];
+
+    vec4 out_data =
+        vec4 (sum[0].x, sum[0].y, sum[1].x, sum[1].y) * coeffs[0] +
+        vec4 (sum[0].z, sum[0].w, sum[1].z, sum[1].w) * coeffs[1] +
+        vec4 (sum[1].x, sum[1].y, sum[2].x, sum[2].y) * coeffs[2] +
+        vec4 (sum[1].z, sum[1].w, sum[2].z, sum[2].w) * coeffs[3] +
+        vec4 (sum[2].x, sum[2].y, sum[3].x, sum[3].y) * coeffs[4];
+
+    out_data = clamp (out_data, 0.0f, 1.0f);
+    uv_id.x = clamp (uv_id.x, 0u, prop.out_img_width - 1u);
+    out_buf_uv.data[uv_id.y * prop.out_img_width + uv_id.x] = packUnorm4x8 (out_data);
+}
diff --git a/shaders/spv/shader_gauss_scale_pyr.comp.spv b/shaders/spv/shader_gauss_scale_pyr.comp.spv
new file mode 100644
index 0000000..16235d3
--- /dev/null
+++ b/shaders/spv/shader_gauss_scale_pyr.comp.spv
@@ -0,0 +1,891 @@
+	// 7.8.2870
+	0x07230203,0x00010000,0x00080007,0x00000501,0x00000000,0x00020011,0x00000001,0x0006000b,
+	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x00000015,0x00060010,0x00000004,
+	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000001,0x00000136,0x00040005,
+	0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c,0x73756167,0x63735f73,0x5f656c61,
+	0x75762879,0x75763b32,0x00003b32,0x00040005,0x0000000a,0x64695f79,0x00000000,0x00040005,
+	0x0000000b,0x64695f67,0x00000000,0x00070005,0x00000010,0x73756167,0x63735f73,0x5f656c61,
+	0x76287675,0x003b3275,0x00040005,0x0000000f,0x695f7675,0x00000064,0x00040005,0x00000012,
+	0x64695f67,0x00000000,0x00080005,0x00000015,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,
+	0x496e6f69,0x00000044,0x00050005,0x0000001c,0x68737550,0x736e6f43,0x00007374,0x00070006,
+	0x0000001c,0x00000000,0x695f6e69,0x775f676d,0x68746469,0x00000000,0x00070006,0x0000001c,
+	0x00000001,0x695f6e69,0x685f676d,0x68676965,0x00000074,0x00060006,0x0000001c,0x00000002,
+	0x6f5f6e69,0x65736666,0x00785f74,0x00070006,0x0000001c,0x00000003,0x5f74756f,0x5f676d69,
+	0x74646977,0x00000068,0x00070006,0x0000001c,0x00000004,0x5f74756f,0x5f676d69,0x67696568,
+	0x00007468,0x00060006,0x0000001c,0x00000005,0x6772656d,0x69775f65,0x00687464,0x00040005,
+	0x0000001e,0x706f7270,0x00000000,0x00040005,0x00000028,0x64695f79,0x00000000,0x00040005,
+	0x0000002d,0x61726170,0x0000006d,0x00040005,0x0000002f,0x61726170,0x0000006d,0x00040005,
+	0x00000032,0x61726170,0x0000006d,0x00040005,0x00000035,0x695f6e69,0x00000064,0x00050005,
+	0x00000039,0x73756167,0x74735f73,0x00747261,0x00040005,0x0000004a,0x306d7573,0x00000000,
+	0x00040005,0x0000004e,0x316d7573,0x00000000,0x00040005,0x0000004f,0x695f6e69,0x00007864,
+	0x00040005,0x0000006a,0x65786970,0x00795f6c,0x00040005,0x0000006c,0x75426e49,0x00005966,
+	0x00050006,0x0000006c,0x00000000,0x61746164,0x00000000,0x00050005,0x0000006e,0x625f6e69,
+	0x795f6675,0x00000000,0x00050005,0x00000298,0x5f74756f,0x61746164,0x00000030,0x00050005,
+	0x000002cf,0x5f74756f,0x61746164,0x00000031,0x00040005,0x0000031e,0x5f74756f,0x00786469,
+	0x00040005,0x00000328,0x4274754f,0x00596675,0x00050006,0x00000328,0x00000000,0x61746164,
+	0x00000000,0x00050005,0x0000032a,0x5f74756f,0x5f667562,0x00000079,0x00040005,0x00000336,
+	0x695f6e69,0x00000064,0x00050005,0x0000033a,0x73756167,0x74735f73,0x00747261,0x00030005,
+	0x00000346,0x006d7573,0x00040005,0x00000347,0x695f6e69,0x00007864,0x00050005,0x0000035f,
+	0x65786970,0x76755f6c,0x00000000,0x00040005,0x00000361,0x75426e49,0x00565566,0x00050006,
+	0x00000361,0x00000000,0x61746164,0x00000000,0x00050005,0x00000363,0x625f6e69,0x755f6675,
+	0x00000076,0x00050005,0x000004ac,0x5f74756f,0x61746164,0x00000000,0x00050005,0x000004ef,
+	0x4274754f,0x56556675,0x00000000,0x00050006,0x000004ef,0x00000000,0x61746164,0x00000000,
+	0x00050005,0x000004f1,0x5f74756f,0x5f667562,0x00007675,0x00040047,0x00000015,0x0000000b,
+	0x0000001c,0x00050048,0x0000001c,0x00000000,0x00000023,0x00000000,0x00050048,0x0000001c,
+	0x00000001,0x00000023,0x00000004,0x00050048,0x0000001c,0x00000002,0x00000023,0x00000008,
+	0x00050048,0x0000001c,0x00000003,0x00000023,0x0000000c,0x00050048,0x0000001c,0x00000004,
+	0x00000023,0x00000010,0x00050048,0x0000001c,0x00000005,0x00000023,0x00000014,0x00030047,
+	0x0000001c,0x00000002,0x00040047,0x0000006b,0x00000006,0x00000004,0x00040048,0x0000006c,
+	0x00000000,0x00000018,0x00050048,0x0000006c,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x0000006c,0x00000003,0x00040047,0x0000006e,0x00000022,0x00000000,0x00040047,0x0000006e,
+	0x00000021,0x00000000,0x00040047,0x00000327,0x00000006,0x00000004,0x00040048,0x00000328,
+	0x00000000,0x00000019,0x00050048,0x00000328,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x00000328,0x00000003,0x00040047,0x0000032a,0x00000022,0x00000000,0x00040047,0x0000032a,
+	0x00000021,0x00000002,0x00040047,0x00000360,0x00000006,0x00000004,0x00040048,0x00000361,
+	0x00000000,0x00000018,0x00050048,0x00000361,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x00000361,0x00000003,0x00040047,0x00000363,0x00000022,0x00000000,0x00040047,0x00000363,
+	0x00000021,0x00000001,0x00040047,0x000004ee,0x00000006,0x00000004,0x00040048,0x000004ef,
+	0x00000000,0x00000019,0x00050048,0x000004ef,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x000004ef,0x00000003,0x00040047,0x000004f1,0x00000022,0x00000000,0x00040047,0x000004f1,
+	0x00000021,0x00000003,0x00040047,0x000004fe,0x0000000b,0x00000019,0x00020013,0x00000002,
+	0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,
+	0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00050021,
+	0x00000009,0x00000002,0x00000008,0x00000008,0x00040021,0x0000000e,0x00000002,0x00000008,
+	0x00040017,0x00000013,0x00000006,0x00000003,0x00040020,0x00000014,0x00000001,0x00000013,
+	0x0004003b,0x00000014,0x00000015,0x00000001,0x0004002b,0x00000006,0x00000018,0x00000000,
+	0x00040020,0x00000019,0x00000007,0x00000006,0x0008001e,0x0000001c,0x00000006,0x00000006,
+	0x00000006,0x00000006,0x00000006,0x00000006,0x00040020,0x0000001d,0x00000009,0x0000001c,
+	0x0004003b,0x0000001d,0x0000001e,0x00000009,0x00040015,0x0000001f,0x00000020,0x00000001,
+	0x0004002b,0x0000001f,0x00000020,0x00000005,0x00040020,0x00000021,0x00000009,0x00000006,
+	0x0004002b,0x00000006,0x00000024,0x00000001,0x0004002b,0x00000006,0x0000002a,0x00000002,
+	0x0005002c,0x00000007,0x0000002b,0x00000024,0x0000002a,0x0004002b,0x0000001f,0x0000003e,
+	0x00000001,0x0004002b,0x00000006,0x00000041,0x00000007,0x00030016,0x00000045,0x00000020,
+	0x00040017,0x00000046,0x00000045,0x00000004,0x0004002b,0x00000006,0x00000047,0x00000004,
+	0x0004001c,0x00000048,0x00000046,0x00000047,0x00040020,0x00000049,0x00000007,0x00000048,
+	0x0004002b,0x00000045,0x0000004b,0x00000000,0x0007002c,0x00000046,0x0000004c,0x0000004b,
+	0x0000004b,0x0000004b,0x0000004b,0x0007002c,0x00000048,0x0000004d,0x0000004c,0x0000004c,
+	0x0000004c,0x0000004c,0x00020014,0x00000052,0x0004002b,0x0000001f,0x0000005d,0x00000000,
+	0x0004002b,0x0000001f,0x00000065,0x00000002,0x0003001d,0x0000006b,0x00000006,0x0003001e,
+	0x0000006c,0x0000006b,0x00040020,0x0000006d,0x00000002,0x0000006c,0x0004003b,0x0000006d,
+	0x0000006e,0x00000002,0x00040020,0x00000070,0x00000002,0x00000006,0x00040020,0x00000074,
+	0x00000007,0x00000046,0x0004002b,0x0000001f,0x00000082,0x00000003,0x0004002b,0x00000006,
+	0x00000084,0x00000003,0x0004002b,0x00000045,0x0000008c,0x3e1ba5e3,0x0004002b,0x00000045,
+	0x000000cd,0x3e6353f8,0x0004002b,0x00000045,0x0000010e,0x3e810625,0x00040020,0x0000025f,
+	0x00000007,0x00000045,0x0004002b,0x00000045,0x00000307,0x3f800000,0x0004002b,0x0000001f,
+	0x00000318,0x00000004,0x0003001d,0x00000327,0x00000006,0x0003001e,0x00000328,0x00000327,
+	0x00040020,0x00000329,0x00000002,0x00000328,0x0004003b,0x00000329,0x0000032a,0x00000002,
+	0x0004002b,0x00000006,0x00000342,0x00000005,0x0003001d,0x00000360,0x00000006,0x0003001e,
+	0x00000361,0x00000360,0x00040020,0x00000362,0x00000002,0x00000361,0x0004003b,0x00000362,
+	0x00000363,0x00000002,0x0003001d,0x000004ee,0x00000006,0x0003001e,0x000004ef,0x000004ee,
+	0x00040020,0x000004f0,0x00000002,0x000004ef,0x0004003b,0x000004f0,0x000004f1,0x00000002,
+	0x0004002b,0x00000006,0x000004fd,0x00000008,0x0006002c,0x00000013,0x000004fe,0x000004fd,
+	0x000004fd,0x00000024,0x0004001c,0x000004ff,0x00000045,0x00000342,0x0008002c,0x000004ff,
+	0x00000500,0x0000008c,0x000000cd,0x0000010e,0x000000cd,0x0000008c,0x00050036,0x00000002,
+	0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000012,
+	0x00000007,0x0004003b,0x00000008,0x00000028,0x00000007,0x0004003b,0x00000008,0x0000002d,
+	0x00000007,0x0004003b,0x00000008,0x0000002f,0x00000007,0x0004003b,0x00000008,0x00000032,
+	0x00000007,0x0004003d,0x00000013,0x00000016,0x00000015,0x0007004f,0x00000007,0x00000017,
+	0x00000016,0x00000016,0x00000000,0x00000001,0x0003003e,0x00000012,0x00000017,0x00050041,
+	0x00000019,0x0000001a,0x00000012,0x00000018,0x0004003d,0x00000006,0x0000001b,0x0000001a,
+	0x00050041,0x00000021,0x00000022,0x0000001e,0x00000020,0x0004003d,0x00000006,0x00000023,
+	0x00000022,0x00050082,0x00000006,0x00000025,0x00000023,0x00000024,0x0008000c,0x00000006,
+	0x00000026,0x00000001,0x0000002c,0x0000001b,0x00000018,0x00000025,0x00050041,0x00000019,
+	0x00000027,0x00000012,0x00000018,0x0003003e,0x00000027,0x00000026,0x0004003d,0x00000007,
+	0x00000029,0x00000012,0x00050084,0x00000007,0x0000002c,0x00000029,0x0000002b,0x0003003e,
+	0x00000028,0x0000002c,0x0004003d,0x00000007,0x0000002e,0x00000028,0x0003003e,0x0000002d,
+	0x0000002e,0x0004003d,0x00000007,0x00000030,0x00000012,0x0003003e,0x0000002f,0x00000030,
+	0x00060039,0x00000002,0x00000031,0x0000000c,0x0000002d,0x0000002f,0x0004003d,0x00000007,
+	0x00000033,0x00000012,0x0003003e,0x00000032,0x00000033,0x00050039,0x00000002,0x00000034,
+	0x00000010,0x00000032,0x000100fd,0x00010038,0x00050036,0x00000002,0x0000000c,0x00000000,
+	0x00000009,0x00030037,0x00000008,0x0000000a,0x00030037,0x00000008,0x0000000b,0x000200f8,
+	0x0000000d,0x0004003b,0x00000008,0x00000035,0x00000007,0x0004003b,0x00000008,0x00000039,
+	0x00000007,0x0004003b,0x00000049,0x0000004a,0x00000007,0x0004003b,0x00000049,0x0000004e,
+	0x00000007,0x0004003b,0x00000019,0x0000004f,0x00000007,0x0004003b,0x00000019,0x00000054,
+	0x00000007,0x0004003b,0x00000049,0x0000006a,0x00000007,0x0004003b,0x00000019,0x000000aa,
+	0x00000007,0x0004003b,0x00000019,0x000000eb,0x00000007,0x0004003b,0x00000074,0x0000025c,
+	0x00000007,0x0004003b,0x00000074,0x0000026b,0x00000007,0x0004003b,0x00000074,0x0000027c,
+	0x00000007,0x0004003b,0x00000074,0x0000028d,0x00000007,0x0004003b,0x00000074,0x00000298,
+	0x00000007,0x0004003b,0x00000074,0x000002cf,0x00000007,0x0004003b,0x00000019,0x0000031e,
+	0x00000007,0x0004003d,0x00000007,0x00000036,0x0000000a,0x00050050,0x00000007,0x00000037,
+	0x0000002a,0x0000002a,0x00050084,0x00000007,0x00000038,0x00000036,0x00000037,0x0003003e,
+	0x00000035,0x00000038,0x0004003d,0x00000007,0x0000003a,0x00000035,0x00050082,0x00000007,
+	0x0000003b,0x0000003a,0x0000002b,0x0003003e,0x00000039,0x0000003b,0x00050041,0x00000019,
+	0x0000003c,0x00000039,0x00000024,0x0004003d,0x00000006,0x0000003d,0x0000003c,0x00050041,
+	0x00000021,0x0000003f,0x0000001e,0x0000003e,0x0004003d,0x00000006,0x00000040,0x0000003f,
+	0x00050082,0x00000006,0x00000042,0x00000040,0x00000041,0x0008000c,0x00000006,0x00000043,
+	0x00000001,0x0000002c,0x0000003d,0x00000018,0x00000042,0x00050041,0x00000019,0x00000044,
+	0x00000039,0x00000024,0x0003003e,0x00000044,0x00000043,0x0003003e,0x0000004a,0x0000004d,
+	0x0003003e,0x0000004e,0x0000004d,0x00050041,0x00000019,0x00000050,0x00000035,0x00000024,
+	0x0004003d,0x00000006,0x00000051,0x00000050,0x000500aa,0x00000052,0x00000053,0x00000051,
+	0x00000018,0x000300f7,0x00000056,0x00000000,0x000400fa,0x00000053,0x00000055,0x0000005a,
+	0x000200f8,0x00000055,0x00050041,0x00000019,0x00000057,0x00000035,0x00000018,0x0004003d,
+	0x00000006,0x00000058,0x00000057,0x00050082,0x00000006,0x00000059,0x00000058,0x00000024,
+	0x0003003e,0x00000054,0x00000059,0x000200f9,0x00000056,0x000200f8,0x0000005a,0x00050041,
+	0x00000019,0x0000005b,0x00000039,0x00000024,0x0004003d,0x00000006,0x0000005c,0x0000005b,
+	0x00050041,0x00000021,0x0000005e,0x0000001e,0x0000005d,0x0004003d,0x00000006,0x0000005f,
+	0x0000005e,0x00050084,0x00000006,0x00000060,0x0000005c,0x0000005f,0x00050041,0x00000019,
+	0x00000061,0x00000039,0x00000018,0x0004003d,0x00000006,0x00000062,0x00000061,0x00050080,
+	0x00000006,0x00000063,0x00000060,0x00000062,0x0003003e,0x00000054,0x00000063,0x000200f9,
+	0x00000056,0x000200f8,0x00000056,0x0004003d,0x00000006,0x00000064,0x00000054,0x0003003e,
+	0x0000004f,0x00000064,0x00050041,0x00000021,0x00000066,0x0000001e,0x00000065,0x0004003d,
+	0x00000006,0x00000067,0x00000066,0x0004003d,0x00000006,0x00000068,0x0000004f,0x00050080,
+	0x00000006,0x00000069,0x00000068,0x00000067,0x0003003e,0x0000004f,0x00000069,0x0004003d,
+	0x00000006,0x0000006f,0x0000004f,0x00060041,0x00000070,0x00000071,0x0000006e,0x0000005d,
+	0x0000006f,0x0004003d,0x00000006,0x00000072,0x00000071,0x0006000c,0x00000046,0x00000073,
+	0x00000001,0x00000040,0x00000072,0x00050041,0x00000074,0x00000075,0x0000006a,0x0000005d,
+	0x0003003e,0x00000075,0x00000073,0x0004003d,0x00000006,0x00000076,0x0000004f,0x00050080,
+	0x00000006,0x00000077,0x00000076,0x00000024,0x00060041,0x00000070,0x00000078,0x0000006e,
+	0x0000005d,0x00000077,0x0004003d,0x00000006,0x00000079,0x00000078,0x0006000c,0x00000046,
+	0x0000007a,0x00000001,0x00000040,0x00000079,0x00050041,0x00000074,0x0000007b,0x0000006a,
+	0x0000003e,0x0003003e,0x0000007b,0x0000007a,0x0004003d,0x00000006,0x0000007c,0x0000004f,
+	0x00050080,0x00000006,0x0000007d,0x0000007c,0x0000002a,0x00060041,0x00000070,0x0000007e,
+	0x0000006e,0x0000005d,0x0000007d,0x0004003d,0x00000006,0x0000007f,0x0000007e,0x0006000c,
+	0x00000046,0x00000080,0x00000001,0x00000040,0x0000007f,0x00050041,0x00000074,0x00000081,
+	0x0000006a,0x00000065,0x0003003e,0x00000081,0x00000080,0x0004003d,0x00000006,0x00000083,
+	0x0000004f,0x00050080,0x00000006,0x00000085,0x00000083,0x00000084,0x00060041,0x00000070,
+	0x00000086,0x0000006e,0x0000005d,0x00000085,0x0004003d,0x00000006,0x00000087,0x00000086,
+	0x0006000c,0x00000046,0x00000088,0x00000001,0x00000040,0x00000087,0x00050041,0x00000074,
+	0x00000089,0x0000006a,0x00000082,0x0003003e,0x00000089,0x00000088,0x00050041,0x00000074,
+	0x0000008a,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x0000008b,0x0000008a,0x0005008e,
+	0x00000046,0x0000008d,0x0000008b,0x0000008c,0x00050041,0x00000074,0x0000008e,0x0000004a,
+	0x0000005d,0x0004003d,0x00000046,0x0000008f,0x0000008e,0x00050081,0x00000046,0x00000090,
+	0x0000008f,0x0000008d,0x00050041,0x00000074,0x00000091,0x0000004a,0x0000005d,0x0003003e,
+	0x00000091,0x00000090,0x00050041,0x00000074,0x00000092,0x0000006a,0x0000003e,0x0004003d,
+	0x00000046,0x00000093,0x00000092,0x0005008e,0x00000046,0x00000094,0x00000093,0x0000008c,
+	0x00050041,0x00000074,0x00000095,0x0000004a,0x0000003e,0x0004003d,0x00000046,0x00000096,
+	0x00000095,0x00050081,0x00000046,0x00000097,0x00000096,0x00000094,0x00050041,0x00000074,
+	0x00000098,0x0000004a,0x0000003e,0x0003003e,0x00000098,0x00000097,0x00050041,0x00000074,
+	0x00000099,0x0000006a,0x00000065,0x0004003d,0x00000046,0x0000009a,0x00000099,0x0005008e,
+	0x00000046,0x0000009b,0x0000009a,0x0000008c,0x00050041,0x00000074,0x0000009c,0x0000004a,
+	0x00000065,0x0004003d,0x00000046,0x0000009d,0x0000009c,0x00050081,0x00000046,0x0000009e,
+	0x0000009d,0x0000009b,0x00050041,0x00000074,0x0000009f,0x0000004a,0x00000065,0x0003003e,
+	0x0000009f,0x0000009e,0x00050041,0x00000074,0x000000a0,0x0000006a,0x00000082,0x0004003d,
+	0x00000046,0x000000a1,0x000000a0,0x0005008e,0x00000046,0x000000a2,0x000000a1,0x0000008c,
+	0x00050041,0x00000074,0x000000a3,0x0000004a,0x00000082,0x0004003d,0x00000046,0x000000a4,
+	0x000000a3,0x00050081,0x00000046,0x000000a5,0x000000a4,0x000000a2,0x00050041,0x00000074,
+	0x000000a6,0x0000004a,0x00000082,0x0003003e,0x000000a6,0x000000a5,0x00050041,0x00000019,
+	0x000000a7,0x00000035,0x00000024,0x0004003d,0x00000006,0x000000a8,0x000000a7,0x000500aa,
+	0x00000052,0x000000a9,0x000000a8,0x00000018,0x000300f7,0x000000ac,0x00000000,0x000400fa,
+	0x000000a9,0x000000ab,0x000000ae,0x000200f8,0x000000ab,0x0004003d,0x00000006,0x000000ad,
+	0x0000004f,0x0003003e,0x000000aa,0x000000ad,0x000200f9,0x000000ac,0x000200f8,0x000000ae,
+	0x0004003d,0x00000006,0x000000af,0x0000004f,0x00050041,0x00000021,0x000000b0,0x0000001e,
+	0x0000005d,0x0004003d,0x00000006,0x000000b1,0x000000b0,0x00050080,0x00000006,0x000000b2,
+	0x000000af,0x000000b1,0x0003003e,0x000000aa,0x000000b2,0x000200f9,0x000000ac,0x000200f8,
+	0x000000ac,0x0004003d,0x00000006,0x000000b3,0x000000aa,0x0003003e,0x0000004f,0x000000b3,
+	0x0004003d,0x00000006,0x000000b4,0x0000004f,0x00060041,0x00000070,0x000000b5,0x0000006e,
+	0x0000005d,0x000000b4,0x0004003d,0x00000006,0x000000b6,0x000000b5,0x0006000c,0x00000046,
+	0x000000b7,0x00000001,0x00000040,0x000000b6,0x00050041,0x00000074,0x000000b8,0x0000006a,
+	0x0000005d,0x0003003e,0x000000b8,0x000000b7,0x0004003d,0x00000006,0x000000b9,0x0000004f,
+	0x00050080,0x00000006,0x000000ba,0x000000b9,0x00000024,0x00060041,0x00000070,0x000000bb,
+	0x0000006e,0x0000005d,0x000000ba,0x0004003d,0x00000006,0x000000bc,0x000000bb,0x0006000c,
+	0x00000046,0x000000bd,0x00000001,0x00000040,0x000000bc,0x00050041,0x00000074,0x000000be,
+	0x0000006a,0x0000003e,0x0003003e,0x000000be,0x000000bd,0x0004003d,0x00000006,0x000000bf,
+	0x0000004f,0x00050080,0x00000006,0x000000c0,0x000000bf,0x0000002a,0x00060041,0x00000070,
+	0x000000c1,0x0000006e,0x0000005d,0x000000c0,0x0004003d,0x00000006,0x000000c2,0x000000c1,
+	0x0006000c,0x00000046,0x000000c3,0x00000001,0x00000040,0x000000c2,0x00050041,0x00000074,
+	0x000000c4,0x0000006a,0x00000065,0x0003003e,0x000000c4,0x000000c3,0x0004003d,0x00000006,
+	0x000000c5,0x0000004f,0x00050080,0x00000006,0x000000c6,0x000000c5,0x00000084,0x00060041,
+	0x00000070,0x000000c7,0x0000006e,0x0000005d,0x000000c6,0x0004003d,0x00000006,0x000000c8,
+	0x000000c7,0x0006000c,0x00000046,0x000000c9,0x00000001,0x00000040,0x000000c8,0x00050041,
+	0x00000074,0x000000ca,0x0000006a,0x00000082,0x0003003e,0x000000ca,0x000000c9,0x00050041,
+	0x00000074,0x000000cb,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x000000cc,0x000000cb,
+	0x0005008e,0x00000046,0x000000ce,0x000000cc,0x000000cd,0x00050041,0x00000074,0x000000cf,
+	0x0000004a,0x0000005d,0x0004003d,0x00000046,0x000000d0,0x000000cf,0x00050081,0x00000046,
+	0x000000d1,0x000000d0,0x000000ce,0x00050041,0x00000074,0x000000d2,0x0000004a,0x0000005d,
+	0x0003003e,0x000000d2,0x000000d1,0x00050041,0x00000074,0x000000d3,0x0000006a,0x0000003e,
+	0x0004003d,0x00000046,0x000000d4,0x000000d3,0x0005008e,0x00000046,0x000000d5,0x000000d4,
+	0x000000cd,0x00050041,0x00000074,0x000000d6,0x0000004a,0x0000003e,0x0004003d,0x00000046,
+	0x000000d7,0x000000d6,0x00050081,0x00000046,0x000000d8,0x000000d7,0x000000d5,0x00050041,
+	0x00000074,0x000000d9,0x0000004a,0x0000003e,0x0003003e,0x000000d9,0x000000d8,0x00050041,
+	0x00000074,0x000000da,0x0000006a,0x00000065,0x0004003d,0x00000046,0x000000db,0x000000da,
+	0x0005008e,0x00000046,0x000000dc,0x000000db,0x000000cd,0x00050041,0x00000074,0x000000dd,
+	0x0000004a,0x00000065,0x0004003d,0x00000046,0x000000de,0x000000dd,0x00050081,0x00000046,
+	0x000000df,0x000000de,0x000000dc,0x00050041,0x00000074,0x000000e0,0x0000004a,0x00000065,
+	0x0003003e,0x000000e0,0x000000df,0x00050041,0x00000074,0x000000e1,0x0000006a,0x00000082,
+	0x0004003d,0x00000046,0x000000e2,0x000000e1,0x0005008e,0x00000046,0x000000e3,0x000000e2,
+	0x000000cd,0x00050041,0x00000074,0x000000e4,0x0000004a,0x00000082,0x0004003d,0x00000046,
+	0x000000e5,0x000000e4,0x00050081,0x00000046,0x000000e6,0x000000e5,0x000000e3,0x00050041,
+	0x00000074,0x000000e7,0x0000004a,0x00000082,0x0003003e,0x000000e7,0x000000e6,0x00050041,
+	0x00000019,0x000000e8,0x00000035,0x00000024,0x0004003d,0x00000006,0x000000e9,0x000000e8,
+	0x000500aa,0x00000052,0x000000ea,0x000000e9,0x00000018,0x000300f7,0x000000ed,0x00000000,
+	0x000400fa,0x000000ea,0x000000ec,0x000000ef,0x000200f8,0x000000ec,0x0004003d,0x00000006,
+	0x000000ee,0x0000004f,0x0003003e,0x000000eb,0x000000ee,0x000200f9,0x000000ed,0x000200f8,
+	0x000000ef,0x0004003d,0x00000006,0x000000f0,0x0000004f,0x00050041,0x00000021,0x000000f1,
+	0x0000001e,0x0000005d,0x0004003d,0x00000006,0x000000f2,0x000000f1,0x00050080,0x00000006,
+	0x000000f3,0x000000f0,0x000000f2,0x0003003e,0x000000eb,0x000000f3,0x000200f9,0x000000ed,
+	0x000200f8,0x000000ed,0x0004003d,0x00000006,0x000000f4,0x000000eb,0x0003003e,0x0000004f,
+	0x000000f4,0x0004003d,0x00000006,0x000000f5,0x0000004f,0x00060041,0x00000070,0x000000f6,
+	0x0000006e,0x0000005d,0x000000f5,0x0004003d,0x00000006,0x000000f7,0x000000f6,0x0006000c,
+	0x00000046,0x000000f8,0x00000001,0x00000040,0x000000f7,0x00050041,0x00000074,0x000000f9,
+	0x0000006a,0x0000005d,0x0003003e,0x000000f9,0x000000f8,0x0004003d,0x00000006,0x000000fa,
+	0x0000004f,0x00050080,0x00000006,0x000000fb,0x000000fa,0x00000024,0x00060041,0x00000070,
+	0x000000fc,0x0000006e,0x0000005d,0x000000fb,0x0004003d,0x00000006,0x000000fd,0x000000fc,
+	0x0006000c,0x00000046,0x000000fe,0x00000001,0x00000040,0x000000fd,0x00050041,0x00000074,
+	0x000000ff,0x0000006a,0x0000003e,0x0003003e,0x000000ff,0x000000fe,0x0004003d,0x00000006,
+	0x00000100,0x0000004f,0x00050080,0x00000006,0x00000101,0x00000100,0x0000002a,0x00060041,
+	0x00000070,0x00000102,0x0000006e,0x0000005d,0x00000101,0x0004003d,0x00000006,0x00000103,
+	0x00000102,0x0006000c,0x00000046,0x00000104,0x00000001,0x00000040,0x00000103,0x00050041,
+	0x00000074,0x00000105,0x0000006a,0x00000065,0x0003003e,0x00000105,0x00000104,0x0004003d,
+	0x00000006,0x00000106,0x0000004f,0x00050080,0x00000006,0x00000107,0x00000106,0x00000084,
+	0x00060041,0x00000070,0x00000108,0x0000006e,0x0000005d,0x00000107,0x0004003d,0x00000006,
+	0x00000109,0x00000108,0x0006000c,0x00000046,0x0000010a,0x00000001,0x00000040,0x00000109,
+	0x00050041,0x00000074,0x0000010b,0x0000006a,0x00000082,0x0003003e,0x0000010b,0x0000010a,
+	0x00050041,0x00000074,0x0000010c,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x0000010d,
+	0x0000010c,0x0005008e,0x00000046,0x0000010f,0x0000010d,0x0000010e,0x00050041,0x00000074,
+	0x00000110,0x0000004a,0x0000005d,0x0004003d,0x00000046,0x00000111,0x00000110,0x00050081,
+	0x00000046,0x00000112,0x00000111,0x0000010f,0x00050041,0x00000074,0x00000113,0x0000004a,
+	0x0000005d,0x0003003e,0x00000113,0x00000112,0x00050041,0x00000074,0x00000114,0x0000006a,
+	0x0000003e,0x0004003d,0x00000046,0x00000115,0x00000114,0x0005008e,0x00000046,0x00000116,
+	0x00000115,0x0000010e,0x00050041,0x00000074,0x00000117,0x0000004a,0x0000003e,0x0004003d,
+	0x00000046,0x00000118,0x00000117,0x00050081,0x00000046,0x00000119,0x00000118,0x00000116,
+	0x00050041,0x00000074,0x0000011a,0x0000004a,0x0000003e,0x0003003e,0x0000011a,0x00000119,
+	0x00050041,0x00000074,0x0000011b,0x0000006a,0x00000065,0x0004003d,0x00000046,0x0000011c,
+	0x0000011b,0x0005008e,0x00000046,0x0000011d,0x0000011c,0x0000010e,0x00050041,0x00000074,
+	0x0000011e,0x0000004a,0x00000065,0x0004003d,0x00000046,0x0000011f,0x0000011e,0x00050081,
+	0x00000046,0x00000120,0x0000011f,0x0000011d,0x00050041,0x00000074,0x00000121,0x0000004a,
+	0x00000065,0x0003003e,0x00000121,0x00000120,0x00050041,0x00000074,0x00000122,0x0000006a,
+	0x00000082,0x0004003d,0x00000046,0x00000123,0x00000122,0x0005008e,0x00000046,0x00000124,
+	0x00000123,0x0000010e,0x00050041,0x00000074,0x00000125,0x0000004a,0x00000082,0x0004003d,
+	0x00000046,0x00000126,0x00000125,0x00050081,0x00000046,0x00000127,0x00000126,0x00000124,
+	0x00050041,0x00000074,0x00000128,0x0000004a,0x00000082,0x0003003e,0x00000128,0x00000127,
+	0x00050041,0x00000074,0x00000129,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x0000012a,
+	0x00000129,0x0005008e,0x00000046,0x0000012b,0x0000012a,0x0000008c,0x00050041,0x00000074,
+	0x0000012c,0x0000004e,0x0000005d,0x0004003d,0x00000046,0x0000012d,0x0000012c,0x00050081,
+	0x00000046,0x0000012e,0x0000012d,0x0000012b,0x00050041,0x00000074,0x0000012f,0x0000004e,
+	0x0000005d,0x0003003e,0x0000012f,0x0000012e,0x00050041,0x00000074,0x00000130,0x0000006a,
+	0x0000003e,0x0004003d,0x00000046,0x00000131,0x00000130,0x0005008e,0x00000046,0x00000132,
+	0x00000131,0x0000008c,0x00050041,0x00000074,0x00000133,0x0000004e,0x0000003e,0x0004003d,
+	0x00000046,0x00000134,0x00000133,0x00050081,0x00000046,0x00000135,0x00000134,0x00000132,
+	0x00050041,0x00000074,0x00000136,0x0000004e,0x0000003e,0x0003003e,0x00000136,0x00000135,
+	0x00050041,0x00000074,0x00000137,0x0000006a,0x00000065,0x0004003d,0x00000046,0x00000138,
+	0x00000137,0x0005008e,0x00000046,0x00000139,0x00000138,0x0000008c,0x00050041,0x00000074,
+	0x0000013a,0x0000004e,0x00000065,0x0004003d,0x00000046,0x0000013b,0x0000013a,0x00050081,
+	0x00000046,0x0000013c,0x0000013b,0x00000139,0x00050041,0x00000074,0x0000013d,0x0000004e,
+	0x00000065,0x0003003e,0x0000013d,0x0000013c,0x00050041,0x00000074,0x0000013e,0x0000006a,
+	0x00000082,0x0004003d,0x00000046,0x0000013f,0x0000013e,0x0005008e,0x00000046,0x00000140,
+	0x0000013f,0x0000008c,0x00050041,0x00000074,0x00000141,0x0000004e,0x00000082,0x0004003d,
+	0x00000046,0x00000142,0x00000141,0x00050081,0x00000046,0x00000143,0x00000142,0x00000140,
+	0x00050041,0x00000074,0x00000144,0x0000004e,0x00000082,0x0003003e,0x00000144,0x00000143,
+	0x00050041,0x00000021,0x00000145,0x0000001e,0x0000005d,0x0004003d,0x00000006,0x00000146,
+	0x00000145,0x0004003d,0x00000006,0x00000147,0x0000004f,0x00050080,0x00000006,0x00000148,
+	0x00000147,0x00000146,0x0003003e,0x0000004f,0x00000148,0x0004003d,0x00000006,0x00000149,
+	0x0000004f,0x00060041,0x00000070,0x0000014a,0x0000006e,0x0000005d,0x00000149,0x0004003d,
+	0x00000006,0x0000014b,0x0000014a,0x0006000c,0x00000046,0x0000014c,0x00000001,0x00000040,
+	0x0000014b,0x00050041,0x00000074,0x0000014d,0x0000006a,0x0000005d,0x0003003e,0x0000014d,
+	0x0000014c,0x0004003d,0x00000006,0x0000014e,0x0000004f,0x00050080,0x00000006,0x0000014f,
+	0x0000014e,0x00000024,0x00060041,0x00000070,0x00000150,0x0000006e,0x0000005d,0x0000014f,
+	0x0004003d,0x00000006,0x00000151,0x00000150,0x0006000c,0x00000046,0x00000152,0x00000001,
+	0x00000040,0x00000151,0x00050041,0x00000074,0x00000153,0x0000006a,0x0000003e,0x0003003e,
+	0x00000153,0x00000152,0x0004003d,0x00000006,0x00000154,0x0000004f,0x00050080,0x00000006,
+	0x00000155,0x00000154,0x0000002a,0x00060041,0x00000070,0x00000156,0x0000006e,0x0000005d,
+	0x00000155,0x0004003d,0x00000006,0x00000157,0x00000156,0x0006000c,0x00000046,0x00000158,
+	0x00000001,0x00000040,0x00000157,0x00050041,0x00000074,0x00000159,0x0000006a,0x00000065,
+	0x0003003e,0x00000159,0x00000158,0x0004003d,0x00000006,0x0000015a,0x0000004f,0x00050080,
+	0x00000006,0x0000015b,0x0000015a,0x00000084,0x00060041,0x00000070,0x0000015c,0x0000006e,
+	0x0000005d,0x0000015b,0x0004003d,0x00000006,0x0000015d,0x0000015c,0x0006000c,0x00000046,
+	0x0000015e,0x00000001,0x00000040,0x0000015d,0x00050041,0x00000074,0x0000015f,0x0000006a,
+	0x00000082,0x0003003e,0x0000015f,0x0000015e,0x00050041,0x00000074,0x00000160,0x0000006a,
+	0x0000005d,0x0004003d,0x00000046,0x00000161,0x00000160,0x0005008e,0x00000046,0x00000162,
+	0x00000161,0x000000cd,0x00050041,0x00000074,0x00000163,0x0000004a,0x0000005d,0x0004003d,
+	0x00000046,0x00000164,0x00000163,0x00050081,0x00000046,0x00000165,0x00000164,0x00000162,
+	0x00050041,0x00000074,0x00000166,0x0000004a,0x0000005d,0x0003003e,0x00000166,0x00000165,
+	0x00050041,0x00000074,0x00000167,0x0000006a,0x0000003e,0x0004003d,0x00000046,0x00000168,
+	0x00000167,0x0005008e,0x00000046,0x00000169,0x00000168,0x000000cd,0x00050041,0x00000074,
+	0x0000016a,0x0000004a,0x0000003e,0x0004003d,0x00000046,0x0000016b,0x0000016a,0x00050081,
+	0x00000046,0x0000016c,0x0000016b,0x00000169,0x00050041,0x00000074,0x0000016d,0x0000004a,
+	0x0000003e,0x0003003e,0x0000016d,0x0000016c,0x00050041,0x00000074,0x0000016e,0x0000006a,
+	0x00000065,0x0004003d,0x00000046,0x0000016f,0x0000016e,0x0005008e,0x00000046,0x00000170,
+	0x0000016f,0x000000cd,0x00050041,0x00000074,0x00000171,0x0000004a,0x00000065,0x0004003d,
+	0x00000046,0x00000172,0x00000171,0x00050081,0x00000046,0x00000173,0x00000172,0x00000170,
+	0x00050041,0x00000074,0x00000174,0x0000004a,0x00000065,0x0003003e,0x00000174,0x00000173,
+	0x00050041,0x00000074,0x00000175,0x0000006a,0x00000082,0x0004003d,0x00000046,0x00000176,
+	0x00000175,0x0005008e,0x00000046,0x00000177,0x00000176,0x000000cd,0x00050041,0x00000074,
+	0x00000178,0x0000004a,0x00000082,0x0004003d,0x00000046,0x00000179,0x00000178,0x00050081,
+	0x00000046,0x0000017a,0x00000179,0x00000177,0x00050041,0x00000074,0x0000017b,0x0000004a,
+	0x00000082,0x0003003e,0x0000017b,0x0000017a,0x00050041,0x00000074,0x0000017c,0x0000006a,
+	0x0000005d,0x0004003d,0x00000046,0x0000017d,0x0000017c,0x0005008e,0x00000046,0x0000017e,
+	0x0000017d,0x000000cd,0x00050041,0x00000074,0x0000017f,0x0000004e,0x0000005d,0x0004003d,
+	0x00000046,0x00000180,0x0000017f,0x00050081,0x00000046,0x00000181,0x00000180,0x0000017e,
+	0x00050041,0x00000074,0x00000182,0x0000004e,0x0000005d,0x0003003e,0x00000182,0x00000181,
+	0x00050041,0x00000074,0x00000183,0x0000006a,0x0000003e,0x0004003d,0x00000046,0x00000184,
+	0x00000183,0x0005008e,0x00000046,0x00000185,0x00000184,0x000000cd,0x00050041,0x00000074,
+	0x00000186,0x0000004e,0x0000003e,0x0004003d,0x00000046,0x00000187,0x00000186,0x00050081,
+	0x00000046,0x00000188,0x00000187,0x00000185,0x00050041,0x00000074,0x00000189,0x0000004e,
+	0x0000003e,0x0003003e,0x00000189,0x00000188,0x00050041,0x00000074,0x0000018a,0x0000006a,
+	0x00000065,0x0004003d,0x00000046,0x0000018b,0x0000018a,0x0005008e,0x00000046,0x0000018c,
+	0x0000018b,0x000000cd,0x00050041,0x00000074,0x0000018d,0x0000004e,0x00000065,0x0004003d,
+	0x00000046,0x0000018e,0x0000018d,0x00050081,0x00000046,0x0000018f,0x0000018e,0x0000018c,
+	0x00050041,0x00000074,0x00000190,0x0000004e,0x00000065,0x0003003e,0x00000190,0x0000018f,
+	0x00050041,0x00000074,0x00000191,0x0000006a,0x00000082,0x0004003d,0x00000046,0x00000192,
+	0x00000191,0x0005008e,0x00000046,0x00000193,0x00000192,0x000000cd,0x00050041,0x00000074,
+	0x00000194,0x0000004e,0x00000082,0x0004003d,0x00000046,0x00000195,0x00000194,0x00050081,
+	0x00000046,0x00000196,0x00000195,0x00000193,0x00050041,0x00000074,0x00000197,0x0000004e,
+	0x00000082,0x0003003e,0x00000197,0x00000196,0x00050041,0x00000021,0x00000198,0x0000001e,
+	0x0000005d,0x0004003d,0x00000006,0x00000199,0x00000198,0x0004003d,0x00000006,0x0000019a,
+	0x0000004f,0x00050080,0x00000006,0x0000019b,0x0000019a,0x00000199,0x0003003e,0x0000004f,
+	0x0000019b,0x0004003d,0x00000006,0x0000019c,0x0000004f,0x00060041,0x00000070,0x0000019d,
+	0x0000006e,0x0000005d,0x0000019c,0x0004003d,0x00000006,0x0000019e,0x0000019d,0x0006000c,
+	0x00000046,0x0000019f,0x00000001,0x00000040,0x0000019e,0x00050041,0x00000074,0x000001a0,
+	0x0000006a,0x0000005d,0x0003003e,0x000001a0,0x0000019f,0x0004003d,0x00000006,0x000001a1,
+	0x0000004f,0x00050080,0x00000006,0x000001a2,0x000001a1,0x00000024,0x00060041,0x00000070,
+	0x000001a3,0x0000006e,0x0000005d,0x000001a2,0x0004003d,0x00000006,0x000001a4,0x000001a3,
+	0x0006000c,0x00000046,0x000001a5,0x00000001,0x00000040,0x000001a4,0x00050041,0x00000074,
+	0x000001a6,0x0000006a,0x0000003e,0x0003003e,0x000001a6,0x000001a5,0x0004003d,0x00000006,
+	0x000001a7,0x0000004f,0x00050080,0x00000006,0x000001a8,0x000001a7,0x0000002a,0x00060041,
+	0x00000070,0x000001a9,0x0000006e,0x0000005d,0x000001a8,0x0004003d,0x00000006,0x000001aa,
+	0x000001a9,0x0006000c,0x00000046,0x000001ab,0x00000001,0x00000040,0x000001aa,0x00050041,
+	0x00000074,0x000001ac,0x0000006a,0x00000065,0x0003003e,0x000001ac,0x000001ab,0x0004003d,
+	0x00000006,0x000001ad,0x0000004f,0x00050080,0x00000006,0x000001ae,0x000001ad,0x00000084,
+	0x00060041,0x00000070,0x000001af,0x0000006e,0x0000005d,0x000001ae,0x0004003d,0x00000006,
+	0x000001b0,0x000001af,0x0006000c,0x00000046,0x000001b1,0x00000001,0x00000040,0x000001b0,
+	0x00050041,0x00000074,0x000001b2,0x0000006a,0x00000082,0x0003003e,0x000001b2,0x000001b1,
+	0x00050041,0x00000074,0x000001b3,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x000001b4,
+	0x000001b3,0x0005008e,0x00000046,0x000001b5,0x000001b4,0x0000008c,0x00050041,0x00000074,
+	0x000001b6,0x0000004a,0x0000005d,0x0004003d,0x00000046,0x000001b7,0x000001b6,0x00050081,
+	0x00000046,0x000001b8,0x000001b7,0x000001b5,0x00050041,0x00000074,0x000001b9,0x0000004a,
+	0x0000005d,0x0003003e,0x000001b9,0x000001b8,0x00050041,0x00000074,0x000001ba,0x0000006a,
+	0x0000003e,0x0004003d,0x00000046,0x000001bb,0x000001ba,0x0005008e,0x00000046,0x000001bc,
+	0x000001bb,0x0000008c,0x00050041,0x00000074,0x000001bd,0x0000004a,0x0000003e,0x0004003d,
+	0x00000046,0x000001be,0x000001bd,0x00050081,0x00000046,0x000001bf,0x000001be,0x000001bc,
+	0x00050041,0x00000074,0x000001c0,0x0000004a,0x0000003e,0x0003003e,0x000001c0,0x000001bf,
+	0x00050041,0x00000074,0x000001c1,0x0000006a,0x00000065,0x0004003d,0x00000046,0x000001c2,
+	0x000001c1,0x0005008e,0x00000046,0x000001c3,0x000001c2,0x0000008c,0x00050041,0x00000074,
+	0x000001c4,0x0000004a,0x00000065,0x0004003d,0x00000046,0x000001c5,0x000001c4,0x00050081,
+	0x00000046,0x000001c6,0x000001c5,0x000001c3,0x00050041,0x00000074,0x000001c7,0x0000004a,
+	0x00000065,0x0003003e,0x000001c7,0x000001c6,0x00050041,0x00000074,0x000001c8,0x0000006a,
+	0x00000082,0x0004003d,0x00000046,0x000001c9,0x000001c8,0x0005008e,0x00000046,0x000001ca,
+	0x000001c9,0x0000008c,0x00050041,0x00000074,0x000001cb,0x0000004a,0x00000082,0x0004003d,
+	0x00000046,0x000001cc,0x000001cb,0x00050081,0x00000046,0x000001cd,0x000001cc,0x000001ca,
+	0x00050041,0x00000074,0x000001ce,0x0000004a,0x00000082,0x0003003e,0x000001ce,0x000001cd,
+	0x00050041,0x00000074,0x000001cf,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x000001d0,
+	0x000001cf,0x0005008e,0x00000046,0x000001d1,0x000001d0,0x0000010e,0x00050041,0x00000074,
+	0x000001d2,0x0000004e,0x0000005d,0x0004003d,0x00000046,0x000001d3,0x000001d2,0x00050081,
+	0x00000046,0x000001d4,0x000001d3,0x000001d1,0x00050041,0x00000074,0x000001d5,0x0000004e,
+	0x0000005d,0x0003003e,0x000001d5,0x000001d4,0x00050041,0x00000074,0x000001d6,0x0000006a,
+	0x0000003e,0x0004003d,0x00000046,0x000001d7,0x000001d6,0x0005008e,0x00000046,0x000001d8,
+	0x000001d7,0x0000010e,0x00050041,0x00000074,0x000001d9,0x0000004e,0x0000003e,0x0004003d,
+	0x00000046,0x000001da,0x000001d9,0x00050081,0x00000046,0x000001db,0x000001da,0x000001d8,
+	0x00050041,0x00000074,0x000001dc,0x0000004e,0x0000003e,0x0003003e,0x000001dc,0x000001db,
+	0x00050041,0x00000074,0x000001dd,0x0000006a,0x00000065,0x0004003d,0x00000046,0x000001de,
+	0x000001dd,0x0005008e,0x00000046,0x000001df,0x000001de,0x0000010e,0x00050041,0x00000074,
+	0x000001e0,0x0000004e,0x00000065,0x0004003d,0x00000046,0x000001e1,0x000001e0,0x00050081,
+	0x00000046,0x000001e2,0x000001e1,0x000001df,0x00050041,0x00000074,0x000001e3,0x0000004e,
+	0x00000065,0x0003003e,0x000001e3,0x000001e2,0x00050041,0x00000074,0x000001e4,0x0000006a,
+	0x00000082,0x0004003d,0x00000046,0x000001e5,0x000001e4,0x0005008e,0x00000046,0x000001e6,
+	0x000001e5,0x0000010e,0x00050041,0x00000074,0x000001e7,0x0000004e,0x00000082,0x0004003d,
+	0x00000046,0x000001e8,0x000001e7,0x00050081,0x00000046,0x000001e9,0x000001e8,0x000001e6,
+	0x00050041,0x00000074,0x000001ea,0x0000004e,0x00000082,0x0003003e,0x000001ea,0x000001e9,
+	0x00050041,0x00000021,0x000001eb,0x0000001e,0x0000005d,0x0004003d,0x00000006,0x000001ec,
+	0x000001eb,0x0004003d,0x00000006,0x000001ed,0x0000004f,0x00050080,0x00000006,0x000001ee,
+	0x000001ed,0x000001ec,0x0003003e,0x0000004f,0x000001ee,0x0004003d,0x00000006,0x000001ef,
+	0x0000004f,0x00060041,0x00000070,0x000001f0,0x0000006e,0x0000005d,0x000001ef,0x0004003d,
+	0x00000006,0x000001f1,0x000001f0,0x0006000c,0x00000046,0x000001f2,0x00000001,0x00000040,
+	0x000001f1,0x00050041,0x00000074,0x000001f3,0x0000006a,0x0000005d,0x0003003e,0x000001f3,
+	0x000001f2,0x0004003d,0x00000006,0x000001f4,0x0000004f,0x00050080,0x00000006,0x000001f5,
+	0x000001f4,0x00000024,0x00060041,0x00000070,0x000001f6,0x0000006e,0x0000005d,0x000001f5,
+	0x0004003d,0x00000006,0x000001f7,0x000001f6,0x0006000c,0x00000046,0x000001f8,0x00000001,
+	0x00000040,0x000001f7,0x00050041,0x00000074,0x000001f9,0x0000006a,0x0000003e,0x0003003e,
+	0x000001f9,0x000001f8,0x0004003d,0x00000006,0x000001fa,0x0000004f,0x00050080,0x00000006,
+	0x000001fb,0x000001fa,0x0000002a,0x00060041,0x00000070,0x000001fc,0x0000006e,0x0000005d,
+	0x000001fb,0x0004003d,0x00000006,0x000001fd,0x000001fc,0x0006000c,0x00000046,0x000001fe,
+	0x00000001,0x00000040,0x000001fd,0x00050041,0x00000074,0x000001ff,0x0000006a,0x00000065,
+	0x0003003e,0x000001ff,0x000001fe,0x0004003d,0x00000006,0x00000200,0x0000004f,0x00050080,
+	0x00000006,0x00000201,0x00000200,0x00000084,0x00060041,0x00000070,0x00000202,0x0000006e,
+	0x0000005d,0x00000201,0x0004003d,0x00000006,0x00000203,0x00000202,0x0006000c,0x00000046,
+	0x00000204,0x00000001,0x00000040,0x00000203,0x00050041,0x00000074,0x00000205,0x0000006a,
+	0x00000082,0x0003003e,0x00000205,0x00000204,0x00050041,0x00000074,0x00000206,0x0000006a,
+	0x0000005d,0x0004003d,0x00000046,0x00000207,0x00000206,0x0005008e,0x00000046,0x00000208,
+	0x00000207,0x000000cd,0x00050041,0x00000074,0x00000209,0x0000004e,0x0000005d,0x0004003d,
+	0x00000046,0x0000020a,0x00000209,0x00050081,0x00000046,0x0000020b,0x0000020a,0x00000208,
+	0x00050041,0x00000074,0x0000020c,0x0000004e,0x0000005d,0x0003003e,0x0000020c,0x0000020b,
+	0x00050041,0x00000074,0x0000020d,0x0000006a,0x0000003e,0x0004003d,0x00000046,0x0000020e,
+	0x0000020d,0x0005008e,0x00000046,0x0000020f,0x0000020e,0x000000cd,0x00050041,0x00000074,
+	0x00000210,0x0000004e,0x0000003e,0x0004003d,0x00000046,0x00000211,0x00000210,0x00050081,
+	0x00000046,0x00000212,0x00000211,0x0000020f,0x00050041,0x00000074,0x00000213,0x0000004e,
+	0x0000003e,0x0003003e,0x00000213,0x00000212,0x00050041,0x00000074,0x00000214,0x0000006a,
+	0x00000065,0x0004003d,0x00000046,0x00000215,0x00000214,0x0005008e,0x00000046,0x00000216,
+	0x00000215,0x000000cd,0x00050041,0x00000074,0x00000217,0x0000004e,0x00000065,0x0004003d,
+	0x00000046,0x00000218,0x00000217,0x00050081,0x00000046,0x00000219,0x00000218,0x00000216,
+	0x00050041,0x00000074,0x0000021a,0x0000004e,0x00000065,0x0003003e,0x0000021a,0x00000219,
+	0x00050041,0x00000074,0x0000021b,0x0000006a,0x00000082,0x0004003d,0x00000046,0x0000021c,
+	0x0000021b,0x0005008e,0x00000046,0x0000021d,0x0000021c,0x000000cd,0x00050041,0x00000074,
+	0x0000021e,0x0000004e,0x00000082,0x0004003d,0x00000046,0x0000021f,0x0000021e,0x00050081,
+	0x00000046,0x00000220,0x0000021f,0x0000021d,0x00050041,0x00000074,0x00000221,0x0000004e,
+	0x00000082,0x0003003e,0x00000221,0x00000220,0x00050041,0x00000021,0x00000222,0x0000001e,
+	0x0000005d,0x0004003d,0x00000006,0x00000223,0x00000222,0x0004003d,0x00000006,0x00000224,
+	0x0000004f,0x00050080,0x00000006,0x00000225,0x00000224,0x00000223,0x0003003e,0x0000004f,
+	0x00000225,0x0004003d,0x00000006,0x00000226,0x0000004f,0x00060041,0x00000070,0x00000227,
+	0x0000006e,0x0000005d,0x00000226,0x0004003d,0x00000006,0x00000228,0x00000227,0x0006000c,
+	0x00000046,0x00000229,0x00000001,0x00000040,0x00000228,0x00050041,0x00000074,0x0000022a,
+	0x0000006a,0x0000005d,0x0003003e,0x0000022a,0x00000229,0x0004003d,0x00000006,0x0000022b,
+	0x0000004f,0x00050080,0x00000006,0x0000022c,0x0000022b,0x00000024,0x00060041,0x00000070,
+	0x0000022d,0x0000006e,0x0000005d,0x0000022c,0x0004003d,0x00000006,0x0000022e,0x0000022d,
+	0x0006000c,0x00000046,0x0000022f,0x00000001,0x00000040,0x0000022e,0x00050041,0x00000074,
+	0x00000230,0x0000006a,0x0000003e,0x0003003e,0x00000230,0x0000022f,0x0004003d,0x00000006,
+	0x00000231,0x0000004f,0x00050080,0x00000006,0x00000232,0x00000231,0x0000002a,0x00060041,
+	0x00000070,0x00000233,0x0000006e,0x0000005d,0x00000232,0x0004003d,0x00000006,0x00000234,
+	0x00000233,0x0006000c,0x00000046,0x00000235,0x00000001,0x00000040,0x00000234,0x00050041,
+	0x00000074,0x00000236,0x0000006a,0x00000065,0x0003003e,0x00000236,0x00000235,0x0004003d,
+	0x00000006,0x00000237,0x0000004f,0x00050080,0x00000006,0x00000238,0x00000237,0x00000084,
+	0x00060041,0x00000070,0x00000239,0x0000006e,0x0000005d,0x00000238,0x0004003d,0x00000006,
+	0x0000023a,0x00000239,0x0006000c,0x00000046,0x0000023b,0x00000001,0x00000040,0x0000023a,
+	0x00050041,0x00000074,0x0000023c,0x0000006a,0x00000082,0x0003003e,0x0000023c,0x0000023b,
+	0x00050041,0x00000074,0x0000023d,0x0000006a,0x0000005d,0x0004003d,0x00000046,0x0000023e,
+	0x0000023d,0x0005008e,0x00000046,0x0000023f,0x0000023e,0x0000008c,0x00050041,0x00000074,
+	0x00000240,0x0000004e,0x0000005d,0x0004003d,0x00000046,0x00000241,0x00000240,0x00050081,
+	0x00000046,0x00000242,0x00000241,0x0000023f,0x00050041,0x00000074,0x00000243,0x0000004e,
+	0x0000005d,0x0003003e,0x00000243,0x00000242,0x00050041,0x00000074,0x00000244,0x0000006a,
+	0x0000003e,0x0004003d,0x00000046,0x00000245,0x00000244,0x0005008e,0x00000046,0x00000246,
+	0x00000245,0x0000008c,0x00050041,0x00000074,0x00000247,0x0000004e,0x0000003e,0x0004003d,
+	0x00000046,0x00000248,0x00000247,0x00050081,0x00000046,0x00000249,0x00000248,0x00000246,
+	0x00050041,0x00000074,0x0000024a,0x0000004e,0x0000003e,0x0003003e,0x0000024a,0x00000249,
+	0x00050041,0x00000074,0x0000024b,0x0000006a,0x00000065,0x0004003d,0x00000046,0x0000024c,
+	0x0000024b,0x0005008e,0x00000046,0x0000024d,0x0000024c,0x0000008c,0x00050041,0x00000074,
+	0x0000024e,0x0000004e,0x00000065,0x0004003d,0x00000046,0x0000024f,0x0000024e,0x00050081,
+	0x00000046,0x00000250,0x0000024f,0x0000024d,0x00050041,0x00000074,0x00000251,0x0000004e,
+	0x00000065,0x0003003e,0x00000251,0x00000250,0x00050041,0x00000074,0x00000252,0x0000006a,
+	0x00000082,0x0004003d,0x00000046,0x00000253,0x00000252,0x0005008e,0x00000046,0x00000254,
+	0x00000253,0x0000008c,0x00050041,0x00000074,0x00000255,0x0000004e,0x00000082,0x0004003d,
+	0x00000046,0x00000256,0x00000255,0x00050081,0x00000046,0x00000257,0x00000256,0x00000254,
+	0x00050041,0x00000074,0x00000258,0x0000004e,0x00000082,0x0003003e,0x00000258,0x00000257,
+	0x00050041,0x00000019,0x00000259,0x00000035,0x00000018,0x0004003d,0x00000006,0x0000025a,
+	0x00000259,0x000500aa,0x00000052,0x0000025b,0x0000025a,0x00000018,0x000300f7,0x0000025e,
+	0x00000000,0x000400fa,0x0000025b,0x0000025d,0x00000263,0x000200f8,0x0000025d,0x00060041,
+	0x0000025f,0x00000260,0x0000004a,0x0000003e,0x00000018,0x0004003d,0x00000045,0x00000261,
+	0x00000260,0x00070050,0x00000046,0x00000262,0x00000261,0x00000261,0x00000261,0x00000261,
+	0x0003003e,0x0000025c,0x00000262,0x000200f9,0x0000025e,0x000200f8,0x00000263,0x00050041,
+	0x00000074,0x00000264,0x0000004a,0x0000005d,0x0004003d,0x00000046,0x00000265,0x00000264,
+	0x0003003e,0x0000025c,0x00000265,0x000200f9,0x0000025e,0x000200f8,0x0000025e,0x0004003d,
+	0x00000046,0x00000266,0x0000025c,0x00050041,0x00000074,0x00000267,0x0000004a,0x0000005d,
+	0x0003003e,0x00000267,0x00000266,0x00050041,0x00000019,0x00000268,0x00000035,0x00000018,
+	0x0004003d,0x00000006,0x00000269,0x00000268,0x000500aa,0x00000052,0x0000026a,0x00000269,
+	0x00000018,0x000300f7,0x0000026d,0x00000000,0x000400fa,0x0000026a,0x0000026c,0x00000271,
+	0x000200f8,0x0000026c,0x00060041,0x0000025f,0x0000026e,0x0000004e,0x0000003e,0x00000018,
+	0x0004003d,0x00000045,0x0000026f,0x0000026e,0x00070050,0x00000046,0x00000270,0x0000026f,
+	0x0000026f,0x0000026f,0x0000026f,0x0003003e,0x0000026b,0x00000270,0x000200f9,0x0000026d,
+	0x000200f8,0x00000271,0x00050041,0x00000074,0x00000272,0x0000004e,0x0000005d,0x0004003d,
+	0x00000046,0x00000273,0x00000272,0x0003003e,0x0000026b,0x00000273,0x000200f9,0x0000026d,
+	0x000200f8,0x0000026d,0x0004003d,0x00000046,0x00000274,0x0000026b,0x00050041,0x00000074,
+	0x00000275,0x0000004e,0x0000005d,0x0003003e,0x00000275,0x00000274,0x00050041,0x00000019,
+	0x00000276,0x00000035,0x00000018,0x0004003d,0x00000006,0x00000277,0x00000276,0x00050041,
+	0x00000021,0x00000278,0x0000001e,0x00000020,0x0004003d,0x00000006,0x00000279,0x00000278,
+	0x00050082,0x00000006,0x0000027a,0x00000279,0x0000002a,0x000500aa,0x00000052,0x0000027b,
+	0x00000277,0x0000027a,0x000300f7,0x0000027e,0x00000000,0x000400fa,0x0000027b,0x0000027d,
+	0x00000282,0x000200f8,0x0000027d,0x00060041,0x0000025f,0x0000027f,0x0000004a,0x00000065,
+	0x00000084,0x0004003d,0x00000045,0x00000280,0x0000027f,0x00070050,0x00000046,0x00000281,
+	0x00000280,0x00000280,0x00000280,0x00000280,0x0003003e,0x0000027c,0x00000281,0x000200f9,
+	0x0000027e,0x000200f8,0x00000282,0x00050041,0x00000074,0x00000283,0x0000004a,0x00000082,
+	0x0004003d,0x00000046,0x00000284,0x00000283,0x0003003e,0x0000027c,0x00000284,0x000200f9,
+	0x0000027e,0x000200f8,0x0000027e,0x0004003d,0x00000046,0x00000285,0x0000027c,0x00050041,
+	0x00000074,0x00000286,0x0000004a,0x00000082,0x0003003e,0x00000286,0x00000285,0x00050041,
+	0x00000019,0x00000287,0x00000035,0x00000018,0x0004003d,0x00000006,0x00000288,0x00000287,
+	0x00050041,0x00000021,0x00000289,0x0000001e,0x00000020,0x0004003d,0x00000006,0x0000028a,
+	0x00000289,0x00050082,0x00000006,0x0000028b,0x0000028a,0x0000002a,0x000500aa,0x00000052,
+	0x0000028c,0x00000288,0x0000028b,0x000300f7,0x0000028f,0x00000000,0x000400fa,0x0000028c,
+	0x0000028e,0x00000293,0x000200f8,0x0000028e,0x00060041,0x0000025f,0x00000290,0x0000004e,
+	0x00000065,0x00000084,0x0004003d,0x00000045,0x00000291,0x00000290,0x00070050,0x00000046,
+	0x00000292,0x00000291,0x00000291,0x00000291,0x00000291,0x0003003e,0x0000028d,0x00000292,
+	0x000200f9,0x0000028f,0x000200f8,0x00000293,0x00050041,0x00000074,0x00000294,0x0000004e,
+	0x00000082,0x0004003d,0x00000046,0x00000295,0x00000294,0x0003003e,0x0000028d,0x00000295,
+	0x000200f9,0x0000028f,0x000200f8,0x0000028f,0x0004003d,0x00000046,0x00000296,0x0000028d,
+	0x00050041,0x00000074,0x00000297,0x0000004e,0x00000082,0x0003003e,0x00000297,0x00000296,
+	0x00060041,0x0000025f,0x00000299,0x0000004a,0x0000005d,0x0000002a,0x0004003d,0x00000045,
+	0x0000029a,0x00000299,0x00060041,0x0000025f,0x0000029b,0x0000004a,0x0000003e,0x00000018,
+	0x0004003d,0x00000045,0x0000029c,0x0000029b,0x00060041,0x0000025f,0x0000029d,0x0000004a,
+	0x0000003e,0x0000002a,0x0004003d,0x00000045,0x0000029e,0x0000029d,0x00060041,0x0000025f,
+	0x0000029f,0x0000004a,0x00000065,0x00000018,0x0004003d,0x00000045,0x000002a0,0x0000029f,
+	0x00070050,0x00000046,0x000002a1,0x0000029a,0x0000029c,0x0000029e,0x000002a0,0x0005008e,
+	0x00000046,0x000002a2,0x000002a1,0x0000008c,0x00060041,0x0000025f,0x000002a3,0x0000004a,
+	0x0000005d,0x00000084,0x0004003d,0x00000045,0x000002a4,0x000002a3,0x00060041,0x0000025f,
+	0x000002a5,0x0000004a,0x0000003e,0x00000024,0x0004003d,0x00000045,0x000002a6,0x000002a5,
+	0x00060041,0x0000025f,0x000002a7,0x0000004a,0x0000003e,0x00000084,0x0004003d,0x00000045,
+	0x000002a8,0x000002a7,0x00060041,0x0000025f,0x000002a9,0x0000004a,0x00000065,0x00000024,
+	0x0004003d,0x00000045,0x000002aa,0x000002a9,0x00070050,0x00000046,0x000002ab,0x000002a4,
+	0x000002a6,0x000002a8,0x000002aa,0x0005008e,0x00000046,0x000002ac,0x000002ab,0x000000cd,
+	0x00050081,0x00000046,0x000002ad,0x000002a2,0x000002ac,0x00060041,0x0000025f,0x000002ae,
+	0x0000004a,0x0000003e,0x00000018,0x0004003d,0x00000045,0x000002af,0x000002ae,0x00060041,
+	0x0000025f,0x000002b0,0x0000004a,0x0000003e,0x0000002a,0x0004003d,0x00000045,0x000002b1,
+	0x000002b0,0x00060041,0x0000025f,0x000002b2,0x0000004a,0x00000065,0x00000018,0x0004003d,
+	0x00000045,0x000002b3,0x000002b2,0x00060041,0x0000025f,0x000002b4,0x0000004a,0x00000065,
+	0x0000002a,0x0004003d,0x00000045,0x000002b5,0x000002b4,0x00070050,0x00000046,0x000002b6,
+	0x000002af,0x000002b1,0x000002b3,0x000002b5,0x0005008e,0x00000046,0x000002b7,0x000002b6,
+	0x0000010e,0x00050081,0x00000046,0x000002b8,0x000002ad,0x000002b7,0x00060041,0x0000025f,
+	0x000002b9,0x0000004a,0x0000003e,0x00000024,0x0004003d,0x00000045,0x000002ba,0x000002b9,
+	0x00060041,0x0000025f,0x000002bb,0x0000004a,0x0000003e,0x00000084,0x0004003d,0x00000045,
+	0x000002bc,0x000002bb,0x00060041,0x0000025f,0x000002bd,0x0000004a,0x00000065,0x00000024,
+	0x0004003d,0x00000045,0x000002be,0x000002bd,0x00060041,0x0000025f,0x000002bf,0x0000004a,
+	0x00000065,0x00000084,0x0004003d,0x00000045,0x000002c0,0x000002bf,0x00070050,0x00000046,
+	0x000002c1,0x000002ba,0x000002bc,0x000002be,0x000002c0,0x0005008e,0x00000046,0x000002c2,
+	0x000002c1,0x000000cd,0x00050081,0x00000046,0x000002c3,0x000002b8,0x000002c2,0x00060041,
+	0x0000025f,0x000002c4,0x0000004a,0x0000003e,0x0000002a,0x0004003d,0x00000045,0x000002c5,
+	0x000002c4,0x00060041,0x0000025f,0x000002c6,0x0000004a,0x00000065,0x00000018,0x0004003d,
+	0x00000045,0x000002c7,0x000002c6,0x00060041,0x0000025f,0x000002c8,0x0000004a,0x00000065,
+	0x0000002a,0x0004003d,0x00000045,0x000002c9,0x000002c8,0x00060041,0x0000025f,0x000002ca,
+	0x0000004a,0x00000082,0x00000018,0x0004003d,0x00000045,0x000002cb,0x000002ca,0x00070050,
+	0x00000046,0x000002cc,0x000002c5,0x000002c7,0x000002c9,0x000002cb,0x0005008e,0x00000046,
+	0x000002cd,0x000002cc,0x0000008c,0x00050081,0x00000046,0x000002ce,0x000002c3,0x000002cd,
+	0x0003003e,0x00000298,0x000002ce,0x00060041,0x0000025f,0x000002d0,0x0000004e,0x0000005d,
+	0x0000002a,0x0004003d,0x00000045,0x000002d1,0x000002d0,0x00060041,0x0000025f,0x000002d2,
+	0x0000004e,0x0000003e,0x00000018,0x0004003d,0x00000045,0x000002d3,0x000002d2,0x00060041,
+	0x0000025f,0x000002d4,0x0000004e,0x0000003e,0x0000002a,0x0004003d,0x00000045,0x000002d5,
+	0x000002d4,0x00060041,0x0000025f,0x000002d6,0x0000004e,0x00000065,0x00000018,0x0004003d,
+	0x00000045,0x000002d7,0x000002d6,0x00070050,0x00000046,0x000002d8,0x000002d1,0x000002d3,
+	0x000002d5,0x000002d7,0x0005008e,0x00000046,0x000002d9,0x000002d8,0x0000008c,0x00060041,
+	0x0000025f,0x000002da,0x0000004e,0x0000005d,0x00000084,0x0004003d,0x00000045,0x000002db,
+	0x000002da,0x00060041,0x0000025f,0x000002dc,0x0000004e,0x0000003e,0x00000024,0x0004003d,
+	0x00000045,0x000002dd,0x000002dc,0x00060041,0x0000025f,0x000002de,0x0000004e,0x0000003e,
+	0x00000084,0x0004003d,0x00000045,0x000002df,0x000002de,0x00060041,0x0000025f,0x000002e0,
+	0x0000004e,0x00000065,0x00000024,0x0004003d,0x00000045,0x000002e1,0x000002e0,0x00070050,
+	0x00000046,0x000002e2,0x000002db,0x000002dd,0x000002df,0x000002e1,0x0005008e,0x00000046,
+	0x000002e3,0x000002e2,0x000000cd,0x00050081,0x00000046,0x000002e4,0x000002d9,0x000002e3,
+	0x00060041,0x0000025f,0x000002e5,0x0000004e,0x0000003e,0x00000018,0x0004003d,0x00000045,
+	0x000002e6,0x000002e5,0x00060041,0x0000025f,0x000002e7,0x0000004e,0x0000003e,0x0000002a,
+	0x0004003d,0x00000045,0x000002e8,0x000002e7,0x00060041,0x0000025f,0x000002e9,0x0000004e,
+	0x00000065,0x00000018,0x0004003d,0x00000045,0x000002ea,0x000002e9,0x00060041,0x0000025f,
+	0x000002eb,0x0000004e,0x00000065,0x0000002a,0x0004003d,0x00000045,0x000002ec,0x000002eb,
+	0x00070050,0x00000046,0x000002ed,0x000002e6,0x000002e8,0x000002ea,0x000002ec,0x0005008e,
+	0x00000046,0x000002ee,0x000002ed,0x0000010e,0x00050081,0x00000046,0x000002ef,0x000002e4,
+	0x000002ee,0x00060041,0x0000025f,0x000002f0,0x0000004e,0x0000003e,0x00000024,0x0004003d,
+	0x00000045,0x000002f1,0x000002f0,0x00060041,0x0000025f,0x000002f2,0x0000004e,0x0000003e,
+	0x00000084,0x0004003d,0x00000045,0x000002f3,0x000002f2,0x00060041,0x0000025f,0x000002f4,
+	0x0000004e,0x00000065,0x00000024,0x0004003d,0x00000045,0x000002f5,0x000002f4,0x00060041,
+	0x0000025f,0x000002f6,0x0000004e,0x00000065,0x00000084,0x0004003d,0x00000045,0x000002f7,
+	0x000002f6,0x00070050,0x00000046,0x000002f8,0x000002f1,0x000002f3,0x000002f5,0x000002f7,
+	0x0005008e,0x00000046,0x000002f9,0x000002f8,0x000000cd,0x00050081,0x00000046,0x000002fa,
+	0x000002ef,0x000002f9,0x00060041,0x0000025f,0x000002fb,0x0000004e,0x0000003e,0x0000002a,
+	0x0004003d,0x00000045,0x000002fc,0x000002fb,0x00060041,0x0000025f,0x000002fd,0x0000004e,
+	0x00000065,0x00000018,0x0004003d,0x00000045,0x000002fe,0x000002fd,0x00060041,0x0000025f,
+	0x000002ff,0x0000004e,0x00000065,0x0000002a,0x0004003d,0x00000045,0x00000300,0x000002ff,
+	0x00060041,0x0000025f,0x00000301,0x0000004e,0x00000082,0x00000018,0x0004003d,0x00000045,
+	0x00000302,0x00000301,0x00070050,0x00000046,0x00000303,0x000002fc,0x000002fe,0x00000300,
+	0x00000302,0x0005008e,0x00000046,0x00000304,0x00000303,0x0000008c,0x00050081,0x00000046,
+	0x00000305,0x000002fa,0x00000304,0x0003003e,0x000002cf,0x00000305,0x0004003d,0x00000046,
+	0x00000306,0x00000298,0x00070050,0x00000046,0x00000308,0x0000004b,0x0000004b,0x0000004b,
+	0x0000004b,0x00070050,0x00000046,0x00000309,0x00000307,0x00000307,0x00000307,0x00000307,
+	0x0008000c,0x00000046,0x0000030a,0x00000001,0x0000002b,0x00000306,0x00000308,0x00000309,
+	0x0003003e,0x00000298,0x0000030a,0x0004003d,0x00000046,0x0000030b,0x000002cf,0x00070050,
+	0x00000046,0x0000030c,0x0000004b,0x0000004b,0x0000004b,0x0000004b,0x00070050,0x00000046,
+	0x0000030d,0x00000307,0x00000307,0x00000307,0x00000307,0x0008000c,0x00000046,0x0000030e,
+	0x00000001,0x0000002b,0x0000030b,0x0000030c,0x0000030d,0x0003003e,0x000002cf,0x0000030e,
+	0x00050041,0x00000019,0x0000030f,0x0000000a,0x00000018,0x0004003d,0x00000006,0x00000310,
+	0x0000030f,0x00050041,0x00000021,0x00000311,0x0000001e,0x00000082,0x0004003d,0x00000006,
+	0x00000312,0x00000311,0x00050082,0x00000006,0x00000313,0x00000312,0x00000024,0x0008000c,
+	0x00000006,0x00000314,0x00000001,0x0000002c,0x00000310,0x00000018,0x00000313,0x00050041,
+	0x00000019,0x00000315,0x0000000a,0x00000018,0x0003003e,0x00000315,0x00000314,0x00050041,
+	0x00000019,0x00000316,0x0000000a,0x00000024,0x0004003d,0x00000006,0x00000317,0x00000316,
+	0x00050041,0x00000021,0x00000319,0x0000001e,0x00000318,0x0004003d,0x00000006,0x0000031a,
+	0x00000319,0x00050082,0x00000006,0x0000031b,0x0000031a,0x0000002a,0x0008000c,0x00000006,
+	0x0000031c,0x00000001,0x0000002c,0x00000317,0x00000018,0x0000031b,0x00050041,0x00000019,
+	0x0000031d,0x0000000a,0x00000024,0x0003003e,0x0000031d,0x0000031c,0x00050041,0x00000019,
+	0x0000031f,0x0000000a,0x00000024,0x0004003d,0x00000006,0x00000320,0x0000031f,0x00050041,
+	0x00000021,0x00000321,0x0000001e,0x00000082,0x0004003d,0x00000006,0x00000322,0x00000321,
+	0x00050084,0x00000006,0x00000323,0x00000320,0x00000322,0x00050041,0x00000019,0x00000324,
+	0x0000000a,0x00000018,0x0004003d,0x00000006,0x00000325,0x00000324,0x00050080,0x00000006,
+	0x00000326,0x00000323,0x00000325,0x0003003e,0x0000031e,0x00000326,0x0004003d,0x00000006,
+	0x0000032b,0x0000031e,0x0004003d,0x00000046,0x0000032c,0x00000298,0x0006000c,0x00000006,
+	0x0000032d,0x00000001,0x00000037,0x0000032c,0x00060041,0x00000070,0x0000032e,0x0000032a,
+	0x0000005d,0x0000032b,0x0003003e,0x0000032e,0x0000032d,0x0004003d,0x00000006,0x0000032f,
+	0x0000031e,0x00050041,0x00000021,0x00000330,0x0000001e,0x00000082,0x0004003d,0x00000006,
+	0x00000331,0x00000330,0x00050080,0x00000006,0x00000332,0x0000032f,0x00000331,0x0004003d,
+	0x00000046,0x00000333,0x000002cf,0x0006000c,0x00000006,0x00000334,0x00000001,0x00000037,
+	0x00000333,0x00060041,0x00000070,0x00000335,0x0000032a,0x0000005d,0x00000332,0x0003003e,
+	0x00000335,0x00000334,0x000100fd,0x00010038,0x00050036,0x00000002,0x00000010,0x00000000,
+	0x0000000e,0x00030037,0x00000008,0x0000000f,0x000200f8,0x00000011,0x0004003b,0x00000008,
+	0x00000336,0x00000007,0x0004003b,0x00000008,0x0000033a,0x00000007,0x0004003b,0x00000049,
+	0x00000346,0x00000007,0x0004003b,0x00000019,0x00000347,0x00000007,0x0004003b,0x00000019,
+	0x0000034b,0x00000007,0x0004003b,0x00000049,0x0000035f,0x00000007,0x0004003b,0x00000019,
+	0x0000039a,0x00000007,0x0004003b,0x00000019,0x000003da,0x00000007,0x0004003b,0x00000074,
+	0x00000488,0x00000007,0x0004003b,0x00000074,0x0000049d,0x00000007,0x0004003b,0x00000074,
+	0x000004ac,0x00000007,0x0004003d,0x00000007,0x00000337,0x0000000f,0x00050050,0x00000007,
+	0x00000338,0x0000002a,0x0000002a,0x00050084,0x00000007,0x00000339,0x00000337,0x00000338,
+	0x0003003e,0x00000336,0x00000339,0x0004003d,0x00000007,0x0000033b,0x00000336,0x00050082,
+	0x00000007,0x0000033c,0x0000033b,0x0000002b,0x0003003e,0x0000033a,0x0000033c,0x00050041,
+	0x00000019,0x0000033d,0x0000033a,0x00000024,0x0004003d,0x00000006,0x0000033e,0x0000033d,
+	0x00050041,0x00000021,0x0000033f,0x0000001e,0x0000003e,0x0004003d,0x00000006,0x00000340,
+	0x0000033f,0x00050086,0x00000006,0x00000341,0x00000340,0x0000002a,0x00050082,0x00000006,
+	0x00000343,0x00000341,0x00000342,0x0008000c,0x00000006,0x00000344,0x00000001,0x0000002c,
+	0x0000033e,0x00000018,0x00000343,0x00050041,0x00000019,0x00000345,0x0000033a,0x00000024,
+	0x0003003e,0x00000345,0x00000344,0x0003003e,0x00000346,0x0000004d,0x00050041,0x00000019,
+	0x00000348,0x00000336,0x00000024,0x0004003d,0x00000006,0x00000349,0x00000348,0x000500aa,
+	0x00000052,0x0000034a,0x00000349,0x00000018,0x000300f7,0x0000034d,0x00000000,0x000400fa,
+	0x0000034a,0x0000034c,0x00000351,0x000200f8,0x0000034c,0x00050041,0x00000019,0x0000034e,
+	0x00000336,0x00000018,0x0004003d,0x00000006,0x0000034f,0x0000034e,0x00050082,0x00000006,
+	0x00000350,0x0000034f,0x00000024,0x0003003e,0x0000034b,0x00000350,0x000200f9,0x0000034d,
+	0x000200f8,0x00000351,0x00050041,0x00000019,0x00000352,0x0000033a,0x00000024,0x0004003d,
+	0x00000006,0x00000353,0x00000352,0x00050041,0x00000021,0x00000354,0x0000001e,0x0000005d,
+	0x0004003d,0x00000006,0x00000355,0x00000354,0x00050084,0x00000006,0x00000356,0x00000353,
+	0x00000355,0x00050041,0x00000019,0x00000357,0x0000033a,0x00000018,0x0004003d,0x00000006,
+	0x00000358,0x00000357,0x00050080,0x00000006,0x00000359,0x00000356,0x00000358,0x0003003e,
+	0x0000034b,0x00000359,0x000200f9,0x0000034d,0x000200f8,0x0000034d,0x0004003d,0x00000006,
+	0x0000035a,0x0000034b,0x0003003e,0x00000347,0x0000035a,0x00050041,0x00000021,0x0000035b,
+	0x0000001e,0x00000065,0x0004003d,0x00000006,0x0000035c,0x0000035b,0x0004003d,0x00000006,
+	0x0000035d,0x00000347,0x00050080,0x00000006,0x0000035e,0x0000035d,0x0000035c,0x0003003e,
+	0x00000347,0x0000035e,0x0004003d,0x00000006,0x00000364,0x00000347,0x00060041,0x00000070,
+	0x00000365,0x00000363,0x0000005d,0x00000364,0x0004003d,0x00000006,0x00000366,0x00000365,
+	0x0006000c,0x00000046,0x00000367,0x00000001,0x00000040,0x00000366,0x00050041,0x00000074,
+	0x00000368,0x0000035f,0x0000005d,0x0003003e,0x00000368,0x00000367,0x0004003d,0x00000006,
+	0x00000369,0x00000347,0x00050080,0x00000006,0x0000036a,0x00000369,0x00000024,0x00060041,
+	0x00000070,0x0000036b,0x00000363,0x0000005d,0x0000036a,0x0004003d,0x00000006,0x0000036c,
+	0x0000036b,0x0006000c,0x00000046,0x0000036d,0x00000001,0x00000040,0x0000036c,0x00050041,
+	0x00000074,0x0000036e,0x0000035f,0x0000003e,0x0003003e,0x0000036e,0x0000036d,0x0004003d,
+	0x00000006,0x0000036f,0x00000347,0x00050080,0x00000006,0x00000370,0x0000036f,0x0000002a,
+	0x00060041,0x00000070,0x00000371,0x00000363,0x0000005d,0x00000370,0x0004003d,0x00000006,
+	0x00000372,0x00000371,0x0006000c,0x00000046,0x00000373,0x00000001,0x00000040,0x00000372,
+	0x00050041,0x00000074,0x00000374,0x0000035f,0x00000065,0x0003003e,0x00000374,0x00000373,
+	0x0004003d,0x00000006,0x00000375,0x00000347,0x00050080,0x00000006,0x00000376,0x00000375,
+	0x00000084,0x00060041,0x00000070,0x00000377,0x00000363,0x0000005d,0x00000376,0x0004003d,
+	0x00000006,0x00000378,0x00000377,0x0006000c,0x00000046,0x00000379,0x00000001,0x00000040,
+	0x00000378,0x00050041,0x00000074,0x0000037a,0x0000035f,0x00000082,0x0003003e,0x0000037a,
+	0x00000379,0x00050041,0x00000074,0x0000037b,0x0000035f,0x0000005d,0x0004003d,0x00000046,
+	0x0000037c,0x0000037b,0x0005008e,0x00000046,0x0000037d,0x0000037c,0x0000008c,0x00050041,
+	0x00000074,0x0000037e,0x00000346,0x0000005d,0x0004003d,0x00000046,0x0000037f,0x0000037e,
+	0x00050081,0x00000046,0x00000380,0x0000037f,0x0000037d,0x00050041,0x00000074,0x00000381,
+	0x00000346,0x0000005d,0x0003003e,0x00000381,0x00000380,0x00050041,0x00000074,0x00000382,
+	0x0000035f,0x0000003e,0x0004003d,0x00000046,0x00000383,0x00000382,0x0005008e,0x00000046,
+	0x00000384,0x00000383,0x0000008c,0x00050041,0x00000074,0x00000385,0x00000346,0x0000003e,
+	0x0004003d,0x00000046,0x00000386,0x00000385,0x00050081,0x00000046,0x00000387,0x00000386,
+	0x00000384,0x00050041,0x00000074,0x00000388,0x00000346,0x0000003e,0x0003003e,0x00000388,
+	0x00000387,0x00050041,0x00000074,0x00000389,0x0000035f,0x00000065,0x0004003d,0x00000046,
+	0x0000038a,0x00000389,0x0005008e,0x00000046,0x0000038b,0x0000038a,0x0000008c,0x00050041,
+	0x00000074,0x0000038c,0x00000346,0x00000065,0x0004003d,0x00000046,0x0000038d,0x0000038c,
+	0x00050081,0x00000046,0x0000038e,0x0000038d,0x0000038b,0x00050041,0x00000074,0x0000038f,
+	0x00000346,0x00000065,0x0003003e,0x0000038f,0x0000038e,0x00050041,0x00000074,0x00000390,
+	0x0000035f,0x00000082,0x0004003d,0x00000046,0x00000391,0x00000390,0x0005008e,0x00000046,
+	0x00000392,0x00000391,0x0000008c,0x00050041,0x00000074,0x00000393,0x00000346,0x00000082,
+	0x0004003d,0x00000046,0x00000394,0x00000393,0x00050081,0x00000046,0x00000395,0x00000394,
+	0x00000392,0x00050041,0x00000074,0x00000396,0x00000346,0x00000082,0x0003003e,0x00000396,
+	0x00000395,0x00050041,0x00000019,0x00000397,0x00000336,0x00000024,0x0004003d,0x00000006,
+	0x00000398,0x00000397,0x000500aa,0x00000052,0x00000399,0x00000398,0x00000018,0x000300f7,
+	0x0000039c,0x00000000,0x000400fa,0x00000399,0x0000039b,0x0000039e,0x000200f8,0x0000039b,
+	0x0004003d,0x00000006,0x0000039d,0x00000347,0x0003003e,0x0000039a,0x0000039d,0x000200f9,
+	0x0000039c,0x000200f8,0x0000039e,0x0004003d,0x00000006,0x0000039f,0x00000347,0x00050041,
+	0x00000021,0x000003a0,0x0000001e,0x0000005d,0x0004003d,0x00000006,0x000003a1,0x000003a0,
+	0x00050080,0x00000006,0x000003a2,0x0000039f,0x000003a1,0x0003003e,0x0000039a,0x000003a2,
+	0x000200f9,0x0000039c,0x000200f8,0x0000039c,0x0004003d,0x00000006,0x000003a3,0x0000039a,
+	0x0003003e,0x00000347,0x000003a3,0x0004003d,0x00000006,0x000003a4,0x00000347,0x00060041,
+	0x00000070,0x000003a5,0x00000363,0x0000005d,0x000003a4,0x0004003d,0x00000006,0x000003a6,
+	0x000003a5,0x0006000c,0x00000046,0x000003a7,0x00000001,0x00000040,0x000003a6,0x00050041,
+	0x00000074,0x000003a8,0x0000035f,0x0000005d,0x0003003e,0x000003a8,0x000003a7,0x0004003d,
+	0x00000006,0x000003a9,0x00000347,0x00050080,0x00000006,0x000003aa,0x000003a9,0x00000024,
+	0x00060041,0x00000070,0x000003ab,0x00000363,0x0000005d,0x000003aa,0x0004003d,0x00000006,
+	0x000003ac,0x000003ab,0x0006000c,0x00000046,0x000003ad,0x00000001,0x00000040,0x000003ac,
+	0x00050041,0x00000074,0x000003ae,0x0000035f,0x0000003e,0x0003003e,0x000003ae,0x000003ad,
+	0x0004003d,0x00000006,0x000003af,0x00000347,0x00050080,0x00000006,0x000003b0,0x000003af,
+	0x0000002a,0x00060041,0x00000070,0x000003b1,0x00000363,0x0000005d,0x000003b0,0x0004003d,
+	0x00000006,0x000003b2,0x000003b1,0x0006000c,0x00000046,0x000003b3,0x00000001,0x00000040,
+	0x000003b2,0x00050041,0x00000074,0x000003b4,0x0000035f,0x00000065,0x0003003e,0x000003b4,
+	0x000003b3,0x0004003d,0x00000006,0x000003b5,0x00000347,0x00050080,0x00000006,0x000003b6,
+	0x000003b5,0x00000084,0x00060041,0x00000070,0x000003b7,0x00000363,0x0000005d,0x000003b6,
+	0x0004003d,0x00000006,0x000003b8,0x000003b7,0x0006000c,0x00000046,0x000003b9,0x00000001,
+	0x00000040,0x000003b8,0x00050041,0x00000074,0x000003ba,0x0000035f,0x00000082,0x0003003e,
+	0x000003ba,0x000003b9,0x00050041,0x00000074,0x000003bb,0x0000035f,0x0000005d,0x0004003d,
+	0x00000046,0x000003bc,0x000003bb,0x0005008e,0x00000046,0x000003bd,0x000003bc,0x000000cd,
+	0x00050041,0x00000074,0x000003be,0x00000346,0x0000005d,0x0004003d,0x00000046,0x000003bf,
+	0x000003be,0x00050081,0x00000046,0x000003c0,0x000003bf,0x000003bd,0x00050041,0x00000074,
+	0x000003c1,0x00000346,0x0000005d,0x0003003e,0x000003c1,0x000003c0,0x00050041,0x00000074,
+	0x000003c2,0x0000035f,0x0000003e,0x0004003d,0x00000046,0x000003c3,0x000003c2,0x0005008e,
+	0x00000046,0x000003c4,0x000003c3,0x000000cd,0x00050041,0x00000074,0x000003c5,0x00000346,
+	0x0000003e,0x0004003d,0x00000046,0x000003c6,0x000003c5,0x00050081,0x00000046,0x000003c7,
+	0x000003c6,0x000003c4,0x00050041,0x00000074,0x000003c8,0x00000346,0x0000003e,0x0003003e,
+	0x000003c8,0x000003c7,0x00050041,0x00000074,0x000003c9,0x0000035f,0x00000065,0x0004003d,
+	0x00000046,0x000003ca,0x000003c9,0x0005008e,0x00000046,0x000003cb,0x000003ca,0x000000cd,
+	0x00050041,0x00000074,0x000003cc,0x00000346,0x00000065,0x0004003d,0x00000046,0x000003cd,
+	0x000003cc,0x00050081,0x00000046,0x000003ce,0x000003cd,0x000003cb,0x00050041,0x00000074,
+	0x000003cf,0x00000346,0x00000065,0x0003003e,0x000003cf,0x000003ce,0x00050041,0x00000074,
+	0x000003d0,0x0000035f,0x00000082,0x0004003d,0x00000046,0x000003d1,0x000003d0,0x0005008e,
+	0x00000046,0x000003d2,0x000003d1,0x000000cd,0x00050041,0x00000074,0x000003d3,0x00000346,
+	0x00000082,0x0004003d,0x00000046,0x000003d4,0x000003d3,0x00050081,0x00000046,0x000003d5,
+	0x000003d4,0x000003d2,0x00050041,0x00000074,0x000003d6,0x00000346,0x00000082,0x0003003e,
+	0x000003d6,0x000003d5,0x00050041,0x00000019,0x000003d7,0x00000336,0x00000024,0x0004003d,
+	0x00000006,0x000003d8,0x000003d7,0x000500aa,0x00000052,0x000003d9,0x000003d8,0x00000018,
+	0x000300f7,0x000003dc,0x00000000,0x000400fa,0x000003d9,0x000003db,0x000003de,0x000200f8,
+	0x000003db,0x0004003d,0x00000006,0x000003dd,0x00000347,0x0003003e,0x000003da,0x000003dd,
+	0x000200f9,0x000003dc,0x000200f8,0x000003de,0x0004003d,0x00000006,0x000003df,0x00000347,
+	0x00050041,0x00000021,0x000003e0,0x0000001e,0x0000005d,0x0004003d,0x00000006,0x000003e1,
+	0x000003e0,0x00050080,0x00000006,0x000003e2,0x000003df,0x000003e1,0x0003003e,0x000003da,
+	0x000003e2,0x000200f9,0x000003dc,0x000200f8,0x000003dc,0x0004003d,0x00000006,0x000003e3,
+	0x000003da,0x0003003e,0x00000347,0x000003e3,0x0004003d,0x00000006,0x000003e4,0x00000347,
+	0x00060041,0x00000070,0x000003e5,0x00000363,0x0000005d,0x000003e4,0x0004003d,0x00000006,
+	0x000003e6,0x000003e5,0x0006000c,0x00000046,0x000003e7,0x00000001,0x00000040,0x000003e6,
+	0x00050041,0x00000074,0x000003e8,0x0000035f,0x0000005d,0x0003003e,0x000003e8,0x000003e7,
+	0x0004003d,0x00000006,0x000003e9,0x00000347,0x00050080,0x00000006,0x000003ea,0x000003e9,
+	0x00000024,0x00060041,0x00000070,0x000003eb,0x00000363,0x0000005d,0x000003ea,0x0004003d,
+	0x00000006,0x000003ec,0x000003eb,0x0006000c,0x00000046,0x000003ed,0x00000001,0x00000040,
+	0x000003ec,0x00050041,0x00000074,0x000003ee,0x0000035f,0x0000003e,0x0003003e,0x000003ee,
+	0x000003ed,0x0004003d,0x00000006,0x000003ef,0x00000347,0x00050080,0x00000006,0x000003f0,
+	0x000003ef,0x0000002a,0x00060041,0x00000070,0x000003f1,0x00000363,0x0000005d,0x000003f0,
+	0x0004003d,0x00000006,0x000003f2,0x000003f1,0x0006000c,0x00000046,0x000003f3,0x00000001,
+	0x00000040,0x000003f2,0x00050041,0x00000074,0x000003f4,0x0000035f,0x00000065,0x0003003e,
+	0x000003f4,0x000003f3,0x0004003d,0x00000006,0x000003f5,0x00000347,0x00050080,0x00000006,
+	0x000003f6,0x000003f5,0x00000084,0x00060041,0x00000070,0x000003f7,0x00000363,0x0000005d,
+	0x000003f6,0x0004003d,0x00000006,0x000003f8,0x000003f7,0x0006000c,0x00000046,0x000003f9,
+	0x00000001,0x00000040,0x000003f8,0x00050041,0x00000074,0x000003fa,0x0000035f,0x00000082,
+	0x0003003e,0x000003fa,0x000003f9,0x00050041,0x00000074,0x000003fb,0x0000035f,0x0000005d,
+	0x0004003d,0x00000046,0x000003fc,0x000003fb,0x0005008e,0x00000046,0x000003fd,0x000003fc,
+	0x0000010e,0x00050041,0x00000074,0x000003fe,0x00000346,0x0000005d,0x0004003d,0x00000046,
+	0x000003ff,0x000003fe,0x00050081,0x00000046,0x00000400,0x000003ff,0x000003fd,0x00050041,
+	0x00000074,0x00000401,0x00000346,0x0000005d,0x0003003e,0x00000401,0x00000400,0x00050041,
+	0x00000074,0x00000402,0x0000035f,0x0000003e,0x0004003d,0x00000046,0x00000403,0x00000402,
+	0x0005008e,0x00000046,0x00000404,0x00000403,0x0000010e,0x00050041,0x00000074,0x00000405,
+	0x00000346,0x0000003e,0x0004003d,0x00000046,0x00000406,0x00000405,0x00050081,0x00000046,
+	0x00000407,0x00000406,0x00000404,0x00050041,0x00000074,0x00000408,0x00000346,0x0000003e,
+	0x0003003e,0x00000408,0x00000407,0x00050041,0x00000074,0x00000409,0x0000035f,0x00000065,
+	0x0004003d,0x00000046,0x0000040a,0x00000409,0x0005008e,0x00000046,0x0000040b,0x0000040a,
+	0x0000010e,0x00050041,0x00000074,0x0000040c,0x00000346,0x00000065,0x0004003d,0x00000046,
+	0x0000040d,0x0000040c,0x00050081,0x00000046,0x0000040e,0x0000040d,0x0000040b,0x00050041,
+	0x00000074,0x0000040f,0x00000346,0x00000065,0x0003003e,0x0000040f,0x0000040e,0x00050041,
+	0x00000074,0x00000410,0x0000035f,0x00000082,0x0004003d,0x00000046,0x00000411,0x00000410,
+	0x0005008e,0x00000046,0x00000412,0x00000411,0x0000010e,0x00050041,0x00000074,0x00000413,
+	0x00000346,0x00000082,0x0004003d,0x00000046,0x00000414,0x00000413,0x00050081,0x00000046,
+	0x00000415,0x00000414,0x00000412,0x00050041,0x00000074,0x00000416,0x00000346,0x00000082,
+	0x0003003e,0x00000416,0x00000415,0x00050041,0x00000021,0x00000417,0x0000001e,0x0000005d,
+	0x0004003d,0x00000006,0x00000418,0x00000417,0x0004003d,0x00000006,0x00000419,0x00000347,
+	0x00050080,0x00000006,0x0000041a,0x00000419,0x00000418,0x0003003e,0x00000347,0x0000041a,
+	0x0004003d,0x00000006,0x0000041b,0x00000347,0x00060041,0x00000070,0x0000041c,0x00000363,
+	0x0000005d,0x0000041b,0x0004003d,0x00000006,0x0000041d,0x0000041c,0x0006000c,0x00000046,
+	0x0000041e,0x00000001,0x00000040,0x0000041d,0x00050041,0x00000074,0x0000041f,0x0000035f,
+	0x0000005d,0x0003003e,0x0000041f,0x0000041e,0x0004003d,0x00000006,0x00000420,0x00000347,
+	0x00050080,0x00000006,0x00000421,0x00000420,0x00000024,0x00060041,0x00000070,0x00000422,
+	0x00000363,0x0000005d,0x00000421,0x0004003d,0x00000006,0x00000423,0x00000422,0x0006000c,
+	0x00000046,0x00000424,0x00000001,0x00000040,0x00000423,0x00050041,0x00000074,0x00000425,
+	0x0000035f,0x0000003e,0x0003003e,0x00000425,0x00000424,0x0004003d,0x00000006,0x00000426,
+	0x00000347,0x00050080,0x00000006,0x00000427,0x00000426,0x0000002a,0x00060041,0x00000070,
+	0x00000428,0x00000363,0x0000005d,0x00000427,0x0004003d,0x00000006,0x00000429,0x00000428,
+	0x0006000c,0x00000046,0x0000042a,0x00000001,0x00000040,0x00000429,0x00050041,0x00000074,
+	0x0000042b,0x0000035f,0x00000065,0x0003003e,0x0000042b,0x0000042a,0x0004003d,0x00000006,
+	0x0000042c,0x00000347,0x00050080,0x00000006,0x0000042d,0x0000042c,0x00000084,0x00060041,
+	0x00000070,0x0000042e,0x00000363,0x0000005d,0x0000042d,0x0004003d,0x00000006,0x0000042f,
+	0x0000042e,0x0006000c,0x00000046,0x00000430,0x00000001,0x00000040,0x0000042f,0x00050041,
+	0x00000074,0x00000431,0x0000035f,0x00000082,0x0003003e,0x00000431,0x00000430,0x00050041,
+	0x00000074,0x00000432,0x0000035f,0x0000005d,0x0004003d,0x00000046,0x00000433,0x00000432,
+	0x0005008e,0x00000046,0x00000434,0x00000433,0x000000cd,0x00050041,0x00000074,0x00000435,
+	0x00000346,0x0000005d,0x0004003d,0x00000046,0x00000436,0x00000435,0x00050081,0x00000046,
+	0x00000437,0x00000436,0x00000434,0x00050041,0x00000074,0x00000438,0x00000346,0x0000005d,
+	0x0003003e,0x00000438,0x00000437,0x00050041,0x00000074,0x00000439,0x0000035f,0x0000003e,
+	0x0004003d,0x00000046,0x0000043a,0x00000439,0x0005008e,0x00000046,0x0000043b,0x0000043a,
+	0x000000cd,0x00050041,0x00000074,0x0000043c,0x00000346,0x0000003e,0x0004003d,0x00000046,
+	0x0000043d,0x0000043c,0x00050081,0x00000046,0x0000043e,0x0000043d,0x0000043b,0x00050041,
+	0x00000074,0x0000043f,0x00000346,0x0000003e,0x0003003e,0x0000043f,0x0000043e,0x00050041,
+	0x00000074,0x00000440,0x0000035f,0x00000065,0x0004003d,0x00000046,0x00000441,0x00000440,
+	0x0005008e,0x00000046,0x00000442,0x00000441,0x000000cd,0x00050041,0x00000074,0x00000443,
+	0x00000346,0x00000065,0x0004003d,0x00000046,0x00000444,0x00000443,0x00050081,0x00000046,
+	0x00000445,0x00000444,0x00000442,0x00050041,0x00000074,0x00000446,0x00000346,0x00000065,
+	0x0003003e,0x00000446,0x00000445,0x00050041,0x00000074,0x00000447,0x0000035f,0x00000082,
+	0x0004003d,0x00000046,0x00000448,0x00000447,0x0005008e,0x00000046,0x00000449,0x00000448,
+	0x000000cd,0x00050041,0x00000074,0x0000044a,0x00000346,0x00000082,0x0004003d,0x00000046,
+	0x0000044b,0x0000044a,0x00050081,0x00000046,0x0000044c,0x0000044b,0x00000449,0x00050041,
+	0x00000074,0x0000044d,0x00000346,0x00000082,0x0003003e,0x0000044d,0x0000044c,0x00050041,
+	0x00000021,0x0000044e,0x0000001e,0x0000005d,0x0004003d,0x00000006,0x0000044f,0x0000044e,
+	0x0004003d,0x00000006,0x00000450,0x00000347,0x00050080,0x00000006,0x00000451,0x00000450,
+	0x0000044f,0x0003003e,0x00000347,0x00000451,0x0004003d,0x00000006,0x00000452,0x00000347,
+	0x00060041,0x00000070,0x00000453,0x00000363,0x0000005d,0x00000452,0x0004003d,0x00000006,
+	0x00000454,0x00000453,0x0006000c,0x00000046,0x00000455,0x00000001,0x00000040,0x00000454,
+	0x00050041,0x00000074,0x00000456,0x0000035f,0x0000005d,0x0003003e,0x00000456,0x00000455,
+	0x0004003d,0x00000006,0x00000457,0x00000347,0x00050080,0x00000006,0x00000458,0x00000457,
+	0x00000024,0x00060041,0x00000070,0x00000459,0x00000363,0x0000005d,0x00000458,0x0004003d,
+	0x00000006,0x0000045a,0x00000459,0x0006000c,0x00000046,0x0000045b,0x00000001,0x00000040,
+	0x0000045a,0x00050041,0x00000074,0x0000045c,0x0000035f,0x0000003e,0x0003003e,0x0000045c,
+	0x0000045b,0x0004003d,0x00000006,0x0000045d,0x00000347,0x00050080,0x00000006,0x0000045e,
+	0x0000045d,0x0000002a,0x00060041,0x00000070,0x0000045f,0x00000363,0x0000005d,0x0000045e,
+	0x0004003d,0x00000006,0x00000460,0x0000045f,0x0006000c,0x00000046,0x00000461,0x00000001,
+	0x00000040,0x00000460,0x00050041,0x00000074,0x00000462,0x0000035f,0x00000065,0x0003003e,
+	0x00000462,0x00000461,0x0004003d,0x00000006,0x00000463,0x00000347,0x00050080,0x00000006,
+	0x00000464,0x00000463,0x00000084,0x00060041,0x00000070,0x00000465,0x00000363,0x0000005d,
+	0x00000464,0x0004003d,0x00000006,0x00000466,0x00000465,0x0006000c,0x00000046,0x00000467,
+	0x00000001,0x00000040,0x00000466,0x00050041,0x00000074,0x00000468,0x0000035f,0x00000082,
+	0x0003003e,0x00000468,0x00000467,0x00050041,0x00000074,0x00000469,0x0000035f,0x0000005d,
+	0x0004003d,0x00000046,0x0000046a,0x00000469,0x0005008e,0x00000046,0x0000046b,0x0000046a,
+	0x0000008c,0x00050041,0x00000074,0x0000046c,0x00000346,0x0000005d,0x0004003d,0x00000046,
+	0x0000046d,0x0000046c,0x00050081,0x00000046,0x0000046e,0x0000046d,0x0000046b,0x00050041,
+	0x00000074,0x0000046f,0x00000346,0x0000005d,0x0003003e,0x0000046f,0x0000046e,0x00050041,
+	0x00000074,0x00000470,0x0000035f,0x0000003e,0x0004003d,0x00000046,0x00000471,0x00000470,
+	0x0005008e,0x00000046,0x00000472,0x00000471,0x0000008c,0x00050041,0x00000074,0x00000473,
+	0x00000346,0x0000003e,0x0004003d,0x00000046,0x00000474,0x00000473,0x00050081,0x00000046,
+	0x00000475,0x00000474,0x00000472,0x00050041,0x00000074,0x00000476,0x00000346,0x0000003e,
+	0x0003003e,0x00000476,0x00000475,0x00050041,0x00000074,0x00000477,0x0000035f,0x00000065,
+	0x0004003d,0x00000046,0x00000478,0x00000477,0x0005008e,0x00000046,0x00000479,0x00000478,
+	0x0000008c,0x00050041,0x00000074,0x0000047a,0x00000346,0x00000065,0x0004003d,0x00000046,
+	0x0000047b,0x0000047a,0x00050081,0x00000046,0x0000047c,0x0000047b,0x00000479,0x00050041,
+	0x00000074,0x0000047d,0x00000346,0x00000065,0x0003003e,0x0000047d,0x0000047c,0x00050041,
+	0x00000074,0x0000047e,0x0000035f,0x00000082,0x0004003d,0x00000046,0x0000047f,0x0000047e,
+	0x0005008e,0x00000046,0x00000480,0x0000047f,0x0000008c,0x00050041,0x00000074,0x00000481,
+	0x00000346,0x00000082,0x0004003d,0x00000046,0x00000482,0x00000481,0x00050081,0x00000046,
+	0x00000483,0x00000482,0x00000480,0x00050041,0x00000074,0x00000484,0x00000346,0x00000082,
+	0x0003003e,0x00000484,0x00000483,0x00050041,0x00000019,0x00000485,0x00000336,0x00000018,
+	0x0004003d,0x00000006,0x00000486,0x00000485,0x000500aa,0x00000052,0x00000487,0x00000486,
+	0x00000018,0x000300f7,0x0000048a,0x00000000,0x000400fa,0x00000487,0x00000489,0x00000492,
+	0x000200f8,0x00000489,0x00050041,0x00000074,0x0000048b,0x00000346,0x0000003e,0x0004003d,
+	0x00000046,0x0000048c,0x0000048b,0x00050051,0x00000045,0x0000048d,0x0000048c,0x00000000,
+	0x00050051,0x00000045,0x0000048e,0x0000048c,0x00000001,0x00050051,0x00000045,0x0000048f,
+	0x0000048c,0x00000002,0x00050051,0x00000045,0x00000490,0x0000048c,0x00000003,0x00070050,
+	0x00000046,0x00000491,0x0000048d,0x0000048e,0x0000048f,0x00000490,0x0003003e,0x00000488,
+	0x00000491,0x000200f9,0x0000048a,0x000200f8,0x00000492,0x00050041,0x00000074,0x00000493,
+	0x00000346,0x0000005d,0x0004003d,0x00000046,0x00000494,0x00000493,0x0003003e,0x00000488,
+	0x00000494,0x000200f9,0x0000048a,0x000200f8,0x0000048a,0x0004003d,0x00000046,0x00000495,
+	0x00000488,0x00050041,0x00000074,0x00000496,0x00000346,0x0000005d,0x0003003e,0x00000496,
+	0x00000495,0x00050041,0x00000019,0x00000497,0x00000336,0x00000018,0x0004003d,0x00000006,
+	0x00000498,0x00000497,0x00050041,0x00000021,0x00000499,0x0000001e,0x00000020,0x0004003d,
+	0x00000006,0x0000049a,0x00000499,0x00050082,0x00000006,0x0000049b,0x0000049a,0x0000002a,
+	0x000500aa,0x00000052,0x0000049c,0x00000498,0x0000049b,0x000300f7,0x0000049f,0x00000000,
+	0x000400fa,0x0000049c,0x0000049e,0x000004a7,0x000200f8,0x0000049e,0x00050041,0x00000074,
+	0x000004a0,0x00000346,0x00000065,0x0004003d,0x00000046,0x000004a1,0x000004a0,0x00050051,
+	0x00000045,0x000004a2,0x000004a1,0x00000000,0x00050051,0x00000045,0x000004a3,0x000004a1,
+	0x00000001,0x00050051,0x00000045,0x000004a4,0x000004a1,0x00000002,0x00050051,0x00000045,
+	0x000004a5,0x000004a1,0x00000003,0x00070050,0x00000046,0x000004a6,0x000004a2,0x000004a3,
+	0x000004a4,0x000004a5,0x0003003e,0x0000049d,0x000004a6,0x000200f9,0x0000049f,0x000200f8,
+	0x000004a7,0x00050041,0x00000074,0x000004a8,0x00000346,0x00000082,0x0004003d,0x00000046,
+	0x000004a9,0x000004a8,0x0003003e,0x0000049d,0x000004a9,0x000200f9,0x0000049f,0x000200f8,
+	0x0000049f,0x0004003d,0x00000046,0x000004aa,0x0000049d,0x00050041,0x00000074,0x000004ab,
+	0x00000346,0x00000082,0x0003003e,0x000004ab,0x000004aa,0x00060041,0x0000025f,0x000004ad,
+	0x00000346,0x0000005d,0x00000018,0x0004003d,0x00000045,0x000004ae,0x000004ad,0x00060041,
+	0x0000025f,0x000004af,0x00000346,0x0000005d,0x00000024,0x0004003d,0x00000045,0x000004b0,
+	0x000004af,0x00060041,0x0000025f,0x000004b1,0x00000346,0x0000003e,0x00000018,0x0004003d,
+	0x00000045,0x000004b2,0x000004b1,0x00060041,0x0000025f,0x000004b3,0x00000346,0x0000003e,
+	0x00000024,0x0004003d,0x00000045,0x000004b4,0x000004b3,0x00070050,0x00000046,0x000004b5,
+	0x000004ae,0x000004b0,0x000004b2,0x000004b4,0x0005008e,0x00000046,0x000004b6,0x000004b5,
+	0x0000008c,0x00060041,0x0000025f,0x000004b7,0x00000346,0x0000005d,0x0000002a,0x0004003d,
+	0x00000045,0x000004b8,0x000004b7,0x00060041,0x0000025f,0x000004b9,0x00000346,0x0000005d,
+	0x00000084,0x0004003d,0x00000045,0x000004ba,0x000004b9,0x00060041,0x0000025f,0x000004bb,
+	0x00000346,0x0000003e,0x0000002a,0x0004003d,0x00000045,0x000004bc,0x000004bb,0x00060041,
+	0x0000025f,0x000004bd,0x00000346,0x0000003e,0x00000084,0x0004003d,0x00000045,0x000004be,
+	0x000004bd,0x00070050,0x00000046,0x000004bf,0x000004b8,0x000004ba,0x000004bc,0x000004be,
+	0x0005008e,0x00000046,0x000004c0,0x000004bf,0x000000cd,0x00050081,0x00000046,0x000004c1,
+	0x000004b6,0x000004c0,0x00060041,0x0000025f,0x000004c2,0x00000346,0x0000003e,0x00000018,
+	0x0004003d,0x00000045,0x000004c3,0x000004c2,0x00060041,0x0000025f,0x000004c4,0x00000346,
+	0x0000003e,0x00000024,0x0004003d,0x00000045,0x000004c5,0x000004c4,0x00060041,0x0000025f,
+	0x000004c6,0x00000346,0x00000065,0x00000018,0x0004003d,0x00000045,0x000004c7,0x000004c6,
+	0x00060041,0x0000025f,0x000004c8,0x00000346,0x00000065,0x00000024,0x0004003d,0x00000045,
+	0x000004c9,0x000004c8,0x00070050,0x00000046,0x000004ca,0x000004c3,0x000004c5,0x000004c7,
+	0x000004c9,0x0005008e,0x00000046,0x000004cb,0x000004ca,0x0000010e,0x00050081,0x00000046,
+	0x000004cc,0x000004c1,0x000004cb,0x00060041,0x0000025f,0x000004cd,0x00000346,0x0000003e,
+	0x0000002a,0x0004003d,0x00000045,0x000004ce,0x000004cd,0x00060041,0x0000025f,0x000004cf,
+	0x00000346,0x0000003e,0x00000084,0x0004003d,0x00000045,0x000004d0,0x000004cf,0x00060041,
+	0x0000025f,0x000004d1,0x00000346,0x00000065,0x0000002a,0x0004003d,0x00000045,0x000004d2,
+	0x000004d1,0x00060041,0x0000025f,0x000004d3,0x00000346,0x00000065,0x00000084,0x0004003d,
+	0x00000045,0x000004d4,0x000004d3,0x00070050,0x00000046,0x000004d5,0x000004ce,0x000004d0,
+	0x000004d2,0x000004d4,0x0005008e,0x00000046,0x000004d6,0x000004d5,0x000000cd,0x00050081,
+	0x00000046,0x000004d7,0x000004cc,0x000004d6,0x00060041,0x0000025f,0x000004d8,0x00000346,
+	0x00000065,0x00000018,0x0004003d,0x00000045,0x000004d9,0x000004d8,0x00060041,0x0000025f,
+	0x000004da,0x00000346,0x00000065,0x00000024,0x0004003d,0x00000045,0x000004db,0x000004da,
+	0x00060041,0x0000025f,0x000004dc,0x00000346,0x00000082,0x00000018,0x0004003d,0x00000045,
+	0x000004dd,0x000004dc,0x00060041,0x0000025f,0x000004de,0x00000346,0x00000082,0x00000024,
+	0x0004003d,0x00000045,0x000004df,0x000004de,0x00070050,0x00000046,0x000004e0,0x000004d9,
+	0x000004db,0x000004dd,0x000004df,0x0005008e,0x00000046,0x000004e1,0x000004e0,0x0000008c,
+	0x00050081,0x00000046,0x000004e2,0x000004d7,0x000004e1,0x0003003e,0x000004ac,0x000004e2,
+	0x0004003d,0x00000046,0x000004e3,0x000004ac,0x00070050,0x00000046,0x000004e4,0x0000004b,
+	0x0000004b,0x0000004b,0x0000004b,0x00070050,0x00000046,0x000004e5,0x00000307,0x00000307,
+	0x00000307,0x00000307,0x0008000c,0x00000046,0x000004e6,0x00000001,0x0000002b,0x000004e3,
+	0x000004e4,0x000004e5,0x0003003e,0x000004ac,0x000004e6,0x00050041,0x00000019,0x000004e7,
+	0x0000000f,0x00000018,0x0004003d,0x00000006,0x000004e8,0x000004e7,0x00050041,0x00000021,
+	0x000004e9,0x0000001e,0x00000082,0x0004003d,0x00000006,0x000004ea,0x000004e9,0x00050082,
+	0x00000006,0x000004eb,0x000004ea,0x00000024,0x0008000c,0x00000006,0x000004ec,0x00000001,
+	0x0000002c,0x000004e8,0x00000018,0x000004eb,0x00050041,0x00000019,0x000004ed,0x0000000f,
+	0x00000018,0x0003003e,0x000004ed,0x000004ec,0x00050041,0x00000019,0x000004f2,0x0000000f,
+	0x00000024,0x0004003d,0x00000006,0x000004f3,0x000004f2,0x00050041,0x00000021,0x000004f4,
+	0x0000001e,0x00000082,0x0004003d,0x00000006,0x000004f5,0x000004f4,0x00050084,0x00000006,
+	0x000004f6,0x000004f3,0x000004f5,0x00050041,0x00000019,0x000004f7,0x0000000f,0x00000018,
+	0x0004003d,0x00000006,0x000004f8,0x000004f7,0x00050080,0x00000006,0x000004f9,0x000004f6,
+	0x000004f8,0x0004003d,0x00000046,0x000004fa,0x000004ac,0x0006000c,0x00000006,0x000004fb,
+	0x00000001,0x00000037,0x000004fa,0x00060041,0x00000070,0x000004fc,0x000004f1,0x0000005d,
+	0x000004f9,0x0003003e,0x000004fc,0x000004fb,0x000100fd,0x00010038
diff --git a/shaders/spv/shader_geomap.comp b/shaders/spv/shader_geomap.comp
new file mode 100644
index 0000000..f92dcb4
--- /dev/null
+++ b/shaders/spv/shader_geomap.comp
@@ -0,0 +1,238 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBufY {
+    uint data[];
+} in_buf_y;
+
+layout (binding = 1) readonly buffer InBufUV {
+    uint data[];
+} in_buf_uv;
+
+layout (binding = 2) writeonly buffer OutBufY {
+    uint data[];
+} out_buf_y;
+
+layout (binding = 3) writeonly buffer OutBufUV {
+    uint data[];
+} out_buf_uv;
+
+layout (binding = 4) readonly buffer GeoMapTable {
+    vec2 data[];
+} lut;
+
+layout (push_constant) uniform PushConsts {
+    uint in_img_width;
+    uint in_img_height;
+    uint out_img_width;
+    uint out_img_height;
+    uint lut_width;
+    uint lut_height;
+    float lut_step[4];
+    float lut_std_step[2];
+} prop;
+
+#define UNIT_SIZE 4u
+
+#define unpack_unorm_y(index) \
+    { \
+        vec4 value = unpackUnorm4x8 (in_buf_y.data[index00[index]]); \
+        out_y00[index] = value[x00_fract[index]]; \
+        value = unpackUnorm4x8 (in_buf_y.data[index01[index]]); \
+        out_y01[index] = value[x01_fract[index]]; \
+        value = unpackUnorm4x8 (in_buf_y.data[index10[index]]); \
+        out_y10[index] = value[x10_fract[index]]; \
+        value = unpackUnorm4x8 (in_buf_y.data[index11[index]]); \
+        out_y11[index] = value[x11_fract[index]]; \
+    }
+
+void geomap_y (vec4 lut_x, vec4 lut_y, out vec4 in_img_x, out vec4 in_img_y, out bvec4 out_bound, out uint out_data);
+void geomap_uv (vec2 in_uv_x, vec2 in_uv_y, bvec4 out_bound_uv, out uint out_data);
+
+void main ()
+{
+    uint g_x = gl_GlobalInvocationID.x;
+    uint g_y = gl_GlobalInvocationID.y * 2u;
+
+    vec2 cent = (vec2 (prop.out_img_width, prop.out_img_height) - 1.0f) / 2.0f;
+    vec2 step = g_x < uint (cent.x) ? vec2 (prop.lut_step[0], prop.lut_step[1]) :
+                                      vec2 (prop.lut_step[2], prop.lut_step[3]);
+
+    vec2 start = (vec2 (g_x, g_y) - cent) * step + cent * vec2 (prop.lut_std_step[0], prop.lut_std_step[1]);
+    vec4 lut_x = start.x * float (UNIT_SIZE) + vec4 (0.0f, step.x, step.x * 2.0f, step.x * 3.0f);
+    vec4 lut_y = start.yyyy;
+    lut_x = clamp (lut_x, 0.0f, float (prop.lut_width) - 1.0f);
+    lut_y = clamp (lut_y, 0.0f, float (prop.lut_height) - 1.0f - step.y);
+
+    uint out_data;
+    vec4 in_img_x, in_img_y;
+    bvec4 out_bound;
+    geomap_y (lut_x, lut_y, in_img_x, in_img_y, out_bound, out_data);
+    out_buf_y.data[g_y * prop.out_img_width + g_x] = out_data;
+
+    bvec4 out_bound_uv = out_bound.xxzz;
+    if (all (out_bound_uv)) {
+        out_data = packUnorm4x8 (vec4 (0.5f));
+    } else {
+        vec2 in_uv_x = in_img_x.xz;
+        vec2 in_uv_y = in_img_y.xz / 2.0f;
+        in_uv_y = clamp (in_uv_y, 0.0f, float (prop.in_img_height / 2u - 1u));
+        geomap_uv (in_uv_x, in_uv_y, out_bound_uv, out_data);
+    }
+    out_buf_uv.data[g_y / 2u * prop.out_img_width + g_x] = out_data;
+
+    lut_y += step.y;
+    geomap_y (lut_x, lut_y, in_img_x, in_img_y, out_bound, out_data);
+    out_buf_y.data[(g_y + 1u) * prop.out_img_width + g_x] = out_data;
+}
+
+void geomap_y (vec4 lut_x, vec4 lut_y, out vec4 in_img_x, out vec4 in_img_y, out bvec4 out_bound, out uint out_data)
+{
+    uvec4 x00 = uvec4 (lut_x);
+    uvec4 y00 = uvec4 (lut_y);
+    uvec4 x01 = x00 + 1u;
+    uvec4 y01 = y00;
+    uvec4 x10 = x00;
+    uvec4 y10 = y00 + 1u;
+    uvec4 x11 = x01;
+    uvec4 y11 = y10;
+
+    vec4 fract_x = fract (lut_x);
+    vec4 fract_y = fract (lut_y);
+    vec4 weight00 = (1.0f - fract_x) * (1.0f - fract_y);
+    vec4 weight01 = fract_x * (1.0f - fract_y);
+    vec4 weight10 = (1.0f - fract_x) * fract_y;
+    vec4 weight11 = fract_x * fract_y;
+
+    uvec4 index00 = y00 * prop.lut_width + x00;
+    uvec4 index01 = y01 * prop.lut_width + x01;
+    uvec4 index10 = y10 * prop.lut_width + x10;
+    uvec4 index11 = y11 * prop.lut_width + x11;
+
+    vec4 in_img_x00, in_img_x01, in_img_x10, in_img_x11;
+    vec4 in_img_y00, in_img_y01, in_img_y10, in_img_y11;
+    for (uint i = 0u; i < UNIT_SIZE; ++i) {
+        vec2 value = lut.data[index00[i]];
+        in_img_x00[i] = value.x;
+        in_img_y00[i] = value.y;
+        value = lut.data[index01[i]];
+        in_img_x01[i] = value.x;
+        in_img_y01[i] = value.y;
+        value = lut.data[index10[i]];
+        in_img_x10[i] = value.x;
+        in_img_y10[i] = value.y;
+        value = lut.data[index11[i]];
+        in_img_x11[i] = value.x;
+        in_img_y11[i] = value.y;
+    }
+    in_img_x = in_img_x00 * weight00 + in_img_x01 * weight01 + in_img_x10 * weight10 + in_img_x11 * weight11;
+    in_img_y = in_img_y00 * weight00 + in_img_y01 * weight01 + in_img_y10 * weight10 + in_img_y11 * weight11;
+
+    for (uint i = 0u; i < UNIT_SIZE; ++i) {
+        out_bound[i] = in_img_x[i] < 0.0f || in_img_x[i] > float (prop.in_img_width * UNIT_SIZE - 1u) ||
+                       in_img_y[i] < 0.0f || in_img_y[i] > float (prop.in_img_height - 1u);
+    }
+    if (all (out_bound)) {
+        out_data = 0u;
+        return;
+    }
+
+    x00 = uvec4 (in_img_x);
+    y00 = uvec4 (in_img_y);
+    x01 = x00 + 1u;
+    y01 = y00;
+    x10 = x00;
+    y10 = y00 + 1u;
+    x11 = x01;
+    y11 = y10;
+
+    fract_x = fract (in_img_x);
+    fract_y = fract (in_img_y);
+    weight00 = (1.0f - fract_x) * (1.0f - fract_y);
+    weight01 = fract_x * (1.0f - fract_y);
+    weight10 = (1.0f - fract_x) * fract_y;
+    weight11 = fract_x * fract_y;
+
+    uvec4 x00_floor = x00 / UNIT_SIZE;
+    uvec4 x01_floor = x01 / UNIT_SIZE;
+    uvec4 x10_floor = x10 / UNIT_SIZE;
+    uvec4 x11_floor = x11 / UNIT_SIZE;
+    uvec4 x00_fract = x00 % UNIT_SIZE;
+    uvec4 x01_fract = x01 % UNIT_SIZE;
+    uvec4 x10_fract = x10 % UNIT_SIZE;
+    uvec4 x11_fract = x11 % UNIT_SIZE;
+
+    index00 = y00 * prop.in_img_width + x00_floor;
+    index01 = y01 * prop.in_img_width + x01_floor;
+    index10 = y10 * prop.in_img_width + x10_floor;
+    index11 = y11 * prop.in_img_width + x11_floor;
+
+    // pixel Y-value
+    vec4 out_y00, out_y01, out_y10, out_y11;
+    unpack_unorm_y (0);
+    unpack_unorm_y (1);
+    unpack_unorm_y (2);
+    unpack_unorm_y (3);
+
+    vec4 inter_y = out_y00 * weight00 + out_y01 * weight01 + out_y10 * weight10 + out_y11 * weight11;
+    out_data = packUnorm4x8 (inter_y * vec4 (not (out_bound)));
+}
+
+void geomap_uv (vec2 in_uv_x, vec2 in_uv_y, bvec4 out_bound_uv, out uint out_data)
+{
+    uvec2 x00 = uvec2 (in_uv_x);
+    uvec2 y00 = uvec2 (in_uv_y);
+    uvec2 x01 = x00 + 1u;
+    uvec2 y01 = y00;
+    uvec2 x10 = x00;
+    uvec2 y10 = y00 + 1u;
+    uvec2 x11 = x01;
+    uvec2 y11 = y10;
+
+    vec2 fract_x = fract (in_uv_x);
+    vec2 fract_y = fract (in_uv_y);
+    vec2 weight00 = (1.0f - fract_x) * (1.0f - fract_y);
+    vec2 weight01 = fract_x * (1.0f - fract_y);
+    vec2 weight10 = (1.0f - fract_x) * fract_y;
+    vec2 weight11 = fract_x * fract_y;
+
+    uvec2 x00_floor = x00 / UNIT_SIZE;
+    uvec2 x01_floor = x01 / UNIT_SIZE;
+    uvec2 x10_floor = x10 / UNIT_SIZE;
+    uvec2 x11_floor = x11 / UNIT_SIZE;
+    uvec2 x00_fract = (x00 % UNIT_SIZE) / 2u;
+    uvec2 x01_fract = (x01 % UNIT_SIZE) / 2u;
+    uvec2 x10_fract = (x10 % UNIT_SIZE) / 2u;
+    uvec2 x11_fract = (x11 % UNIT_SIZE) / 2u;
+
+    uvec2 index00 = y00 * prop.in_img_width + x00_floor;
+    uvec2 index01 = y01 * prop.in_img_width + x01_floor;
+    uvec2 index10 = y10 * prop.in_img_width + x10_floor;
+    uvec2 index11 = y11 * prop.in_img_width + x11_floor;
+
+    // pixel UV-value
+    vec4 out_uv00, out_uv01, out_uv10, out_uv11;
+    vec4 value = unpackUnorm4x8 (in_buf_uv.data[index00.x]);
+    out_uv00.xy = x00_fract.x == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index01.x]);
+    out_uv01.xy = x01_fract.x == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index10.x]);
+    out_uv10.xy = x10_fract.x == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index11.x]);
+    out_uv11.xy = x11_fract.x == 0u ? value.xy : value.zw;
+
+    value = unpackUnorm4x8 (in_buf_uv.data[index00.y]);
+    out_uv00.zw = x00_fract.y == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index01.y]);
+    out_uv01.zw = x01_fract.y == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index10.y]);
+    out_uv10.zw = x10_fract.y == 0u ? value.xy : value.zw;
+    value = unpackUnorm4x8 (in_buf_uv.data[index11.y]);
+    out_uv11.zw = x11_fract.y == 0u ? value.xy : value.zw;
+
+    vec4 inter_uv = out_uv00 * weight00.xxyy + out_uv01 * weight01.xxyy +
+                    out_uv10 * weight10.xxyy + out_uv11 * weight11.xxyy;
+    inter_uv = inter_uv * vec4 (not (out_bound_uv)) + vec4 (out_bound_uv) * 0.5f;
+    out_data = packUnorm4x8 (inter_uv);
+}
diff --git a/shaders/spv/shader_geomap.comp.spv b/shaders/spv/shader_geomap.comp.spv
new file mode 100644
index 0000000..6f822b8
--- /dev/null
+++ b/shaders/spv/shader_geomap.comp.spv
@@ -0,0 +1,847 @@
+	// 7.8.2870
+	0x07230203,0x00010000,0x00080007,0x00000466,0x00000000,0x00020011,0x00000001,0x0006000b,
+	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x00000023,0x00060010,0x00000004,
+	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000001,0x00000136,0x00040005,
+	0x00000004,0x6e69616d,0x00000000,0x000b0005,0x00000015,0x6d6f6567,0x795f7061,0x34667628,
+	0x3466763b,0x3466763b,0x3466763b,0x3462763b,0x3b31753b,0x00000000,0x00040005,0x0000000f,
+	0x5f74756c,0x00000078,0x00040005,0x00000010,0x5f74756c,0x00000079,0x00050005,0x00000011,
+	0x695f6e69,0x785f676d,0x00000000,0x00050005,0x00000012,0x695f6e69,0x795f676d,0x00000000,
+	0x00050005,0x00000013,0x5f74756f,0x6e756f62,0x00000064,0x00050005,0x00000014,0x5f74756f,
+	0x61746164,0x00000000,0x00090005,0x0000001e,0x6d6f6567,0x755f7061,0x66762876,0x66763b32,
+	0x62763b32,0x31753b34,0x0000003b,0x00040005,0x0000001a,0x755f6e69,0x00785f76,0x00040005,
+	0x0000001b,0x755f6e69,0x00795f76,0x00060005,0x0000001c,0x5f74756f,0x6e756f62,0x76755f64,
+	0x00000000,0x00050005,0x0000001d,0x5f74756f,0x61746164,0x00000000,0x00030005,0x00000020,
+	0x00785f67,0x00080005,0x00000023,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,
+	0x00000044,0x00030005,0x00000028,0x00795f67,0x00040005,0x0000002e,0x746e6563,0x00000000,
+	0x00050005,0x00000032,0x68737550,0x736e6f43,0x00007374,0x00070006,0x00000032,0x00000000,
+	0x695f6e69,0x775f676d,0x68746469,0x00000000,0x00070006,0x00000032,0x00000001,0x695f6e69,
+	0x685f676d,0x68676965,0x00000074,0x00070006,0x00000032,0x00000002,0x5f74756f,0x5f676d69,
+	0x74646977,0x00000068,0x00070006,0x00000032,0x00000003,0x5f74756f,0x5f676d69,0x67696568,
+	0x00007468,0x00060006,0x00000032,0x00000004,0x5f74756c,0x74646977,0x00000068,0x00060006,
+	0x00000032,0x00000005,0x5f74756c,0x67696568,0x00007468,0x00060006,0x00000032,0x00000006,
+	0x5f74756c,0x70657473,0x00000000,0x00070006,0x00000032,0x00000007,0x5f74756c,0x5f647473,
+	0x70657473,0x00000000,0x00040005,0x00000034,0x706f7270,0x00000000,0x00040005,0x00000046,
+	0x70657473,0x00000000,0x00040005,0x00000060,0x72617473,0x00000074,0x00040005,0x00000073,
+	0x5f74756c,0x00000078,0x00040005,0x00000085,0x5f74756c,0x00000079,0x00050005,0x0000009d,
+	0x695f6e69,0x785f676d,0x00000000,0x00050005,0x0000009e,0x695f6e69,0x795f676d,0x00000000,
+	0x00050005,0x0000009f,0x5f74756f,0x6e756f62,0x00000064,0x00050005,0x000000a0,0x5f74756f,
+	0x61746164,0x00000000,0x00040005,0x000000a1,0x61726170,0x0000006d,0x00040005,0x000000a3,
+	0x61726170,0x0000006d,0x00040005,0x000000a5,0x61726170,0x0000006d,0x00040005,0x000000a6,
+	0x61726170,0x0000006d,0x00040005,0x000000a7,0x61726170,0x0000006d,0x00040005,0x000000a8,
+	0x61726170,0x0000006d,0x00040005,0x000000af,0x4274754f,0x00596675,0x00050006,0x000000af,
+	0x00000000,0x61746164,0x00000000,0x00050005,0x000000b1,0x5f74756f,0x5f667562,0x00000079,
+	0x00060005,0x000000bb,0x5f74756f,0x6e756f62,0x76755f64,0x00000000,0x00040005,0x000000c6,
+	0x755f6e69,0x00785f76,0x00040005,0x000000c9,0x755f6e69,0x00795f76,0x00040005,0x000000d7,
+	0x61726170,0x0000006d,0x00040005,0x000000d9,0x61726170,0x0000006d,0x00040005,0x000000db,
+	0x61726170,0x0000006d,0x00040005,0x000000dd,0x61726170,0x0000006d,0x00050005,0x000000e1,
+	0x4274754f,0x56556675,0x00000000,0x00050006,0x000000e1,0x00000000,0x61746164,0x00000000,
+	0x00050005,0x000000e3,0x5f74756f,0x5f667562,0x00007675,0x00040005,0x000000f2,0x61726170,
+	0x0000006d,0x00040005,0x000000f4,0x61726170,0x0000006d,0x00040005,0x000000f6,0x61726170,
+	0x0000006d,0x00040005,0x000000f7,0x61726170,0x0000006d,0x00040005,0x000000f8,0x61726170,
+	0x0000006d,0x00040005,0x000000f9,0x61726170,0x0000006d,0x00030005,0x0000010a,0x00303078,
+	0x00030005,0x0000010d,0x00303079,0x00030005,0x00000110,0x00313078,0x00030005,0x00000114,
+	0x00313079,0x00030005,0x00000116,0x00303178,0x00030005,0x00000118,0x00303179,0x00030005,
+	0x0000011c,0x00313178,0x00030005,0x0000011e,0x00313179,0x00040005,0x00000120,0x63617266,
+	0x00785f74,0x00040005,0x00000123,0x63617266,0x00795f74,0x00050005,0x00000126,0x67696577,
+	0x30307468,0x00000000,0x00050005,0x0000012e,0x67696577,0x31307468,0x00000000,0x00050005,
+	0x00000134,0x67696577,0x30317468,0x00000000,0x00050005,0x0000013a,0x67696577,0x31317468,
+	0x00000000,0x00040005,0x0000013e,0x65646e69,0x00303078,0x00040005,0x00000146,0x65646e69,
+	0x00313078,0x00040005,0x0000014e,0x65646e69,0x00303178,0x00040005,0x00000156,0x65646e69,
+	0x00313178,0x00030005,0x0000015e,0x00000069,0x00040005,0x00000166,0x756c6176,0x00000065,
+	0x00050005,0x00000168,0x4d6f6547,0x61547061,0x00656c62,0x00050006,0x00000168,0x00000000,
+	0x61746164,0x00000000,0x00030005,0x0000016a,0x0074756c,0x00050005,0x00000171,0x695f6e69,
+	0x785f676d,0x00003030,0x00050005,0x00000176,0x695f6e69,0x795f676d,0x00003030,0x00050005,
+	0x00000180,0x695f6e69,0x785f676d,0x00003130,0x00050005,0x00000185,0x695f6e69,0x795f676d,
+	0x00003130,0x00050005,0x0000018f,0x695f6e69,0x785f676d,0x00003031,0x00050005,0x00000194,
+	0x695f6e69,0x795f676d,0x00003031,0x00050005,0x0000019e,0x695f6e69,0x785f676d,0x00003131,
+	0x00050005,0x000001a3,0x695f6e69,0x795f676d,0x00003131,0x00030005,0x000001c8,0x00000069,
+	0x00050005,0x00000225,0x5f303078,0x6f6f6c66,0x00000072,0x00050005,0x00000229,0x5f313078,
+	0x6f6f6c66,0x00000072,0x00050005,0x0000022d,0x5f303178,0x6f6f6c66,0x00000072,0x00050005,
+	0x00000231,0x5f313178,0x6f6f6c66,0x00000072,0x00050005,0x00000235,0x5f303078,0x63617266,
+	0x00000074,0x00050005,0x00000239,0x5f313078,0x63617266,0x00000074,0x00050005,0x0000023d,
+	0x5f303178,0x63617266,0x00000074,0x00050005,0x00000241,0x5f313178,0x63617266,0x00000074,
+	0x00040005,0x00000261,0x756c6176,0x00000065,0x00040005,0x00000263,0x75426e49,0x00005966,
+	0x00050006,0x00000263,0x00000000,0x61746164,0x00000000,0x00050005,0x00000265,0x625f6e69,
+	0x795f6675,0x00000000,0x00040005,0x0000026b,0x5f74756f,0x00303079,0x00040005,0x00000276,
+	0x5f74756f,0x00313079,0x00040005,0x00000281,0x5f74756f,0x00303179,0x00040005,0x0000028c,
+	0x5f74756f,0x00313179,0x00040005,0x00000292,0x756c6176,0x00000065,0x00040005,0x000002bb,
+	0x756c6176,0x00000065,0x00040005,0x000002e4,0x756c6176,0x00000065,0x00040005,0x0000030e,
+	0x65746e69,0x00795f72,0x00030005,0x00000328,0x00303078,0x00030005,0x0000032b,0x00303079,
+	0x00030005,0x0000032e,0x00313078,0x00030005,0x00000332,0x00313079,0x00030005,0x00000334,
+	0x00303178,0x00030005,0x00000336,0x00303179,0x00030005,0x0000033a,0x00313178,0x00030005,
+	0x0000033c,0x00313179,0x00040005,0x0000033e,0x63617266,0x00785f74,0x00040005,0x00000341,
+	0x63617266,0x00795f74,0x00050005,0x00000344,0x67696577,0x30307468,0x00000000,0x00050005,
+	0x0000034c,0x67696577,0x31307468,0x00000000,0x00050005,0x00000352,0x67696577,0x30317468,
+	0x00000000,0x00050005,0x00000358,0x67696577,0x31317468,0x00000000,0x00050005,0x0000035c,
+	0x5f303078,0x6f6f6c66,0x00000072,0x00050005,0x00000360,0x5f313078,0x6f6f6c66,0x00000072,
+	0x00050005,0x00000364,0x5f303178,0x6f6f6c66,0x00000072,0x00050005,0x00000368,0x5f313178,
+	0x6f6f6c66,0x00000072,0x00050005,0x0000036c,0x5f303078,0x63617266,0x00000074,0x00050005,
+	0x00000372,0x5f313078,0x63617266,0x00000074,0x00050005,0x00000378,0x5f303178,0x63617266,
+	0x00000074,0x00050005,0x0000037e,0x5f313178,0x63617266,0x00000074,0x00040005,0x00000384,
+	0x65646e69,0x00303078,0x00040005,0x0000038c,0x65646e69,0x00313078,0x00040005,0x00000394,
+	0x65646e69,0x00303178,0x00040005,0x0000039c,0x65646e69,0x00313178,0x00040005,0x000003a4,
+	0x756c6176,0x00000065,0x00040005,0x000003a6,0x75426e49,0x00565566,0x00050006,0x000003a6,
+	0x00000000,0x61746164,0x00000000,0x00050005,0x000003a8,0x625f6e69,0x755f6675,0x00000076,
+	0x00050005,0x000003ae,0x5f74756f,0x30307675,0x00000000,0x00050005,0x000003c2,0x5f74756f,
+	0x31307675,0x00000000,0x00050005,0x000003d6,0x5f74756f,0x30317675,0x00000000,0x00050005,
+	0x000003ea,0x5f74756f,0x31317675,0x00000000,0x00050005,0x00000445,0x65746e69,0x76755f72,
+	0x00000000,0x00040047,0x00000023,0x0000000b,0x0000001c,0x00040047,0x00000030,0x00000006,
+	0x00000004,0x00040047,0x00000031,0x00000006,0x00000004,0x00050048,0x00000032,0x00000000,
+	0x00000023,0x00000000,0x00050048,0x00000032,0x00000001,0x00000023,0x00000004,0x00050048,
+	0x00000032,0x00000002,0x00000023,0x00000008,0x00050048,0x00000032,0x00000003,0x00000023,
+	0x0000000c,0x00050048,0x00000032,0x00000004,0x00000023,0x00000010,0x00050048,0x00000032,
+	0x00000005,0x00000023,0x00000014,0x00050048,0x00000032,0x00000006,0x00000023,0x00000018,
+	0x00050048,0x00000032,0x00000007,0x00000023,0x00000028,0x00030047,0x00000032,0x00000002,
+	0x00040047,0x000000ae,0x00000006,0x00000004,0x00040048,0x000000af,0x00000000,0x00000019,
+	0x00050048,0x000000af,0x00000000,0x00000023,0x00000000,0x00030047,0x000000af,0x00000003,
+	0x00040047,0x000000b1,0x00000022,0x00000000,0x00040047,0x000000b1,0x00000021,0x00000002,
+	0x00040047,0x000000e0,0x00000006,0x00000004,0x00040048,0x000000e1,0x00000000,0x00000019,
+	0x00050048,0x000000e1,0x00000000,0x00000023,0x00000000,0x00030047,0x000000e1,0x00000003,
+	0x00040047,0x000000e3,0x00000022,0x00000000,0x00040047,0x000000e3,0x00000021,0x00000003,
+	0x00040047,0x00000167,0x00000006,0x00000008,0x00040048,0x00000168,0x00000000,0x00000018,
+	0x00050048,0x00000168,0x00000000,0x00000023,0x00000000,0x00030047,0x00000168,0x00000003,
+	0x00040047,0x0000016a,0x00000022,0x00000000,0x00040047,0x0000016a,0x00000021,0x00000004,
+	0x00040047,0x00000262,0x00000006,0x00000004,0x00040048,0x00000263,0x00000000,0x00000018,
+	0x00050048,0x00000263,0x00000000,0x00000023,0x00000000,0x00030047,0x00000263,0x00000003,
+	0x00040047,0x00000265,0x00000022,0x00000000,0x00040047,0x00000265,0x00000021,0x00000000,
+	0x00040047,0x000003a5,0x00000006,0x00000004,0x00040048,0x000003a6,0x00000000,0x00000018,
+	0x00050048,0x000003a6,0x00000000,0x00000023,0x00000000,0x00030047,0x000003a6,0x00000003,
+	0x00040047,0x000003a8,0x00000022,0x00000000,0x00040047,0x000003a8,0x00000021,0x00000001,
+	0x00040047,0x00000465,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,
+	0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,
+	0x00040020,0x00000008,0x00000007,0x00000007,0x00020014,0x00000009,0x00040017,0x0000000a,
+	0x00000009,0x00000004,0x00040020,0x0000000b,0x00000007,0x0000000a,0x00040015,0x0000000c,
+	0x00000020,0x00000000,0x00040020,0x0000000d,0x00000007,0x0000000c,0x00090021,0x0000000e,
+	0x00000002,0x00000008,0x00000008,0x00000008,0x00000008,0x0000000b,0x0000000d,0x00040017,
+	0x00000017,0x00000006,0x00000002,0x00040020,0x00000018,0x00000007,0x00000017,0x00070021,
+	0x00000019,0x00000002,0x00000018,0x00000018,0x0000000b,0x0000000d,0x00040017,0x00000021,
+	0x0000000c,0x00000003,0x00040020,0x00000022,0x00000001,0x00000021,0x0004003b,0x00000022,
+	0x00000023,0x00000001,0x0004002b,0x0000000c,0x00000024,0x00000000,0x00040020,0x00000025,
+	0x00000001,0x0000000c,0x0004002b,0x0000000c,0x00000029,0x00000001,0x0004002b,0x0000000c,
+	0x0000002c,0x00000002,0x0004002b,0x0000000c,0x0000002f,0x00000004,0x0004001c,0x00000030,
+	0x00000006,0x0000002f,0x0004001c,0x00000031,0x00000006,0x0000002c,0x000a001e,0x00000032,
+	0x0000000c,0x0000000c,0x0000000c,0x0000000c,0x0000000c,0x0000000c,0x00000030,0x00000031,
+	0x00040020,0x00000033,0x00000009,0x00000032,0x0004003b,0x00000033,0x00000034,0x00000009,
+	0x00040015,0x00000035,0x00000020,0x00000001,0x0004002b,0x00000035,0x00000036,0x00000002,
+	0x00040020,0x00000037,0x00000009,0x0000000c,0x0004002b,0x00000035,0x0000003b,0x00000003,
+	0x0004002b,0x00000006,0x00000040,0x3f800000,0x0004002b,0x00000006,0x00000043,0x40000000,
+	0x00040020,0x00000048,0x00000007,0x00000006,0x0004002b,0x00000035,0x00000050,0x00000006,
+	0x0004002b,0x00000035,0x00000051,0x00000000,0x00040020,0x00000052,0x00000009,0x00000006,
+	0x0004002b,0x00000035,0x00000055,0x00000001,0x0004002b,0x00000035,0x0000006b,0x00000007,
+	0x0004002b,0x00000006,0x00000076,0x40800000,0x0004002b,0x00000006,0x00000078,0x00000000,
+	0x0004002b,0x00000006,0x00000080,0x40400000,0x0004002b,0x00000035,0x00000089,0x00000004,
+	0x0004002b,0x00000035,0x00000092,0x00000005,0x0003001d,0x000000ae,0x0000000c,0x0003001e,
+	0x000000af,0x000000ae,0x00040020,0x000000b0,0x00000002,0x000000af,0x0004003b,0x000000b0,
+	0x000000b1,0x00000002,0x00040020,0x000000b9,0x00000002,0x0000000c,0x0004002b,0x00000006,
+	0x000000c2,0x3f000000,0x0007002c,0x00000007,0x000000c3,0x000000c2,0x000000c2,0x000000c2,
+	0x000000c2,0x0003001d,0x000000e0,0x0000000c,0x0003001e,0x000000e1,0x000000e0,0x00040020,
+	0x000000e2,0x00000002,0x000000e1,0x0004003b,0x000000e2,0x000000e3,0x00000002,0x00040017,
+	0x00000108,0x0000000c,0x00000004,0x00040020,0x00000109,0x00000007,0x00000108,0x0003001d,
+	0x00000167,0x00000017,0x0003001e,0x00000168,0x00000167,0x00040020,0x00000169,0x00000002,
+	0x00000168,0x0004003b,0x00000169,0x0000016a,0x00000002,0x00040020,0x0000016e,0x00000002,
+	0x00000017,0x00040020,0x000001f6,0x00000007,0x00000009,0x0003001d,0x00000262,0x0000000c,
+	0x0003001e,0x00000263,0x00000262,0x00040020,0x00000264,0x00000002,0x00000263,0x0004003b,
+	0x00000264,0x00000265,0x00000002,0x0004002b,0x0000000c,0x000002e5,0x00000003,0x0007002c,
+	0x00000007,0x00000321,0x00000078,0x00000078,0x00000078,0x00000078,0x0007002c,0x00000007,
+	0x00000322,0x00000040,0x00000040,0x00000040,0x00000040,0x00040017,0x00000326,0x0000000c,
+	0x00000002,0x00040020,0x00000327,0x00000007,0x00000326,0x0003001d,0x000003a5,0x0000000c,
+	0x0003001e,0x000003a6,0x000003a5,0x00040020,0x000003a7,0x00000002,0x000003a6,0x0004003b,
+	0x000003a7,0x000003a8,0x00000002,0x0004002b,0x0000000c,0x00000464,0x00000008,0x0006002c,
+	0x00000021,0x00000465,0x00000464,0x00000464,0x00000029,0x00050036,0x00000002,0x00000004,
+	0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x0000000d,0x00000020,0x00000007,
+	0x0004003b,0x0000000d,0x00000028,0x00000007,0x0004003b,0x00000018,0x0000002e,0x00000007,
+	0x0004003b,0x00000018,0x00000046,0x00000007,0x0004003b,0x00000018,0x0000004d,0x00000007,
+	0x0004003b,0x00000018,0x00000060,0x00000007,0x0004003b,0x00000008,0x00000073,0x00000007,
+	0x0004003b,0x00000008,0x00000085,0x00000007,0x0004003b,0x00000008,0x0000009d,0x00000007,
+	0x0004003b,0x00000008,0x0000009e,0x00000007,0x0004003b,0x0000000b,0x0000009f,0x00000007,
+	0x0004003b,0x0000000d,0x000000a0,0x00000007,0x0004003b,0x00000008,0x000000a1,0x00000007,
+	0x0004003b,0x00000008,0x000000a3,0x00000007,0x0004003b,0x00000008,0x000000a5,0x00000007,
+	0x0004003b,0x00000008,0x000000a6,0x00000007,0x0004003b,0x0000000b,0x000000a7,0x00000007,
+	0x0004003b,0x0000000d,0x000000a8,0x00000007,0x0004003b,0x0000000b,0x000000bb,0x00000007,
+	0x0004003b,0x00000018,0x000000c6,0x00000007,0x0004003b,0x00000018,0x000000c9,0x00000007,
+	0x0004003b,0x00000018,0x000000d7,0x00000007,0x0004003b,0x00000018,0x000000d9,0x00000007,
+	0x0004003b,0x0000000b,0x000000db,0x00000007,0x0004003b,0x0000000d,0x000000dd,0x00000007,
+	0x0004003b,0x00000008,0x000000f2,0x00000007,0x0004003b,0x00000008,0x000000f4,0x00000007,
+	0x0004003b,0x00000008,0x000000f6,0x00000007,0x0004003b,0x00000008,0x000000f7,0x00000007,
+	0x0004003b,0x0000000b,0x000000f8,0x00000007,0x0004003b,0x0000000d,0x000000f9,0x00000007,
+	0x00050041,0x00000025,0x00000026,0x00000023,0x00000024,0x0004003d,0x0000000c,0x00000027,
+	0x00000026,0x0003003e,0x00000020,0x00000027,0x00050041,0x00000025,0x0000002a,0x00000023,
+	0x00000029,0x0004003d,0x0000000c,0x0000002b,0x0000002a,0x00050084,0x0000000c,0x0000002d,
+	0x0000002b,0x0000002c,0x0003003e,0x00000028,0x0000002d,0x00050041,0x00000037,0x00000038,
+	0x00000034,0x00000036,0x0004003d,0x0000000c,0x00000039,0x00000038,0x00040070,0x00000006,
+	0x0000003a,0x00000039,0x00050041,0x00000037,0x0000003c,0x00000034,0x0000003b,0x0004003d,
+	0x0000000c,0x0000003d,0x0000003c,0x00040070,0x00000006,0x0000003e,0x0000003d,0x00050050,
+	0x00000017,0x0000003f,0x0000003a,0x0000003e,0x00050050,0x00000017,0x00000041,0x00000040,
+	0x00000040,0x00050083,0x00000017,0x00000042,0x0000003f,0x00000041,0x00050050,0x00000017,
+	0x00000044,0x00000043,0x00000043,0x00050088,0x00000017,0x00000045,0x00000042,0x00000044,
+	0x0003003e,0x0000002e,0x00000045,0x0004003d,0x0000000c,0x00000047,0x00000020,0x00050041,
+	0x00000048,0x00000049,0x0000002e,0x00000024,0x0004003d,0x00000006,0x0000004a,0x00000049,
+	0x0004006d,0x0000000c,0x0000004b,0x0000004a,0x000500b0,0x00000009,0x0000004c,0x00000047,
+	0x0000004b,0x000300f7,0x0000004f,0x00000000,0x000400fa,0x0000004c,0x0000004e,0x00000059,
+	0x000200f8,0x0000004e,0x00060041,0x00000052,0x00000053,0x00000034,0x00000050,0x00000051,
+	0x0004003d,0x00000006,0x00000054,0x00000053,0x00060041,0x00000052,0x00000056,0x00000034,
+	0x00000050,0x00000055,0x0004003d,0x00000006,0x00000057,0x00000056,0x00050050,0x00000017,
+	0x00000058,0x00000054,0x00000057,0x0003003e,0x0000004d,0x00000058,0x000200f9,0x0000004f,
+	0x000200f8,0x00000059,0x00060041,0x00000052,0x0000005a,0x00000034,0x00000050,0x00000036,
+	0x0004003d,0x00000006,0x0000005b,0x0000005a,0x00060041,0x00000052,0x0000005c,0x00000034,
+	0x00000050,0x0000003b,0x0004003d,0x00000006,0x0000005d,0x0000005c,0x00050050,0x00000017,
+	0x0000005e,0x0000005b,0x0000005d,0x0003003e,0x0000004d,0x0000005e,0x000200f9,0x0000004f,
+	0x000200f8,0x0000004f,0x0004003d,0x00000017,0x0000005f,0x0000004d,0x0003003e,0x00000046,
+	0x0000005f,0x0004003d,0x0000000c,0x00000061,0x00000020,0x00040070,0x00000006,0x00000062,
+	0x00000061,0x0004003d,0x0000000c,0x00000063,0x00000028,0x00040070,0x00000006,0x00000064,
+	0x00000063,0x00050050,0x00000017,0x00000065,0x00000062,0x00000064,0x0004003d,0x00000017,
+	0x00000066,0x0000002e,0x00050083,0x00000017,0x00000067,0x00000065,0x00000066,0x0004003d,
+	0x00000017,0x00000068,0x00000046,0x00050085,0x00000017,0x00000069,0x00000067,0x00000068,
+	0x0004003d,0x00000017,0x0000006a,0x0000002e,0x00060041,0x00000052,0x0000006c,0x00000034,
+	0x0000006b,0x00000051,0x0004003d,0x00000006,0x0000006d,0x0000006c,0x00060041,0x00000052,
+	0x0000006e,0x00000034,0x0000006b,0x00000055,0x0004003d,0x00000006,0x0000006f,0x0000006e,
+	0x00050050,0x00000017,0x00000070,0x0000006d,0x0000006f,0x00050085,0x00000017,0x00000071,
+	0x0000006a,0x00000070,0x00050081,0x00000017,0x00000072,0x00000069,0x00000071,0x0003003e,
+	0x00000060,0x00000072,0x00050041,0x00000048,0x00000074,0x00000060,0x00000024,0x0004003d,
+	0x00000006,0x00000075,0x00000074,0x00050085,0x00000006,0x00000077,0x00000075,0x00000076,
+	0x00050041,0x00000048,0x00000079,0x00000046,0x00000024,0x0004003d,0x00000006,0x0000007a,
+	0x00000079,0x00050041,0x00000048,0x0000007b,0x00000046,0x00000024,0x0004003d,0x00000006,
+	0x0000007c,0x0000007b,0x00050085,0x00000006,0x0000007d,0x0000007c,0x00000043,0x00050041,
+	0x00000048,0x0000007e,0x00000046,0x00000024,0x0004003d,0x00000006,0x0000007f,0x0000007e,
+	0x00050085,0x00000006,0x00000081,0x0000007f,0x00000080,0x00070050,0x00000007,0x00000082,
+	0x00000078,0x0000007a,0x0000007d,0x00000081,0x00070050,0x00000007,0x00000083,0x00000077,
+	0x00000077,0x00000077,0x00000077,0x00050081,0x00000007,0x00000084,0x00000083,0x00000082,
+	0x0003003e,0x00000073,0x00000084,0x0004003d,0x00000017,0x00000086,0x00000060,0x0009004f,
+	0x00000007,0x00000087,0x00000086,0x00000086,0x00000001,0x00000001,0x00000001,0x00000001,
+	0x0003003e,0x00000085,0x00000087,0x0004003d,0x00000007,0x00000088,0x00000073,0x00050041,
+	0x00000037,0x0000008a,0x00000034,0x00000089,0x0004003d,0x0000000c,0x0000008b,0x0000008a,
+	0x00040070,0x00000006,0x0000008c,0x0000008b,0x00050083,0x00000006,0x0000008d,0x0000008c,
+	0x00000040,0x00070050,0x00000007,0x0000008e,0x00000078,0x00000078,0x00000078,0x00000078,
+	0x00070050,0x00000007,0x0000008f,0x0000008d,0x0000008d,0x0000008d,0x0000008d,0x0008000c,
+	0x00000007,0x00000090,0x00000001,0x0000002b,0x00000088,0x0000008e,0x0000008f,0x0003003e,
+	0x00000073,0x00000090,0x0004003d,0x00000007,0x00000091,0x00000085,0x00050041,0x00000037,
+	0x00000093,0x00000034,0x00000092,0x0004003d,0x0000000c,0x00000094,0x00000093,0x00040070,
+	0x00000006,0x00000095,0x00000094,0x00050083,0x00000006,0x00000096,0x00000095,0x00000040,
+	0x00050041,0x00000048,0x00000097,0x00000046,0x00000029,0x0004003d,0x00000006,0x00000098,
+	0x00000097,0x00050083,0x00000006,0x00000099,0x00000096,0x00000098,0x00070050,0x00000007,
+	0x0000009a,0x00000078,0x00000078,0x00000078,0x00000078,0x00070050,0x00000007,0x0000009b,
+	0x00000099,0x00000099,0x00000099,0x00000099,0x0008000c,0x00000007,0x0000009c,0x00000001,
+	0x0000002b,0x00000091,0x0000009a,0x0000009b,0x0003003e,0x00000085,0x0000009c,0x0004003d,
+	0x00000007,0x000000a2,0x00000073,0x0003003e,0x000000a1,0x000000a2,0x0004003d,0x00000007,
+	0x000000a4,0x00000085,0x0003003e,0x000000a3,0x000000a4,0x000a0039,0x00000002,0x000000a9,
+	0x00000015,0x000000a1,0x000000a3,0x000000a5,0x000000a6,0x000000a7,0x000000a8,0x0004003d,
+	0x00000007,0x000000aa,0x000000a5,0x0003003e,0x0000009d,0x000000aa,0x0004003d,0x00000007,
+	0x000000ab,0x000000a6,0x0003003e,0x0000009e,0x000000ab,0x0004003d,0x0000000a,0x000000ac,
+	0x000000a7,0x0003003e,0x0000009f,0x000000ac,0x0004003d,0x0000000c,0x000000ad,0x000000a8,
+	0x0003003e,0x000000a0,0x000000ad,0x0004003d,0x0000000c,0x000000b2,0x00000028,0x00050041,
+	0x00000037,0x000000b3,0x00000034,0x00000036,0x0004003d,0x0000000c,0x000000b4,0x000000b3,
+	0x00050084,0x0000000c,0x000000b5,0x000000b2,0x000000b4,0x0004003d,0x0000000c,0x000000b6,
+	0x00000020,0x00050080,0x0000000c,0x000000b7,0x000000b5,0x000000b6,0x0004003d,0x0000000c,
+	0x000000b8,0x000000a0,0x00060041,0x000000b9,0x000000ba,0x000000b1,0x00000051,0x000000b7,
+	0x0003003e,0x000000ba,0x000000b8,0x0004003d,0x0000000a,0x000000bc,0x0000009f,0x0009004f,
+	0x0000000a,0x000000bd,0x000000bc,0x000000bc,0x00000000,0x00000000,0x00000002,0x00000002,
+	0x0003003e,0x000000bb,0x000000bd,0x0004003d,0x0000000a,0x000000be,0x000000bb,0x0004009b,
+	0x00000009,0x000000bf,0x000000be,0x000300f7,0x000000c1,0x00000000,0x000400fa,0x000000bf,
+	0x000000c0,0x000000c5,0x000200f8,0x000000c0,0x0006000c,0x0000000c,0x000000c4,0x00000001,
+	0x00000037,0x000000c3,0x0003003e,0x000000a0,0x000000c4,0x000200f9,0x000000c1,0x000200f8,
+	0x000000c5,0x0004003d,0x00000007,0x000000c7,0x0000009d,0x0007004f,0x00000017,0x000000c8,
+	0x000000c7,0x000000c7,0x00000000,0x00000002,0x0003003e,0x000000c6,0x000000c8,0x0004003d,
+	0x00000007,0x000000ca,0x0000009e,0x0007004f,0x00000017,0x000000cb,0x000000ca,0x000000ca,
+	0x00000000,0x00000002,0x00050050,0x00000017,0x000000cc,0x00000043,0x00000043,0x00050088,
+	0x00000017,0x000000cd,0x000000cb,0x000000cc,0x0003003e,0x000000c9,0x000000cd,0x0004003d,
+	0x00000017,0x000000ce,0x000000c9,0x00050041,0x00000037,0x000000cf,0x00000034,0x00000055,
+	0x0004003d,0x0000000c,0x000000d0,0x000000cf,0x00050086,0x0000000c,0x000000d1,0x000000d0,
+	0x0000002c,0x00050082,0x0000000c,0x000000d2,0x000000d1,0x00000029,0x00040070,0x00000006,
+	0x000000d3,0x000000d2,0x00050050,0x00000017,0x000000d4,0x00000078,0x00000078,0x00050050,
+	0x00000017,0x000000d5,0x000000d3,0x000000d3,0x0008000c,0x00000017,0x000000d6,0x00000001,
+	0x0000002b,0x000000ce,0x000000d4,0x000000d5,0x0003003e,0x000000c9,0x000000d6,0x0004003d,
+	0x00000017,0x000000d8,0x000000c6,0x0003003e,0x000000d7,0x000000d8,0x0004003d,0x00000017,
+	0x000000da,0x000000c9,0x0003003e,0x000000d9,0x000000da,0x0004003d,0x0000000a,0x000000dc,
+	0x000000bb,0x0003003e,0x000000db,0x000000dc,0x00080039,0x00000002,0x000000de,0x0000001e,
+	0x000000d7,0x000000d9,0x000000db,0x000000dd,0x0004003d,0x0000000c,0x000000df,0x000000dd,
+	0x0003003e,0x000000a0,0x000000df,0x000200f9,0x000000c1,0x000200f8,0x000000c1,0x0004003d,
+	0x0000000c,0x000000e4,0x00000028,0x00050086,0x0000000c,0x000000e5,0x000000e4,0x0000002c,
+	0x00050041,0x00000037,0x000000e6,0x00000034,0x00000036,0x0004003d,0x0000000c,0x000000e7,
+	0x000000e6,0x00050084,0x0000000c,0x000000e8,0x000000e5,0x000000e7,0x0004003d,0x0000000c,
+	0x000000e9,0x00000020,0x00050080,0x0000000c,0x000000ea,0x000000e8,0x000000e9,0x0004003d,
+	0x0000000c,0x000000eb,0x000000a0,0x00060041,0x000000b9,0x000000ec,0x000000e3,0x00000051,
+	0x000000ea,0x0003003e,0x000000ec,0x000000eb,0x00050041,0x00000048,0x000000ed,0x00000046,
+	0x00000029,0x0004003d,0x00000006,0x000000ee,0x000000ed,0x0004003d,0x00000007,0x000000ef,
+	0x00000085,0x00070050,0x00000007,0x000000f0,0x000000ee,0x000000ee,0x000000ee,0x000000ee,
+	0x00050081,0x00000007,0x000000f1,0x000000ef,0x000000f0,0x0003003e,0x00000085,0x000000f1,
+	0x0004003d,0x00000007,0x000000f3,0x00000073,0x0003003e,0x000000f2,0x000000f3,0x0004003d,
+	0x00000007,0x000000f5,0x00000085,0x0003003e,0x000000f4,0x000000f5,0x000a0039,0x00000002,
+	0x000000fa,0x00000015,0x000000f2,0x000000f4,0x000000f6,0x000000f7,0x000000f8,0x000000f9,
+	0x0004003d,0x00000007,0x000000fb,0x000000f6,0x0003003e,0x0000009d,0x000000fb,0x0004003d,
+	0x00000007,0x000000fc,0x000000f7,0x0003003e,0x0000009e,0x000000fc,0x0004003d,0x0000000a,
+	0x000000fd,0x000000f8,0x0003003e,0x0000009f,0x000000fd,0x0004003d,0x0000000c,0x000000fe,
+	0x000000f9,0x0003003e,0x000000a0,0x000000fe,0x0004003d,0x0000000c,0x000000ff,0x00000028,
+	0x00050080,0x0000000c,0x00000100,0x000000ff,0x00000029,0x00050041,0x00000037,0x00000101,
+	0x00000034,0x00000036,0x0004003d,0x0000000c,0x00000102,0x00000101,0x00050084,0x0000000c,
+	0x00000103,0x00000100,0x00000102,0x0004003d,0x0000000c,0x00000104,0x00000020,0x00050080,
+	0x0000000c,0x00000105,0x00000103,0x00000104,0x0004003d,0x0000000c,0x00000106,0x000000a0,
+	0x00060041,0x000000b9,0x00000107,0x000000b1,0x00000051,0x00000105,0x0003003e,0x00000107,
+	0x00000106,0x000100fd,0x00010038,0x00050036,0x00000002,0x00000015,0x00000000,0x0000000e,
+	0x00030037,0x00000008,0x0000000f,0x00030037,0x00000008,0x00000010,0x00030037,0x00000008,
+	0x00000011,0x00030037,0x00000008,0x00000012,0x00030037,0x0000000b,0x00000013,0x00030037,
+	0x0000000d,0x00000014,0x000200f8,0x00000016,0x0004003b,0x00000109,0x0000010a,0x00000007,
+	0x0004003b,0x00000109,0x0000010d,0x00000007,0x0004003b,0x00000109,0x00000110,0x00000007,
+	0x0004003b,0x00000109,0x00000114,0x00000007,0x0004003b,0x00000109,0x00000116,0x00000007,
+	0x0004003b,0x00000109,0x00000118,0x00000007,0x0004003b,0x00000109,0x0000011c,0x00000007,
+	0x0004003b,0x00000109,0x0000011e,0x00000007,0x0004003b,0x00000008,0x00000120,0x00000007,
+	0x0004003b,0x00000008,0x00000123,0x00000007,0x0004003b,0x00000008,0x00000126,0x00000007,
+	0x0004003b,0x00000008,0x0000012e,0x00000007,0x0004003b,0x00000008,0x00000134,0x00000007,
+	0x0004003b,0x00000008,0x0000013a,0x00000007,0x0004003b,0x00000109,0x0000013e,0x00000007,
+	0x0004003b,0x00000109,0x00000146,0x00000007,0x0004003b,0x00000109,0x0000014e,0x00000007,
+	0x0004003b,0x00000109,0x00000156,0x00000007,0x0004003b,0x0000000d,0x0000015e,0x00000007,
+	0x0004003b,0x00000018,0x00000166,0x00000007,0x0004003b,0x00000008,0x00000171,0x00000007,
+	0x0004003b,0x00000008,0x00000176,0x00000007,0x0004003b,0x00000008,0x00000180,0x00000007,
+	0x0004003b,0x00000008,0x00000185,0x00000007,0x0004003b,0x00000008,0x0000018f,0x00000007,
+	0x0004003b,0x00000008,0x00000194,0x00000007,0x0004003b,0x00000008,0x0000019e,0x00000007,
+	0x0004003b,0x00000008,0x000001a3,0x00000007,0x0004003b,0x0000000d,0x000001c8,0x00000007,
+	0x0004003b,0x00000109,0x00000225,0x00000007,0x0004003b,0x00000109,0x00000229,0x00000007,
+	0x0004003b,0x00000109,0x0000022d,0x00000007,0x0004003b,0x00000109,0x00000231,0x00000007,
+	0x0004003b,0x00000109,0x00000235,0x00000007,0x0004003b,0x00000109,0x00000239,0x00000007,
+	0x0004003b,0x00000109,0x0000023d,0x00000007,0x0004003b,0x00000109,0x00000241,0x00000007,
+	0x0004003b,0x00000008,0x00000261,0x00000007,0x0004003b,0x00000008,0x0000026b,0x00000007,
+	0x0004003b,0x00000008,0x00000276,0x00000007,0x0004003b,0x00000008,0x00000281,0x00000007,
+	0x0004003b,0x00000008,0x0000028c,0x00000007,0x0004003b,0x00000008,0x00000292,0x00000007,
+	0x0004003b,0x00000008,0x000002bb,0x00000007,0x0004003b,0x00000008,0x000002e4,0x00000007,
+	0x0004003b,0x00000008,0x0000030e,0x00000007,0x0004003d,0x00000007,0x0000010b,0x0000000f,
+	0x0004006d,0x00000108,0x0000010c,0x0000010b,0x0003003e,0x0000010a,0x0000010c,0x0004003d,
+	0x00000007,0x0000010e,0x00000010,0x0004006d,0x00000108,0x0000010f,0x0000010e,0x0003003e,
+	0x0000010d,0x0000010f,0x0004003d,0x00000108,0x00000111,0x0000010a,0x00070050,0x00000108,
+	0x00000112,0x00000029,0x00000029,0x00000029,0x00000029,0x00050080,0x00000108,0x00000113,
+	0x00000111,0x00000112,0x0003003e,0x00000110,0x00000113,0x0004003d,0x00000108,0x00000115,
+	0x0000010d,0x0003003e,0x00000114,0x00000115,0x0004003d,0x00000108,0x00000117,0x0000010a,
+	0x0003003e,0x00000116,0x00000117,0x0004003d,0x00000108,0x00000119,0x0000010d,0x00070050,
+	0x00000108,0x0000011a,0x00000029,0x00000029,0x00000029,0x00000029,0x00050080,0x00000108,
+	0x0000011b,0x00000119,0x0000011a,0x0003003e,0x00000118,0x0000011b,0x0004003d,0x00000108,
+	0x0000011d,0x00000110,0x0003003e,0x0000011c,0x0000011d,0x0004003d,0x00000108,0x0000011f,
+	0x00000118,0x0003003e,0x0000011e,0x0000011f,0x0004003d,0x00000007,0x00000121,0x0000000f,
+	0x0006000c,0x00000007,0x00000122,0x00000001,0x0000000a,0x00000121,0x0003003e,0x00000120,
+	0x00000122,0x0004003d,0x00000007,0x00000124,0x00000010,0x0006000c,0x00000007,0x00000125,
+	0x00000001,0x0000000a,0x00000124,0x0003003e,0x00000123,0x00000125,0x0004003d,0x00000007,
+	0x00000127,0x00000120,0x00070050,0x00000007,0x00000128,0x00000040,0x00000040,0x00000040,
+	0x00000040,0x00050083,0x00000007,0x00000129,0x00000128,0x00000127,0x0004003d,0x00000007,
+	0x0000012a,0x00000123,0x00070050,0x00000007,0x0000012b,0x00000040,0x00000040,0x00000040,
+	0x00000040,0x00050083,0x00000007,0x0000012c,0x0000012b,0x0000012a,0x00050085,0x00000007,
+	0x0000012d,0x00000129,0x0000012c,0x0003003e,0x00000126,0x0000012d,0x0004003d,0x00000007,
+	0x0000012f,0x00000120,0x0004003d,0x00000007,0x00000130,0x00000123,0x00070050,0x00000007,
+	0x00000131,0x00000040,0x00000040,0x00000040,0x00000040,0x00050083,0x00000007,0x00000132,
+	0x00000131,0x00000130,0x00050085,0x00000007,0x00000133,0x0000012f,0x00000132,0x0003003e,
+	0x0000012e,0x00000133,0x0004003d,0x00000007,0x00000135,0x00000120,0x00070050,0x00000007,
+	0x00000136,0x00000040,0x00000040,0x00000040,0x00000040,0x00050083,0x00000007,0x00000137,
+	0x00000136,0x00000135,0x0004003d,0x00000007,0x00000138,0x00000123,0x00050085,0x00000007,
+	0x00000139,0x00000137,0x00000138,0x0003003e,0x00000134,0x00000139,0x0004003d,0x00000007,
+	0x0000013b,0x00000120,0x0004003d,0x00000007,0x0000013c,0x00000123,0x00050085,0x00000007,
+	0x0000013d,0x0000013b,0x0000013c,0x0003003e,0x0000013a,0x0000013d,0x0004003d,0x00000108,
+	0x0000013f,0x0000010d,0x00050041,0x00000037,0x00000140,0x00000034,0x00000089,0x0004003d,
+	0x0000000c,0x00000141,0x00000140,0x00070050,0x00000108,0x00000142,0x00000141,0x00000141,
+	0x00000141,0x00000141,0x00050084,0x00000108,0x00000143,0x0000013f,0x00000142,0x0004003d,
+	0x00000108,0x00000144,0x0000010a,0x00050080,0x00000108,0x00000145,0x00000143,0x00000144,
+	0x0003003e,0x0000013e,0x00000145,0x0004003d,0x00000108,0x00000147,0x00000114,0x00050041,
+	0x00000037,0x00000148,0x00000034,0x00000089,0x0004003d,0x0000000c,0x00000149,0x00000148,
+	0x00070050,0x00000108,0x0000014a,0x00000149,0x00000149,0x00000149,0x00000149,0x00050084,
+	0x00000108,0x0000014b,0x00000147,0x0000014a,0x0004003d,0x00000108,0x0000014c,0x00000110,
+	0x00050080,0x00000108,0x0000014d,0x0000014b,0x0000014c,0x0003003e,0x00000146,0x0000014d,
+	0x0004003d,0x00000108,0x0000014f,0x00000118,0x00050041,0x00000037,0x00000150,0x00000034,
+	0x00000089,0x0004003d,0x0000000c,0x00000151,0x00000150,0x00070050,0x00000108,0x00000152,
+	0x00000151,0x00000151,0x00000151,0x00000151,0x00050084,0x00000108,0x00000153,0x0000014f,
+	0x00000152,0x0004003d,0x00000108,0x00000154,0x00000116,0x00050080,0x00000108,0x00000155,
+	0x00000153,0x00000154,0x0003003e,0x0000014e,0x00000155,0x0004003d,0x00000108,0x00000157,
+	0x0000011e,0x00050041,0x00000037,0x00000158,0x00000034,0x00000089,0x0004003d,0x0000000c,
+	0x00000159,0x00000158,0x00070050,0x00000108,0x0000015a,0x00000159,0x00000159,0x00000159,
+	0x00000159,0x00050084,0x00000108,0x0000015b,0x00000157,0x0000015a,0x0004003d,0x00000108,
+	0x0000015c,0x0000011c,0x00050080,0x00000108,0x0000015d,0x0000015b,0x0000015c,0x0003003e,
+	0x00000156,0x0000015d,0x0003003e,0x0000015e,0x00000024,0x000200f9,0x0000015f,0x000200f8,
+	0x0000015f,0x000400f6,0x00000161,0x00000162,0x00000000,0x000200f9,0x00000163,0x000200f8,
+	0x00000163,0x0004003d,0x0000000c,0x00000164,0x0000015e,0x000500b0,0x00000009,0x00000165,
+	0x00000164,0x0000002f,0x000400fa,0x00000165,0x00000160,0x00000161,0x000200f8,0x00000160,
+	0x0004003d,0x0000000c,0x0000016b,0x0000015e,0x00050041,0x0000000d,0x0000016c,0x0000013e,
+	0x0000016b,0x0004003d,0x0000000c,0x0000016d,0x0000016c,0x00060041,0x0000016e,0x0000016f,
+	0x0000016a,0x00000051,0x0000016d,0x0004003d,0x00000017,0x00000170,0x0000016f,0x0003003e,
+	0x00000166,0x00000170,0x0004003d,0x0000000c,0x00000172,0x0000015e,0x00050041,0x00000048,
+	0x00000173,0x00000166,0x00000024,0x0004003d,0x00000006,0x00000174,0x00000173,0x00050041,
+	0x00000048,0x00000175,0x00000171,0x00000172,0x0003003e,0x00000175,0x00000174,0x0004003d,
+	0x0000000c,0x00000177,0x0000015e,0x00050041,0x00000048,0x00000178,0x00000166,0x00000029,
+	0x0004003d,0x00000006,0x00000179,0x00000178,0x00050041,0x00000048,0x0000017a,0x00000176,
+	0x00000177,0x0003003e,0x0000017a,0x00000179,0x0004003d,0x0000000c,0x0000017b,0x0000015e,
+	0x00050041,0x0000000d,0x0000017c,0x00000146,0x0000017b,0x0004003d,0x0000000c,0x0000017d,
+	0x0000017c,0x00060041,0x0000016e,0x0000017e,0x0000016a,0x00000051,0x0000017d,0x0004003d,
+	0x00000017,0x0000017f,0x0000017e,0x0003003e,0x00000166,0x0000017f,0x0004003d,0x0000000c,
+	0x00000181,0x0000015e,0x00050041,0x00000048,0x00000182,0x00000166,0x00000024,0x0004003d,
+	0x00000006,0x00000183,0x00000182,0x00050041,0x00000048,0x00000184,0x00000180,0x00000181,
+	0x0003003e,0x00000184,0x00000183,0x0004003d,0x0000000c,0x00000186,0x0000015e,0x00050041,
+	0x00000048,0x00000187,0x00000166,0x00000029,0x0004003d,0x00000006,0x00000188,0x00000187,
+	0x00050041,0x00000048,0x00000189,0x00000185,0x00000186,0x0003003e,0x00000189,0x00000188,
+	0x0004003d,0x0000000c,0x0000018a,0x0000015e,0x00050041,0x0000000d,0x0000018b,0x0000014e,
+	0x0000018a,0x0004003d,0x0000000c,0x0000018c,0x0000018b,0x00060041,0x0000016e,0x0000018d,
+	0x0000016a,0x00000051,0x0000018c,0x0004003d,0x00000017,0x0000018e,0x0000018d,0x0003003e,
+	0x00000166,0x0000018e,0x0004003d,0x0000000c,0x00000190,0x0000015e,0x00050041,0x00000048,
+	0x00000191,0x00000166,0x00000024,0x0004003d,0x00000006,0x00000192,0x00000191,0x00050041,
+	0x00000048,0x00000193,0x0000018f,0x00000190,0x0003003e,0x00000193,0x00000192,0x0004003d,
+	0x0000000c,0x00000195,0x0000015e,0x00050041,0x00000048,0x00000196,0x00000166,0x00000029,
+	0x0004003d,0x00000006,0x00000197,0x00000196,0x00050041,0x00000048,0x00000198,0x00000194,
+	0x00000195,0x0003003e,0x00000198,0x00000197,0x0004003d,0x0000000c,0x00000199,0x0000015e,
+	0x00050041,0x0000000d,0x0000019a,0x00000156,0x00000199,0x0004003d,0x0000000c,0x0000019b,
+	0x0000019a,0x00060041,0x0000016e,0x0000019c,0x0000016a,0x00000051,0x0000019b,0x0004003d,
+	0x00000017,0x0000019d,0x0000019c,0x0003003e,0x00000166,0x0000019d,0x0004003d,0x0000000c,
+	0x0000019f,0x0000015e,0x00050041,0x00000048,0x000001a0,0x00000166,0x00000024,0x0004003d,
+	0x00000006,0x000001a1,0x000001a0,0x00050041,0x00000048,0x000001a2,0x0000019e,0x0000019f,
+	0x0003003e,0x000001a2,0x000001a1,0x0004003d,0x0000000c,0x000001a4,0x0000015e,0x00050041,
+	0x00000048,0x000001a5,0x00000166,0x00000029,0x0004003d,0x00000006,0x000001a6,0x000001a5,
+	0x00050041,0x00000048,0x000001a7,0x000001a3,0x000001a4,0x0003003e,0x000001a7,0x000001a6,
+	0x000200f9,0x00000162,0x000200f8,0x00000162,0x0004003d,0x0000000c,0x000001a8,0x0000015e,
+	0x00050080,0x0000000c,0x000001a9,0x000001a8,0x00000055,0x0003003e,0x0000015e,0x000001a9,
+	0x000200f9,0x0000015f,0x000200f8,0x00000161,0x0004003d,0x00000007,0x000001aa,0x00000171,
+	0x0004003d,0x00000007,0x000001ab,0x00000126,0x00050085,0x00000007,0x000001ac,0x000001aa,
+	0x000001ab,0x0004003d,0x00000007,0x000001ad,0x00000180,0x0004003d,0x00000007,0x000001ae,
+	0x0000012e,0x00050085,0x00000007,0x000001af,0x000001ad,0x000001ae,0x00050081,0x00000007,
+	0x000001b0,0x000001ac,0x000001af,0x0004003d,0x00000007,0x000001b1,0x0000018f,0x0004003d,
+	0x00000007,0x000001b2,0x00000134,0x00050085,0x00000007,0x000001b3,0x000001b1,0x000001b2,
+	0x00050081,0x00000007,0x000001b4,0x000001b0,0x000001b3,0x0004003d,0x00000007,0x000001b5,
+	0x0000019e,0x0004003d,0x00000007,0x000001b6,0x0000013a,0x00050085,0x00000007,0x000001b7,
+	0x000001b5,0x000001b6,0x00050081,0x00000007,0x000001b8,0x000001b4,0x000001b7,0x0003003e,
+	0x00000011,0x000001b8,0x0004003d,0x00000007,0x000001b9,0x00000176,0x0004003d,0x00000007,
+	0x000001ba,0x00000126,0x00050085,0x00000007,0x000001bb,0x000001b9,0x000001ba,0x0004003d,
+	0x00000007,0x000001bc,0x00000185,0x0004003d,0x00000007,0x000001bd,0x0000012e,0x00050085,
+	0x00000007,0x000001be,0x000001bc,0x000001bd,0x00050081,0x00000007,0x000001bf,0x000001bb,
+	0x000001be,0x0004003d,0x00000007,0x000001c0,0x00000194,0x0004003d,0x00000007,0x000001c1,
+	0x00000134,0x00050085,0x00000007,0x000001c2,0x000001c0,0x000001c1,0x00050081,0x00000007,
+	0x000001c3,0x000001bf,0x000001c2,0x0004003d,0x00000007,0x000001c4,0x000001a3,0x0004003d,
+	0x00000007,0x000001c5,0x0000013a,0x00050085,0x00000007,0x000001c6,0x000001c4,0x000001c5,
+	0x00050081,0x00000007,0x000001c7,0x000001c3,0x000001c6,0x0003003e,0x00000012,0x000001c7,
+	0x0003003e,0x000001c8,0x00000024,0x000200f9,0x000001c9,0x000200f8,0x000001c9,0x000400f6,
+	0x000001cb,0x000001cc,0x00000000,0x000200f9,0x000001cd,0x000200f8,0x000001cd,0x0004003d,
+	0x0000000c,0x000001ce,0x000001c8,0x000500b0,0x00000009,0x000001cf,0x000001ce,0x0000002f,
+	0x000400fa,0x000001cf,0x000001ca,0x000001cb,0x000200f8,0x000001ca,0x0004003d,0x0000000c,
+	0x000001d0,0x000001c8,0x0004003d,0x0000000c,0x000001d1,0x000001c8,0x00050041,0x00000048,
+	0x000001d2,0x00000011,0x000001d1,0x0004003d,0x00000006,0x000001d3,0x000001d2,0x000500b8,
+	0x00000009,0x000001d4,0x000001d3,0x00000078,0x000400a8,0x00000009,0x000001d5,0x000001d4,
+	0x000300f7,0x000001d7,0x00000000,0x000400fa,0x000001d5,0x000001d6,0x000001d7,0x000200f8,
+	0x000001d6,0x0004003d,0x0000000c,0x000001d8,0x000001c8,0x00050041,0x00000048,0x000001d9,
+	0x00000011,0x000001d8,0x0004003d,0x00000006,0x000001da,0x000001d9,0x00050041,0x00000037,
+	0x000001db,0x00000034,0x00000051,0x0004003d,0x0000000c,0x000001dc,0x000001db,0x00050084,
+	0x0000000c,0x000001dd,0x000001dc,0x0000002f,0x00050082,0x0000000c,0x000001de,0x000001dd,
+	0x00000029,0x00040070,0x00000006,0x000001df,0x000001de,0x000500ba,0x00000009,0x000001e0,
+	0x000001da,0x000001df,0x000200f9,0x000001d7,0x000200f8,0x000001d7,0x000700f5,0x00000009,
+	0x000001e1,0x000001d4,0x000001ca,0x000001e0,0x000001d6,0x000400a8,0x00000009,0x000001e2,
+	0x000001e1,0x000300f7,0x000001e4,0x00000000,0x000400fa,0x000001e2,0x000001e3,0x000001e4,
+	0x000200f8,0x000001e3,0x0004003d,0x0000000c,0x000001e5,0x000001c8,0x00050041,0x00000048,
+	0x000001e6,0x00000012,0x000001e5,0x0004003d,0x00000006,0x000001e7,0x000001e6,0x000500b8,
+	0x00000009,0x000001e8,0x000001e7,0x00000078,0x000200f9,0x000001e4,0x000200f8,0x000001e4,
+	0x000700f5,0x00000009,0x000001e9,0x000001e1,0x000001d7,0x000001e8,0x000001e3,0x000400a8,
+	0x00000009,0x000001ea,0x000001e9,0x000300f7,0x000001ec,0x00000000,0x000400fa,0x000001ea,
+	0x000001eb,0x000001ec,0x000200f8,0x000001eb,0x0004003d,0x0000000c,0x000001ed,0x000001c8,
+	0x00050041,0x00000048,0x000001ee,0x00000012,0x000001ed,0x0004003d,0x00000006,0x000001ef,
+	0x000001ee,0x00050041,0x00000037,0x000001f0,0x00000034,0x00000055,0x0004003d,0x0000000c,
+	0x000001f1,0x000001f0,0x00050082,0x0000000c,0x000001f2,0x000001f1,0x00000029,0x00040070,
+	0x00000006,0x000001f3,0x000001f2,0x000500ba,0x00000009,0x000001f4,0x000001ef,0x000001f3,
+	0x000200f9,0x000001ec,0x000200f8,0x000001ec,0x000700f5,0x00000009,0x000001f5,0x000001e9,
+	0x000001e4,0x000001f4,0x000001eb,0x00050041,0x000001f6,0x000001f7,0x00000013,0x000001d0,
+	0x0003003e,0x000001f7,0x000001f5,0x000200f9,0x000001cc,0x000200f8,0x000001cc,0x0004003d,
+	0x0000000c,0x000001f8,0x000001c8,0x00050080,0x0000000c,0x000001f9,0x000001f8,0x00000055,
+	0x0003003e,0x000001c8,0x000001f9,0x000200f9,0x000001c9,0x000200f8,0x000001cb,0x0004003d,
+	0x0000000a,0x000001fa,0x00000013,0x0004009b,0x00000009,0x000001fb,0x000001fa,0x000300f7,
+	0x000001fd,0x00000000,0x000400fa,0x000001fb,0x000001fc,0x000001fd,0x000200f8,0x000001fc,
+	0x0003003e,0x00000014,0x00000024,0x000100fd,0x000200f8,0x000001fd,0x0004003d,0x00000007,
+	0x000001ff,0x00000011,0x0004006d,0x00000108,0x00000200,0x000001ff,0x0003003e,0x0000010a,
+	0x00000200,0x0004003d,0x00000007,0x00000201,0x00000012,0x0004006d,0x00000108,0x00000202,
+	0x00000201,0x0003003e,0x0000010d,0x00000202,0x0004003d,0x00000108,0x00000203,0x0000010a,
+	0x00070050,0x00000108,0x00000204,0x00000029,0x00000029,0x00000029,0x00000029,0x00050080,
+	0x00000108,0x00000205,0x00000203,0x00000204,0x0003003e,0x00000110,0x00000205,0x0004003d,
+	0x00000108,0x00000206,0x0000010d,0x0003003e,0x00000114,0x00000206,0x0004003d,0x00000108,
+	0x00000207,0x0000010a,0x0003003e,0x00000116,0x00000207,0x0004003d,0x00000108,0x00000208,
+	0x0000010d,0x00070050,0x00000108,0x00000209,0x00000029,0x00000029,0x00000029,0x00000029,
+	0x00050080,0x00000108,0x0000020a,0x00000208,0x00000209,0x0003003e,0x00000118,0x0000020a,
+	0x0004003d,0x00000108,0x0000020b,0x00000110,0x0003003e,0x0000011c,0x0000020b,0x0004003d,
+	0x00000108,0x0000020c,0x00000118,0x0003003e,0x0000011e,0x0000020c,0x0004003d,0x00000007,
+	0x0000020d,0x00000011,0x0006000c,0x00000007,0x0000020e,0x00000001,0x0000000a,0x0000020d,
+	0x0003003e,0x00000120,0x0000020e,0x0004003d,0x00000007,0x0000020f,0x00000012,0x0006000c,
+	0x00000007,0x00000210,0x00000001,0x0000000a,0x0000020f,0x0003003e,0x00000123,0x00000210,
+	0x0004003d,0x00000007,0x00000211,0x00000120,0x00070050,0x00000007,0x00000212,0x00000040,
+	0x00000040,0x00000040,0x00000040,0x00050083,0x00000007,0x00000213,0x00000212,0x00000211,
+	0x0004003d,0x00000007,0x00000214,0x00000123,0x00070050,0x00000007,0x00000215,0x00000040,
+	0x00000040,0x00000040,0x00000040,0x00050083,0x00000007,0x00000216,0x00000215,0x00000214,
+	0x00050085,0x00000007,0x00000217,0x00000213,0x00000216,0x0003003e,0x00000126,0x00000217,
+	0x0004003d,0x00000007,0x00000218,0x00000120,0x0004003d,0x00000007,0x00000219,0x00000123,
+	0x00070050,0x00000007,0x0000021a,0x00000040,0x00000040,0x00000040,0x00000040,0x00050083,
+	0x00000007,0x0000021b,0x0000021a,0x00000219,0x00050085,0x00000007,0x0000021c,0x00000218,
+	0x0000021b,0x0003003e,0x0000012e,0x0000021c,0x0004003d,0x00000007,0x0000021d,0x00000120,
+	0x00070050,0x00000007,0x0000021e,0x00000040,0x00000040,0x00000040,0x00000040,0x00050083,
+	0x00000007,0x0000021f,0x0000021e,0x0000021d,0x0004003d,0x00000007,0x00000220,0x00000123,
+	0x00050085,0x00000007,0x00000221,0x0000021f,0x00000220,0x0003003e,0x00000134,0x00000221,
+	0x0004003d,0x00000007,0x00000222,0x00000120,0x0004003d,0x00000007,0x00000223,0x00000123,
+	0x00050085,0x00000007,0x00000224,0x00000222,0x00000223,0x0003003e,0x0000013a,0x00000224,
+	0x0004003d,0x00000108,0x00000226,0x0000010a,0x00070050,0x00000108,0x00000227,0x0000002f,
+	0x0000002f,0x0000002f,0x0000002f,0x00050086,0x00000108,0x00000228,0x00000226,0x00000227,
+	0x0003003e,0x00000225,0x00000228,0x0004003d,0x00000108,0x0000022a,0x00000110,0x00070050,
+	0x00000108,0x0000022b,0x0000002f,0x0000002f,0x0000002f,0x0000002f,0x00050086,0x00000108,
+	0x0000022c,0x0000022a,0x0000022b,0x0003003e,0x00000229,0x0000022c,0x0004003d,0x00000108,
+	0x0000022e,0x00000116,0x00070050,0x00000108,0x0000022f,0x0000002f,0x0000002f,0x0000002f,
+	0x0000002f,0x00050086,0x00000108,0x00000230,0x0000022e,0x0000022f,0x0003003e,0x0000022d,
+	0x00000230,0x0004003d,0x00000108,0x00000232,0x0000011c,0x00070050,0x00000108,0x00000233,
+	0x0000002f,0x0000002f,0x0000002f,0x0000002f,0x00050086,0x00000108,0x00000234,0x00000232,
+	0x00000233,0x0003003e,0x00000231,0x00000234,0x0004003d,0x00000108,0x00000236,0x0000010a,
+	0x00070050,0x00000108,0x00000237,0x0000002f,0x0000002f,0x0000002f,0x0000002f,0x00050089,
+	0x00000108,0x00000238,0x00000236,0x00000237,0x0003003e,0x00000235,0x00000238,0x0004003d,
+	0x00000108,0x0000023a,0x00000110,0x00070050,0x00000108,0x0000023b,0x0000002f,0x0000002f,
+	0x0000002f,0x0000002f,0x00050089,0x00000108,0x0000023c,0x0000023a,0x0000023b,0x0003003e,
+	0x00000239,0x0000023c,0x0004003d,0x00000108,0x0000023e,0x00000116,0x00070050,0x00000108,
+	0x0000023f,0x0000002f,0x0000002f,0x0000002f,0x0000002f,0x00050089,0x00000108,0x00000240,
+	0x0000023e,0x0000023f,0x0003003e,0x0000023d,0x00000240,0x0004003d,0x00000108,0x00000242,
+	0x0000011c,0x00070050,0x00000108,0x00000243,0x0000002f,0x0000002f,0x0000002f,0x0000002f,
+	0x00050089,0x00000108,0x00000244,0x00000242,0x00000243,0x0003003e,0x00000241,0x00000244,
+	0x0004003d,0x00000108,0x00000245,0x0000010d,0x00050041,0x00000037,0x00000246,0x00000034,
+	0x00000051,0x0004003d,0x0000000c,0x00000247,0x00000246,0x00070050,0x00000108,0x00000248,
+	0x00000247,0x00000247,0x00000247,0x00000247,0x00050084,0x00000108,0x00000249,0x00000245,
+	0x00000248,0x0004003d,0x00000108,0x0000024a,0x00000225,0x00050080,0x00000108,0x0000024b,
+	0x00000249,0x0000024a,0x0003003e,0x0000013e,0x0000024b,0x0004003d,0x00000108,0x0000024c,
+	0x00000114,0x00050041,0x00000037,0x0000024d,0x00000034,0x00000051,0x0004003d,0x0000000c,
+	0x0000024e,0x0000024d,0x00070050,0x00000108,0x0000024f,0x0000024e,0x0000024e,0x0000024e,
+	0x0000024e,0x00050084,0x00000108,0x00000250,0x0000024c,0x0000024f,0x0004003d,0x00000108,
+	0x00000251,0x00000229,0x00050080,0x00000108,0x00000252,0x00000250,0x00000251,0x0003003e,
+	0x00000146,0x00000252,0x0004003d,0x00000108,0x00000253,0x00000118,0x00050041,0x00000037,
+	0x00000254,0x00000034,0x00000051,0x0004003d,0x0000000c,0x00000255,0x00000254,0x00070050,
+	0x00000108,0x00000256,0x00000255,0x00000255,0x00000255,0x00000255,0x00050084,0x00000108,
+	0x00000257,0x00000253,0x00000256,0x0004003d,0x00000108,0x00000258,0x0000022d,0x00050080,
+	0x00000108,0x00000259,0x00000257,0x00000258,0x0003003e,0x0000014e,0x00000259,0x0004003d,
+	0x00000108,0x0000025a,0x0000011e,0x00050041,0x00000037,0x0000025b,0x00000034,0x00000051,
+	0x0004003d,0x0000000c,0x0000025c,0x0000025b,0x00070050,0x00000108,0x0000025d,0x0000025c,
+	0x0000025c,0x0000025c,0x0000025c,0x00050084,0x00000108,0x0000025e,0x0000025a,0x0000025d,
+	0x0004003d,0x00000108,0x0000025f,0x00000231,0x00050080,0x00000108,0x00000260,0x0000025e,
+	0x0000025f,0x0003003e,0x00000156,0x00000260,0x00050041,0x0000000d,0x00000266,0x0000013e,
+	0x00000024,0x0004003d,0x0000000c,0x00000267,0x00000266,0x00060041,0x000000b9,0x00000268,
+	0x00000265,0x00000051,0x00000267,0x0004003d,0x0000000c,0x00000269,0x00000268,0x0006000c,
+	0x00000007,0x0000026a,0x00000001,0x00000040,0x00000269,0x0003003e,0x00000261,0x0000026a,
+	0x00050041,0x0000000d,0x0000026c,0x00000235,0x00000024,0x0004003d,0x0000000c,0x0000026d,
+	0x0000026c,0x00050041,0x00000048,0x0000026e,0x00000261,0x0000026d,0x0004003d,0x00000006,
+	0x0000026f,0x0000026e,0x00050041,0x00000048,0x00000270,0x0000026b,0x00000024,0x0003003e,
+	0x00000270,0x0000026f,0x00050041,0x0000000d,0x00000271,0x00000146,0x00000024,0x0004003d,
+	0x0000000c,0x00000272,0x00000271,0x00060041,0x000000b9,0x00000273,0x00000265,0x00000051,
+	0x00000272,0x0004003d,0x0000000c,0x00000274,0x00000273,0x0006000c,0x00000007,0x00000275,
+	0x00000001,0x00000040,0x00000274,0x0003003e,0x00000261,0x00000275,0x00050041,0x0000000d,
+	0x00000277,0x00000239,0x00000024,0x0004003d,0x0000000c,0x00000278,0x00000277,0x00050041,
+	0x00000048,0x00000279,0x00000261,0x00000278,0x0004003d,0x00000006,0x0000027a,0x00000279,
+	0x00050041,0x00000048,0x0000027b,0x00000276,0x00000024,0x0003003e,0x0000027b,0x0000027a,
+	0x00050041,0x0000000d,0x0000027c,0x0000014e,0x00000024,0x0004003d,0x0000000c,0x0000027d,
+	0x0000027c,0x00060041,0x000000b9,0x0000027e,0x00000265,0x00000051,0x0000027d,0x0004003d,
+	0x0000000c,0x0000027f,0x0000027e,0x0006000c,0x00000007,0x00000280,0x00000001,0x00000040,
+	0x0000027f,0x0003003e,0x00000261,0x00000280,0x00050041,0x0000000d,0x00000282,0x0000023d,
+	0x00000024,0x0004003d,0x0000000c,0x00000283,0x00000282,0x00050041,0x00000048,0x00000284,
+	0x00000261,0x00000283,0x0004003d,0x00000006,0x00000285,0x00000284,0x00050041,0x00000048,
+	0x00000286,0x00000281,0x00000024,0x0003003e,0x00000286,0x00000285,0x00050041,0x0000000d,
+	0x00000287,0x00000156,0x00000024,0x0004003d,0x0000000c,0x00000288,0x00000287,0x00060041,
+	0x000000b9,0x00000289,0x00000265,0x00000051,0x00000288,0x0004003d,0x0000000c,0x0000028a,
+	0x00000289,0x0006000c,0x00000007,0x0000028b,0x00000001,0x00000040,0x0000028a,0x0003003e,
+	0x00000261,0x0000028b,0x00050041,0x0000000d,0x0000028d,0x00000241,0x00000024,0x0004003d,
+	0x0000000c,0x0000028e,0x0000028d,0x00050041,0x00000048,0x0000028f,0x00000261,0x0000028e,
+	0x0004003d,0x00000006,0x00000290,0x0000028f,0x00050041,0x00000048,0x00000291,0x0000028c,
+	0x00000024,0x0003003e,0x00000291,0x00000290,0x00050041,0x0000000d,0x00000293,0x0000013e,
+	0x00000029,0x0004003d,0x0000000c,0x00000294,0x00000293,0x00060041,0x000000b9,0x00000295,
+	0x00000265,0x00000051,0x00000294,0x0004003d,0x0000000c,0x00000296,0x00000295,0x0006000c,
+	0x00000007,0x00000297,0x00000001,0x00000040,0x00000296,0x0003003e,0x00000292,0x00000297,
+	0x00050041,0x0000000d,0x00000298,0x00000235,0x00000029,0x0004003d,0x0000000c,0x00000299,
+	0x00000298,0x00050041,0x00000048,0x0000029a,0x00000292,0x00000299,0x0004003d,0x00000006,
+	0x0000029b,0x0000029a,0x00050041,0x00000048,0x0000029c,0x0000026b,0x00000029,0x0003003e,
+	0x0000029c,0x0000029b,0x00050041,0x0000000d,0x0000029d,0x00000146,0x00000029,0x0004003d,
+	0x0000000c,0x0000029e,0x0000029d,0x00060041,0x000000b9,0x0000029f,0x00000265,0x00000051,
+	0x0000029e,0x0004003d,0x0000000c,0x000002a0,0x0000029f,0x0006000c,0x00000007,0x000002a1,
+	0x00000001,0x00000040,0x000002a0,0x0003003e,0x00000292,0x000002a1,0x00050041,0x0000000d,
+	0x000002a2,0x00000239,0x00000029,0x0004003d,0x0000000c,0x000002a3,0x000002a2,0x00050041,
+	0x00000048,0x000002a4,0x00000292,0x000002a3,0x0004003d,0x00000006,0x000002a5,0x000002a4,
+	0x00050041,0x00000048,0x000002a6,0x00000276,0x00000029,0x0003003e,0x000002a6,0x000002a5,
+	0x00050041,0x0000000d,0x000002a7,0x0000014e,0x00000029,0x0004003d,0x0000000c,0x000002a8,
+	0x000002a7,0x00060041,0x000000b9,0x000002a9,0x00000265,0x00000051,0x000002a8,0x0004003d,
+	0x0000000c,0x000002aa,0x000002a9,0x0006000c,0x00000007,0x000002ab,0x00000001,0x00000040,
+	0x000002aa,0x0003003e,0x00000292,0x000002ab,0x00050041,0x0000000d,0x000002ac,0x0000023d,
+	0x00000029,0x0004003d,0x0000000c,0x000002ad,0x000002ac,0x00050041,0x00000048,0x000002ae,
+	0x00000292,0x000002ad,0x0004003d,0x00000006,0x000002af,0x000002ae,0x00050041,0x00000048,
+	0x000002b0,0x00000281,0x00000029,0x0003003e,0x000002b0,0x000002af,0x00050041,0x0000000d,
+	0x000002b1,0x00000156,0x00000029,0x0004003d,0x0000000c,0x000002b2,0x000002b1,0x00060041,
+	0x000000b9,0x000002b3,0x00000265,0x00000051,0x000002b2,0x0004003d,0x0000000c,0x000002b4,
+	0x000002b3,0x0006000c,0x00000007,0x000002b5,0x00000001,0x00000040,0x000002b4,0x0003003e,
+	0x00000292,0x000002b5,0x00050041,0x0000000d,0x000002b6,0x00000241,0x00000029,0x0004003d,
+	0x0000000c,0x000002b7,0x000002b6,0x00050041,0x00000048,0x000002b8,0x00000292,0x000002b7,
+	0x0004003d,0x00000006,0x000002b9,0x000002b8,0x00050041,0x00000048,0x000002ba,0x0000028c,
+	0x00000029,0x0003003e,0x000002ba,0x000002b9,0x00050041,0x0000000d,0x000002bc,0x0000013e,
+	0x0000002c,0x0004003d,0x0000000c,0x000002bd,0x000002bc,0x00060041,0x000000b9,0x000002be,
+	0x00000265,0x00000051,0x000002bd,0x0004003d,0x0000000c,0x000002bf,0x000002be,0x0006000c,
+	0x00000007,0x000002c0,0x00000001,0x00000040,0x000002bf,0x0003003e,0x000002bb,0x000002c0,
+	0x00050041,0x0000000d,0x000002c1,0x00000235,0x0000002c,0x0004003d,0x0000000c,0x000002c2,
+	0x000002c1,0x00050041,0x00000048,0x000002c3,0x000002bb,0x000002c2,0x0004003d,0x00000006,
+	0x000002c4,0x000002c3,0x00050041,0x00000048,0x000002c5,0x0000026b,0x0000002c,0x0003003e,
+	0x000002c5,0x000002c4,0x00050041,0x0000000d,0x000002c6,0x00000146,0x0000002c,0x0004003d,
+	0x0000000c,0x000002c7,0x000002c6,0x00060041,0x000000b9,0x000002c8,0x00000265,0x00000051,
+	0x000002c7,0x0004003d,0x0000000c,0x000002c9,0x000002c8,0x0006000c,0x00000007,0x000002ca,
+	0x00000001,0x00000040,0x000002c9,0x0003003e,0x000002bb,0x000002ca,0x00050041,0x0000000d,
+	0x000002cb,0x00000239,0x0000002c,0x0004003d,0x0000000c,0x000002cc,0x000002cb,0x00050041,
+	0x00000048,0x000002cd,0x000002bb,0x000002cc,0x0004003d,0x00000006,0x000002ce,0x000002cd,
+	0x00050041,0x00000048,0x000002cf,0x00000276,0x0000002c,0x0003003e,0x000002cf,0x000002ce,
+	0x00050041,0x0000000d,0x000002d0,0x0000014e,0x0000002c,0x0004003d,0x0000000c,0x000002d1,
+	0x000002d0,0x00060041,0x000000b9,0x000002d2,0x00000265,0x00000051,0x000002d1,0x0004003d,
+	0x0000000c,0x000002d3,0x000002d2,0x0006000c,0x00000007,0x000002d4,0x00000001,0x00000040,
+	0x000002d3,0x0003003e,0x000002bb,0x000002d4,0x00050041,0x0000000d,0x000002d5,0x0000023d,
+	0x0000002c,0x0004003d,0x0000000c,0x000002d6,0x000002d5,0x00050041,0x00000048,0x000002d7,
+	0x000002bb,0x000002d6,0x0004003d,0x00000006,0x000002d8,0x000002d7,0x00050041,0x00000048,
+	0x000002d9,0x00000281,0x0000002c,0x0003003e,0x000002d9,0x000002d8,0x00050041,0x0000000d,
+	0x000002da,0x00000156,0x0000002c,0x0004003d,0x0000000c,0x000002db,0x000002da,0x00060041,
+	0x000000b9,0x000002dc,0x00000265,0x00000051,0x000002db,0x0004003d,0x0000000c,0x000002dd,
+	0x000002dc,0x0006000c,0x00000007,0x000002de,0x00000001,0x00000040,0x000002dd,0x0003003e,
+	0x000002bb,0x000002de,0x00050041,0x0000000d,0x000002df,0x00000241,0x0000002c,0x0004003d,
+	0x0000000c,0x000002e0,0x000002df,0x00050041,0x00000048,0x000002e1,0x000002bb,0x000002e0,
+	0x0004003d,0x00000006,0x000002e2,0x000002e1,0x00050041,0x00000048,0x000002e3,0x0000028c,
+	0x0000002c,0x0003003e,0x000002e3,0x000002e2,0x00050041,0x0000000d,0x000002e6,0x0000013e,
+	0x000002e5,0x0004003d,0x0000000c,0x000002e7,0x000002e6,0x00060041,0x000000b9,0x000002e8,
+	0x00000265,0x00000051,0x000002e7,0x0004003d,0x0000000c,0x000002e9,0x000002e8,0x0006000c,
+	0x00000007,0x000002ea,0x00000001,0x00000040,0x000002e9,0x0003003e,0x000002e4,0x000002ea,
+	0x00050041,0x0000000d,0x000002eb,0x00000235,0x000002e5,0x0004003d,0x0000000c,0x000002ec,
+	0x000002eb,0x00050041,0x00000048,0x000002ed,0x000002e4,0x000002ec,0x0004003d,0x00000006,
+	0x000002ee,0x000002ed,0x00050041,0x00000048,0x000002ef,0x0000026b,0x000002e5,0x0003003e,
+	0x000002ef,0x000002ee,0x00050041,0x0000000d,0x000002f0,0x00000146,0x000002e5,0x0004003d,
+	0x0000000c,0x000002f1,0x000002f0,0x00060041,0x000000b9,0x000002f2,0x00000265,0x00000051,
+	0x000002f1,0x0004003d,0x0000000c,0x000002f3,0x000002f2,0x0006000c,0x00000007,0x000002f4,
+	0x00000001,0x00000040,0x000002f3,0x0003003e,0x000002e4,0x000002f4,0x00050041,0x0000000d,
+	0x000002f5,0x00000239,0x000002e5,0x0004003d,0x0000000c,0x000002f6,0x000002f5,0x00050041,
+	0x00000048,0x000002f7,0x000002e4,0x000002f6,0x0004003d,0x00000006,0x000002f8,0x000002f7,
+	0x00050041,0x00000048,0x000002f9,0x00000276,0x000002e5,0x0003003e,0x000002f9,0x000002f8,
+	0x00050041,0x0000000d,0x000002fa,0x0000014e,0x000002e5,0x0004003d,0x0000000c,0x000002fb,
+	0x000002fa,0x00060041,0x000000b9,0x000002fc,0x00000265,0x00000051,0x000002fb,0x0004003d,
+	0x0000000c,0x000002fd,0x000002fc,0x0006000c,0x00000007,0x000002fe,0x00000001,0x00000040,
+	0x000002fd,0x0003003e,0x000002e4,0x000002fe,0x00050041,0x0000000d,0x000002ff,0x0000023d,
+	0x000002e5,0x0004003d,0x0000000c,0x00000300,0x000002ff,0x00050041,0x00000048,0x00000301,
+	0x000002e4,0x00000300,0x0004003d,0x00000006,0x00000302,0x00000301,0x00050041,0x00000048,
+	0x00000303,0x00000281,0x000002e5,0x0003003e,0x00000303,0x00000302,0x00050041,0x0000000d,
+	0x00000304,0x00000156,0x000002e5,0x0004003d,0x0000000c,0x00000305,0x00000304,0x00060041,
+	0x000000b9,0x00000306,0x00000265,0x00000051,0x00000305,0x0004003d,0x0000000c,0x00000307,
+	0x00000306,0x0006000c,0x00000007,0x00000308,0x00000001,0x00000040,0x00000307,0x0003003e,
+	0x000002e4,0x00000308,0x00050041,0x0000000d,0x00000309,0x00000241,0x000002e5,0x0004003d,
+	0x0000000c,0x0000030a,0x00000309,0x00050041,0x00000048,0x0000030b,0x000002e4,0x0000030a,
+	0x0004003d,0x00000006,0x0000030c,0x0000030b,0x00050041,0x00000048,0x0000030d,0x0000028c,
+	0x000002e5,0x0003003e,0x0000030d,0x0000030c,0x0004003d,0x00000007,0x0000030f,0x0000026b,
+	0x0004003d,0x00000007,0x00000310,0x00000126,0x00050085,0x00000007,0x00000311,0x0000030f,
+	0x00000310,0x0004003d,0x00000007,0x00000312,0x00000276,0x0004003d,0x00000007,0x00000313,
+	0x0000012e,0x00050085,0x00000007,0x00000314,0x00000312,0x00000313,0x00050081,0x00000007,
+	0x00000315,0x00000311,0x00000314,0x0004003d,0x00000007,0x00000316,0x00000281,0x0004003d,
+	0x00000007,0x00000317,0x00000134,0x00050085,0x00000007,0x00000318,0x00000316,0x00000317,
+	0x00050081,0x00000007,0x00000319,0x00000315,0x00000318,0x0004003d,0x00000007,0x0000031a,
+	0x0000028c,0x0004003d,0x00000007,0x0000031b,0x0000013a,0x00050085,0x00000007,0x0000031c,
+	0x0000031a,0x0000031b,0x00050081,0x00000007,0x0000031d,0x00000319,0x0000031c,0x0003003e,
+	0x0000030e,0x0000031d,0x0004003d,0x00000007,0x0000031e,0x0000030e,0x0004003d,0x0000000a,
+	0x0000031f,0x00000013,0x000400a8,0x0000000a,0x00000320,0x0000031f,0x000600a9,0x00000007,
+	0x00000323,0x00000320,0x00000322,0x00000321,0x00050085,0x00000007,0x00000324,0x0000031e,
+	0x00000323,0x0006000c,0x0000000c,0x00000325,0x00000001,0x00000037,0x00000324,0x0003003e,
+	0x00000014,0x00000325,0x000100fd,0x00010038,0x00050036,0x00000002,0x0000001e,0x00000000,
+	0x00000019,0x00030037,0x00000018,0x0000001a,0x00030037,0x00000018,0x0000001b,0x00030037,
+	0x0000000b,0x0000001c,0x00030037,0x0000000d,0x0000001d,0x000200f8,0x0000001f,0x0004003b,
+	0x00000327,0x00000328,0x00000007,0x0004003b,0x00000327,0x0000032b,0x00000007,0x0004003b,
+	0x00000327,0x0000032e,0x00000007,0x0004003b,0x00000327,0x00000332,0x00000007,0x0004003b,
+	0x00000327,0x00000334,0x00000007,0x0004003b,0x00000327,0x00000336,0x00000007,0x0004003b,
+	0x00000327,0x0000033a,0x00000007,0x0004003b,0x00000327,0x0000033c,0x00000007,0x0004003b,
+	0x00000018,0x0000033e,0x00000007,0x0004003b,0x00000018,0x00000341,0x00000007,0x0004003b,
+	0x00000018,0x00000344,0x00000007,0x0004003b,0x00000018,0x0000034c,0x00000007,0x0004003b,
+	0x00000018,0x00000352,0x00000007,0x0004003b,0x00000018,0x00000358,0x00000007,0x0004003b,
+	0x00000327,0x0000035c,0x00000007,0x0004003b,0x00000327,0x00000360,0x00000007,0x0004003b,
+	0x00000327,0x00000364,0x00000007,0x0004003b,0x00000327,0x00000368,0x00000007,0x0004003b,
+	0x00000327,0x0000036c,0x00000007,0x0004003b,0x00000327,0x00000372,0x00000007,0x0004003b,
+	0x00000327,0x00000378,0x00000007,0x0004003b,0x00000327,0x0000037e,0x00000007,0x0004003b,
+	0x00000327,0x00000384,0x00000007,0x0004003b,0x00000327,0x0000038c,0x00000007,0x0004003b,
+	0x00000327,0x00000394,0x00000007,0x0004003b,0x00000327,0x0000039c,0x00000007,0x0004003b,
+	0x00000008,0x000003a4,0x00000007,0x0004003b,0x00000008,0x000003ae,0x00000007,0x0004003b,
+	0x00000018,0x000003b2,0x00000007,0x0004003b,0x00000008,0x000003c2,0x00000007,0x0004003b,
+	0x00000018,0x000003c6,0x00000007,0x0004003b,0x00000008,0x000003d6,0x00000007,0x0004003b,
+	0x00000018,0x000003da,0x00000007,0x0004003b,0x00000008,0x000003ea,0x00000007,0x0004003b,
+	0x00000018,0x000003ee,0x00000007,0x0004003b,0x00000018,0x00000401,0x00000007,0x0004003b,
+	0x00000018,0x00000414,0x00000007,0x0004003b,0x00000018,0x00000427,0x00000007,0x0004003b,
+	0x00000018,0x0000043a,0x00000007,0x0004003b,0x00000008,0x00000445,0x00000007,0x0004003d,
+	0x00000017,0x00000329,0x0000001a,0x0004006d,0x00000326,0x0000032a,0x00000329,0x0003003e,
+	0x00000328,0x0000032a,0x0004003d,0x00000017,0x0000032c,0x0000001b,0x0004006d,0x00000326,
+	0x0000032d,0x0000032c,0x0003003e,0x0000032b,0x0000032d,0x0004003d,0x00000326,0x0000032f,
+	0x00000328,0x00050050,0x00000326,0x00000330,0x00000029,0x00000029,0x00050080,0x00000326,
+	0x00000331,0x0000032f,0x00000330,0x0003003e,0x0000032e,0x00000331,0x0004003d,0x00000326,
+	0x00000333,0x0000032b,0x0003003e,0x00000332,0x00000333,0x0004003d,0x00000326,0x00000335,
+	0x00000328,0x0003003e,0x00000334,0x00000335,0x0004003d,0x00000326,0x00000337,0x0000032b,
+	0x00050050,0x00000326,0x00000338,0x00000029,0x00000029,0x00050080,0x00000326,0x00000339,
+	0x00000337,0x00000338,0x0003003e,0x00000336,0x00000339,0x0004003d,0x00000326,0x0000033b,
+	0x0000032e,0x0003003e,0x0000033a,0x0000033b,0x0004003d,0x00000326,0x0000033d,0x00000336,
+	0x0003003e,0x0000033c,0x0000033d,0x0004003d,0x00000017,0x0000033f,0x0000001a,0x0006000c,
+	0x00000017,0x00000340,0x00000001,0x0000000a,0x0000033f,0x0003003e,0x0000033e,0x00000340,
+	0x0004003d,0x00000017,0x00000342,0x0000001b,0x0006000c,0x00000017,0x00000343,0x00000001,
+	0x0000000a,0x00000342,0x0003003e,0x00000341,0x00000343,0x0004003d,0x00000017,0x00000345,
+	0x0000033e,0x00050050,0x00000017,0x00000346,0x00000040,0x00000040,0x00050083,0x00000017,
+	0x00000347,0x00000346,0x00000345,0x0004003d,0x00000017,0x00000348,0x00000341,0x00050050,
+	0x00000017,0x00000349,0x00000040,0x00000040,0x00050083,0x00000017,0x0000034a,0x00000349,
+	0x00000348,0x00050085,0x00000017,0x0000034b,0x00000347,0x0000034a,0x0003003e,0x00000344,
+	0x0000034b,0x0004003d,0x00000017,0x0000034d,0x0000033e,0x0004003d,0x00000017,0x0000034e,
+	0x00000341,0x00050050,0x00000017,0x0000034f,0x00000040,0x00000040,0x00050083,0x00000017,
+	0x00000350,0x0000034f,0x0000034e,0x00050085,0x00000017,0x00000351,0x0000034d,0x00000350,
+	0x0003003e,0x0000034c,0x00000351,0x0004003d,0x00000017,0x00000353,0x0000033e,0x00050050,
+	0x00000017,0x00000354,0x00000040,0x00000040,0x00050083,0x00000017,0x00000355,0x00000354,
+	0x00000353,0x0004003d,0x00000017,0x00000356,0x00000341,0x00050085,0x00000017,0x00000357,
+	0x00000355,0x00000356,0x0003003e,0x00000352,0x00000357,0x0004003d,0x00000017,0x00000359,
+	0x0000033e,0x0004003d,0x00000017,0x0000035a,0x00000341,0x00050085,0x00000017,0x0000035b,
+	0x00000359,0x0000035a,0x0003003e,0x00000358,0x0000035b,0x0004003d,0x00000326,0x0000035d,
+	0x00000328,0x00050050,0x00000326,0x0000035e,0x0000002f,0x0000002f,0x00050086,0x00000326,
+	0x0000035f,0x0000035d,0x0000035e,0x0003003e,0x0000035c,0x0000035f,0x0004003d,0x00000326,
+	0x00000361,0x0000032e,0x00050050,0x00000326,0x00000362,0x0000002f,0x0000002f,0x00050086,
+	0x00000326,0x00000363,0x00000361,0x00000362,0x0003003e,0x00000360,0x00000363,0x0004003d,
+	0x00000326,0x00000365,0x00000334,0x00050050,0x00000326,0x00000366,0x0000002f,0x0000002f,
+	0x00050086,0x00000326,0x00000367,0x00000365,0x00000366,0x0003003e,0x00000364,0x00000367,
+	0x0004003d,0x00000326,0x00000369,0x0000033a,0x00050050,0x00000326,0x0000036a,0x0000002f,
+	0x0000002f,0x00050086,0x00000326,0x0000036b,0x00000369,0x0000036a,0x0003003e,0x00000368,
+	0x0000036b,0x0004003d,0x00000326,0x0000036d,0x00000328,0x00050050,0x00000326,0x0000036e,
+	0x0000002f,0x0000002f,0x00050089,0x00000326,0x0000036f,0x0000036d,0x0000036e,0x00050050,
+	0x00000326,0x00000370,0x0000002c,0x0000002c,0x00050086,0x00000326,0x00000371,0x0000036f,
+	0x00000370,0x0003003e,0x0000036c,0x00000371,0x0004003d,0x00000326,0x00000373,0x0000032e,
+	0x00050050,0x00000326,0x00000374,0x0000002f,0x0000002f,0x00050089,0x00000326,0x00000375,
+	0x00000373,0x00000374,0x00050050,0x00000326,0x00000376,0x0000002c,0x0000002c,0x00050086,
+	0x00000326,0x00000377,0x00000375,0x00000376,0x0003003e,0x00000372,0x00000377,0x0004003d,
+	0x00000326,0x00000379,0x00000334,0x00050050,0x00000326,0x0000037a,0x0000002f,0x0000002f,
+	0x00050089,0x00000326,0x0000037b,0x00000379,0x0000037a,0x00050050,0x00000326,0x0000037c,
+	0x0000002c,0x0000002c,0x00050086,0x00000326,0x0000037d,0x0000037b,0x0000037c,0x0003003e,
+	0x00000378,0x0000037d,0x0004003d,0x00000326,0x0000037f,0x0000033a,0x00050050,0x00000326,
+	0x00000380,0x0000002f,0x0000002f,0x00050089,0x00000326,0x00000381,0x0000037f,0x00000380,
+	0x00050050,0x00000326,0x00000382,0x0000002c,0x0000002c,0x00050086,0x00000326,0x00000383,
+	0x00000381,0x00000382,0x0003003e,0x0000037e,0x00000383,0x0004003d,0x00000326,0x00000385,
+	0x0000032b,0x00050041,0x00000037,0x00000386,0x00000034,0x00000051,0x0004003d,0x0000000c,
+	0x00000387,0x00000386,0x00050050,0x00000326,0x00000388,0x00000387,0x00000387,0x00050084,
+	0x00000326,0x00000389,0x00000385,0x00000388,0x0004003d,0x00000326,0x0000038a,0x0000035c,
+	0x00050080,0x00000326,0x0000038b,0x00000389,0x0000038a,0x0003003e,0x00000384,0x0000038b,
+	0x0004003d,0x00000326,0x0000038d,0x00000332,0x00050041,0x00000037,0x0000038e,0x00000034,
+	0x00000051,0x0004003d,0x0000000c,0x0000038f,0x0000038e,0x00050050,0x00000326,0x00000390,
+	0x0000038f,0x0000038f,0x00050084,0x00000326,0x00000391,0x0000038d,0x00000390,0x0004003d,
+	0x00000326,0x00000392,0x00000360,0x00050080,0x00000326,0x00000393,0x00000391,0x00000392,
+	0x0003003e,0x0000038c,0x00000393,0x0004003d,0x00000326,0x00000395,0x00000336,0x00050041,
+	0x00000037,0x00000396,0x00000034,0x00000051,0x0004003d,0x0000000c,0x00000397,0x00000396,
+	0x00050050,0x00000326,0x00000398,0x00000397,0x00000397,0x00050084,0x00000326,0x00000399,
+	0x00000395,0x00000398,0x0004003d,0x00000326,0x0000039a,0x00000364,0x00050080,0x00000326,
+	0x0000039b,0x00000399,0x0000039a,0x0003003e,0x00000394,0x0000039b,0x0004003d,0x00000326,
+	0x0000039d,0x0000033c,0x00050041,0x00000037,0x0000039e,0x00000034,0x00000051,0x0004003d,
+	0x0000000c,0x0000039f,0x0000039e,0x00050050,0x00000326,0x000003a0,0x0000039f,0x0000039f,
+	0x00050084,0x00000326,0x000003a1,0x0000039d,0x000003a0,0x0004003d,0x00000326,0x000003a2,
+	0x00000368,0x00050080,0x00000326,0x000003a3,0x000003a1,0x000003a2,0x0003003e,0x0000039c,
+	0x000003a3,0x00050041,0x0000000d,0x000003a9,0x00000384,0x00000024,0x0004003d,0x0000000c,
+	0x000003aa,0x000003a9,0x00060041,0x000000b9,0x000003ab,0x000003a8,0x00000051,0x000003aa,
+	0x0004003d,0x0000000c,0x000003ac,0x000003ab,0x0006000c,0x00000007,0x000003ad,0x00000001,
+	0x00000040,0x000003ac,0x0003003e,0x000003a4,0x000003ad,0x00050041,0x0000000d,0x000003af,
+	0x0000036c,0x00000024,0x0004003d,0x0000000c,0x000003b0,0x000003af,0x000500aa,0x00000009,
+	0x000003b1,0x000003b0,0x00000024,0x000300f7,0x000003b4,0x00000000,0x000400fa,0x000003b1,
+	0x000003b3,0x000003b7,0x000200f8,0x000003b3,0x0004003d,0x00000007,0x000003b5,0x000003a4,
+	0x0007004f,0x00000017,0x000003b6,0x000003b5,0x000003b5,0x00000000,0x00000001,0x0003003e,
+	0x000003b2,0x000003b6,0x000200f9,0x000003b4,0x000200f8,0x000003b7,0x0004003d,0x00000007,
+	0x000003b8,0x000003a4,0x0007004f,0x00000017,0x000003b9,0x000003b8,0x000003b8,0x00000002,
+	0x00000003,0x0003003e,0x000003b2,0x000003b9,0x000200f9,0x000003b4,0x000200f8,0x000003b4,
+	0x0004003d,0x00000017,0x000003ba,0x000003b2,0x0004003d,0x00000007,0x000003bb,0x000003ae,
+	0x0009004f,0x00000007,0x000003bc,0x000003bb,0x000003ba,0x00000004,0x00000005,0x00000002,
+	0x00000003,0x0003003e,0x000003ae,0x000003bc,0x00050041,0x0000000d,0x000003bd,0x0000038c,
+	0x00000024,0x0004003d,0x0000000c,0x000003be,0x000003bd,0x00060041,0x000000b9,0x000003bf,
+	0x000003a8,0x00000051,0x000003be,0x0004003d,0x0000000c,0x000003c0,0x000003bf,0x0006000c,
+	0x00000007,0x000003c1,0x00000001,0x00000040,0x000003c0,0x0003003e,0x000003a4,0x000003c1,
+	0x00050041,0x0000000d,0x000003c3,0x00000372,0x00000024,0x0004003d,0x0000000c,0x000003c4,
+	0x000003c3,0x000500aa,0x00000009,0x000003c5,0x000003c4,0x00000024,0x000300f7,0x000003c8,
+	0x00000000,0x000400fa,0x000003c5,0x000003c7,0x000003cb,0x000200f8,0x000003c7,0x0004003d,
+	0x00000007,0x000003c9,0x000003a4,0x0007004f,0x00000017,0x000003ca,0x000003c9,0x000003c9,
+	0x00000000,0x00000001,0x0003003e,0x000003c6,0x000003ca,0x000200f9,0x000003c8,0x000200f8,
+	0x000003cb,0x0004003d,0x00000007,0x000003cc,0x000003a4,0x0007004f,0x00000017,0x000003cd,
+	0x000003cc,0x000003cc,0x00000002,0x00000003,0x0003003e,0x000003c6,0x000003cd,0x000200f9,
+	0x000003c8,0x000200f8,0x000003c8,0x0004003d,0x00000017,0x000003ce,0x000003c6,0x0004003d,
+	0x00000007,0x000003cf,0x000003c2,0x0009004f,0x00000007,0x000003d0,0x000003cf,0x000003ce,
+	0x00000004,0x00000005,0x00000002,0x00000003,0x0003003e,0x000003c2,0x000003d0,0x00050041,
+	0x0000000d,0x000003d1,0x00000394,0x00000024,0x0004003d,0x0000000c,0x000003d2,0x000003d1,
+	0x00060041,0x000000b9,0x000003d3,0x000003a8,0x00000051,0x000003d2,0x0004003d,0x0000000c,
+	0x000003d4,0x000003d3,0x0006000c,0x00000007,0x000003d5,0x00000001,0x00000040,0x000003d4,
+	0x0003003e,0x000003a4,0x000003d5,0x00050041,0x0000000d,0x000003d7,0x00000378,0x00000024,
+	0x0004003d,0x0000000c,0x000003d8,0x000003d7,0x000500aa,0x00000009,0x000003d9,0x000003d8,
+	0x00000024,0x000300f7,0x000003dc,0x00000000,0x000400fa,0x000003d9,0x000003db,0x000003df,
+	0x000200f8,0x000003db,0x0004003d,0x00000007,0x000003dd,0x000003a4,0x0007004f,0x00000017,
+	0x000003de,0x000003dd,0x000003dd,0x00000000,0x00000001,0x0003003e,0x000003da,0x000003de,
+	0x000200f9,0x000003dc,0x000200f8,0x000003df,0x0004003d,0x00000007,0x000003e0,0x000003a4,
+	0x0007004f,0x00000017,0x000003e1,0x000003e0,0x000003e0,0x00000002,0x00000003,0x0003003e,
+	0x000003da,0x000003e1,0x000200f9,0x000003dc,0x000200f8,0x000003dc,0x0004003d,0x00000017,
+	0x000003e2,0x000003da,0x0004003d,0x00000007,0x000003e3,0x000003d6,0x0009004f,0x00000007,
+	0x000003e4,0x000003e3,0x000003e2,0x00000004,0x00000005,0x00000002,0x00000003,0x0003003e,
+	0x000003d6,0x000003e4,0x00050041,0x0000000d,0x000003e5,0x0000039c,0x00000024,0x0004003d,
+	0x0000000c,0x000003e6,0x000003e5,0x00060041,0x000000b9,0x000003e7,0x000003a8,0x00000051,
+	0x000003e6,0x0004003d,0x0000000c,0x000003e8,0x000003e7,0x0006000c,0x00000007,0x000003e9,
+	0x00000001,0x00000040,0x000003e8,0x0003003e,0x000003a4,0x000003e9,0x00050041,0x0000000d,
+	0x000003eb,0x0000037e,0x00000024,0x0004003d,0x0000000c,0x000003ec,0x000003eb,0x000500aa,
+	0x00000009,0x000003ed,0x000003ec,0x00000024,0x000300f7,0x000003f0,0x00000000,0x000400fa,
+	0x000003ed,0x000003ef,0x000003f3,0x000200f8,0x000003ef,0x0004003d,0x00000007,0x000003f1,
+	0x000003a4,0x0007004f,0x00000017,0x000003f2,0x000003f1,0x000003f1,0x00000000,0x00000001,
+	0x0003003e,0x000003ee,0x000003f2,0x000200f9,0x000003f0,0x000200f8,0x000003f3,0x0004003d,
+	0x00000007,0x000003f4,0x000003a4,0x0007004f,0x00000017,0x000003f5,0x000003f4,0x000003f4,
+	0x00000002,0x00000003,0x0003003e,0x000003ee,0x000003f5,0x000200f9,0x000003f0,0x000200f8,
+	0x000003f0,0x0004003d,0x00000017,0x000003f6,0x000003ee,0x0004003d,0x00000007,0x000003f7,
+	0x000003ea,0x0009004f,0x00000007,0x000003f8,0x000003f7,0x000003f6,0x00000004,0x00000005,
+	0x00000002,0x00000003,0x0003003e,0x000003ea,0x000003f8,0x00050041,0x0000000d,0x000003f9,
+	0x00000384,0x00000029,0x0004003d,0x0000000c,0x000003fa,0x000003f9,0x00060041,0x000000b9,
+	0x000003fb,0x000003a8,0x00000051,0x000003fa,0x0004003d,0x0000000c,0x000003fc,0x000003fb,
+	0x0006000c,0x00000007,0x000003fd,0x00000001,0x00000040,0x000003fc,0x0003003e,0x000003a4,
+	0x000003fd,0x00050041,0x0000000d,0x000003fe,0x0000036c,0x00000029,0x0004003d,0x0000000c,
+	0x000003ff,0x000003fe,0x000500aa,0x00000009,0x00000400,0x000003ff,0x00000024,0x000300f7,
+	0x00000403,0x00000000,0x000400fa,0x00000400,0x00000402,0x00000406,0x000200f8,0x00000402,
+	0x0004003d,0x00000007,0x00000404,0x000003a4,0x0007004f,0x00000017,0x00000405,0x00000404,
+	0x00000404,0x00000000,0x00000001,0x0003003e,0x00000401,0x00000405,0x000200f9,0x00000403,
+	0x000200f8,0x00000406,0x0004003d,0x00000007,0x00000407,0x000003a4,0x0007004f,0x00000017,
+	0x00000408,0x00000407,0x00000407,0x00000002,0x00000003,0x0003003e,0x00000401,0x00000408,
+	0x000200f9,0x00000403,0x000200f8,0x00000403,0x0004003d,0x00000017,0x00000409,0x00000401,
+	0x0004003d,0x00000007,0x0000040a,0x000003ae,0x0009004f,0x00000007,0x0000040b,0x0000040a,
+	0x00000409,0x00000000,0x00000001,0x00000004,0x00000005,0x0003003e,0x000003ae,0x0000040b,
+	0x00050041,0x0000000d,0x0000040c,0x0000038c,0x00000029,0x0004003d,0x0000000c,0x0000040d,
+	0x0000040c,0x00060041,0x000000b9,0x0000040e,0x000003a8,0x00000051,0x0000040d,0x0004003d,
+	0x0000000c,0x0000040f,0x0000040e,0x0006000c,0x00000007,0x00000410,0x00000001,0x00000040,
+	0x0000040f,0x0003003e,0x000003a4,0x00000410,0x00050041,0x0000000d,0x00000411,0x00000372,
+	0x00000029,0x0004003d,0x0000000c,0x00000412,0x00000411,0x000500aa,0x00000009,0x00000413,
+	0x00000412,0x00000024,0x000300f7,0x00000416,0x00000000,0x000400fa,0x00000413,0x00000415,
+	0x00000419,0x000200f8,0x00000415,0x0004003d,0x00000007,0x00000417,0x000003a4,0x0007004f,
+	0x00000017,0x00000418,0x00000417,0x00000417,0x00000000,0x00000001,0x0003003e,0x00000414,
+	0x00000418,0x000200f9,0x00000416,0x000200f8,0x00000419,0x0004003d,0x00000007,0x0000041a,
+	0x000003a4,0x0007004f,0x00000017,0x0000041b,0x0000041a,0x0000041a,0x00000002,0x00000003,
+	0x0003003e,0x00000414,0x0000041b,0x000200f9,0x00000416,0x000200f8,0x00000416,0x0004003d,
+	0x00000017,0x0000041c,0x00000414,0x0004003d,0x00000007,0x0000041d,0x000003c2,0x0009004f,
+	0x00000007,0x0000041e,0x0000041d,0x0000041c,0x00000000,0x00000001,0x00000004,0x00000005,
+	0x0003003e,0x000003c2,0x0000041e,0x00050041,0x0000000d,0x0000041f,0x00000394,0x00000029,
+	0x0004003d,0x0000000c,0x00000420,0x0000041f,0x00060041,0x000000b9,0x00000421,0x000003a8,
+	0x00000051,0x00000420,0x0004003d,0x0000000c,0x00000422,0x00000421,0x0006000c,0x00000007,
+	0x00000423,0x00000001,0x00000040,0x00000422,0x0003003e,0x000003a4,0x00000423,0x00050041,
+	0x0000000d,0x00000424,0x00000378,0x00000029,0x0004003d,0x0000000c,0x00000425,0x00000424,
+	0x000500aa,0x00000009,0x00000426,0x00000425,0x00000024,0x000300f7,0x00000429,0x00000000,
+	0x000400fa,0x00000426,0x00000428,0x0000042c,0x000200f8,0x00000428,0x0004003d,0x00000007,
+	0x0000042a,0x000003a4,0x0007004f,0x00000017,0x0000042b,0x0000042a,0x0000042a,0x00000000,
+	0x00000001,0x0003003e,0x00000427,0x0000042b,0x000200f9,0x00000429,0x000200f8,0x0000042c,
+	0x0004003d,0x00000007,0x0000042d,0x000003a4,0x0007004f,0x00000017,0x0000042e,0x0000042d,
+	0x0000042d,0x00000002,0x00000003,0x0003003e,0x00000427,0x0000042e,0x000200f9,0x00000429,
+	0x000200f8,0x00000429,0x0004003d,0x00000017,0x0000042f,0x00000427,0x0004003d,0x00000007,
+	0x00000430,0x000003d6,0x0009004f,0x00000007,0x00000431,0x00000430,0x0000042f,0x00000000,
+	0x00000001,0x00000004,0x00000005,0x0003003e,0x000003d6,0x00000431,0x00050041,0x0000000d,
+	0x00000432,0x0000039c,0x00000029,0x0004003d,0x0000000c,0x00000433,0x00000432,0x00060041,
+	0x000000b9,0x00000434,0x000003a8,0x00000051,0x00000433,0x0004003d,0x0000000c,0x00000435,
+	0x00000434,0x0006000c,0x00000007,0x00000436,0x00000001,0x00000040,0x00000435,0x0003003e,
+	0x000003a4,0x00000436,0x00050041,0x0000000d,0x00000437,0x0000037e,0x00000029,0x0004003d,
+	0x0000000c,0x00000438,0x00000437,0x000500aa,0x00000009,0x00000439,0x00000438,0x00000024,
+	0x000300f7,0x0000043c,0x00000000,0x000400fa,0x00000439,0x0000043b,0x0000043f,0x000200f8,
+	0x0000043b,0x0004003d,0x00000007,0x0000043d,0x000003a4,0x0007004f,0x00000017,0x0000043e,
+	0x0000043d,0x0000043d,0x00000000,0x00000001,0x0003003e,0x0000043a,0x0000043e,0x000200f9,
+	0x0000043c,0x000200f8,0x0000043f,0x0004003d,0x00000007,0x00000440,0x000003a4,0x0007004f,
+	0x00000017,0x00000441,0x00000440,0x00000440,0x00000002,0x00000003,0x0003003e,0x0000043a,
+	0x00000441,0x000200f9,0x0000043c,0x000200f8,0x0000043c,0x0004003d,0x00000017,0x00000442,
+	0x0000043a,0x0004003d,0x00000007,0x00000443,0x000003ea,0x0009004f,0x00000007,0x00000444,
+	0x00000443,0x00000442,0x00000000,0x00000001,0x00000004,0x00000005,0x0003003e,0x000003ea,
+	0x00000444,0x0004003d,0x00000007,0x00000446,0x000003ae,0x0004003d,0x00000017,0x00000447,
+	0x00000344,0x0009004f,0x00000007,0x00000448,0x00000447,0x00000447,0x00000000,0x00000000,
+	0x00000001,0x00000001,0x00050085,0x00000007,0x00000449,0x00000446,0x00000448,0x0004003d,
+	0x00000007,0x0000044a,0x000003c2,0x0004003d,0x00000017,0x0000044b,0x0000034c,0x0009004f,
+	0x00000007,0x0000044c,0x0000044b,0x0000044b,0x00000000,0x00000000,0x00000001,0x00000001,
+	0x00050085,0x00000007,0x0000044d,0x0000044a,0x0000044c,0x00050081,0x00000007,0x0000044e,
+	0x00000449,0x0000044d,0x0004003d,0x00000007,0x0000044f,0x000003d6,0x0004003d,0x00000017,
+	0x00000450,0x00000352,0x0009004f,0x00000007,0x00000451,0x00000450,0x00000450,0x00000000,
+	0x00000000,0x00000001,0x00000001,0x00050085,0x00000007,0x00000452,0x0000044f,0x00000451,
+	0x00050081,0x00000007,0x00000453,0x0000044e,0x00000452,0x0004003d,0x00000007,0x00000454,
+	0x000003ea,0x0004003d,0x00000017,0x00000455,0x00000358,0x0009004f,0x00000007,0x00000456,
+	0x00000455,0x00000455,0x00000000,0x00000000,0x00000001,0x00000001,0x00050085,0x00000007,
+	0x00000457,0x00000454,0x00000456,0x00050081,0x00000007,0x00000458,0x00000453,0x00000457,
+	0x0003003e,0x00000445,0x00000458,0x0004003d,0x00000007,0x00000459,0x00000445,0x0004003d,
+	0x0000000a,0x0000045a,0x0000001c,0x000400a8,0x0000000a,0x0000045b,0x0000045a,0x000600a9,
+	0x00000007,0x0000045c,0x0000045b,0x00000322,0x00000321,0x00050085,0x00000007,0x0000045d,
+	0x00000459,0x0000045c,0x0004003d,0x0000000a,0x0000045e,0x0000001c,0x000600a9,0x00000007,
+	0x0000045f,0x0000045e,0x00000322,0x00000321,0x0005008e,0x00000007,0x00000460,0x0000045f,
+	0x000000c2,0x00050081,0x00000007,0x00000461,0x0000045d,0x00000460,0x0003003e,0x00000445,
+	0x00000461,0x0004003d,0x00000007,0x00000462,0x00000445,0x0006000c,0x0000000c,0x00000463,
+	0x00000001,0x00000037,0x00000462,0x0003003e,0x0000001d,0x00000463,0x000100fd,0x00010038
diff --git a/shaders/spv/shader_lap_trans_pyr.comp b/shaders/spv/shader_lap_trans_pyr.comp
new file mode 100644
index 0000000..a1f29ee
--- /dev/null
+++ b/shaders/spv/shader_lap_trans_pyr.comp
@@ -0,0 +1,162 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer InBufY {
+    uvec2 data[];
+} in_buf_y;
+
+layout (binding = 1) readonly buffer InBufUV {
+    uvec2 data[];
+} in_buf_uv;
+
+layout (binding = 2) readonly buffer GaussScaleBufY {
+    uint data[];
+} gaussscale_buf_y;
+
+layout (binding = 3) readonly buffer GaussScaleBufUV {
+    uint data[];
+} gaussscale_buf_uv;
+
+layout (binding = 4) writeonly buffer OutBufY {
+    uvec2 data[];
+} out_buf_y;
+
+layout (binding = 5) writeonly buffer OutBufUV {
+    uvec2 data[];
+} out_buf_uv;
+
+layout (push_constant) uniform PushConsts {
+    uint in_img_width;
+    uint in_img_height;
+    uint in_offset_x;
+    uint gaussscale_img_width;
+    uint gaussscale_img_height;
+    uint merge_width;
+} prop;
+
+// normalization of half gray level
+const float norm_half_gl = 128.0f / 255.0f;
+
+void lap_trans_y (uvec2 y_id, uvec2 gs_id);
+void lap_trans_uv (uvec2 uv_id, uvec2 gs_id);
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+
+    uvec2 y_id = uvec2 (g_id.x, g_id.y * 4u);
+    y_id.x = clamp (y_id.x, 0u, prop.merge_width - 1u);
+
+    uvec2 gs_id = uvec2 (g_id.x, g_id.y * 2u);
+    gs_id.x = clamp (gs_id.x, 0u, prop.gaussscale_img_width - 1u);
+    lap_trans_y (y_id, gs_id);
+
+    y_id.y += 2u;
+    gs_id.y += 1u;
+    lap_trans_y (y_id, gs_id);
+
+    uvec2 uv_id = uvec2 (y_id.x, g_id.y * 2u);
+    gs_id.y = g_id.y;
+    lap_trans_uv (uv_id, gs_id);
+}
+
+void lap_trans_y (uvec2 y_id, uvec2 gs_id)
+{
+    y_id.y = clamp (y_id.y, 0u, prop.in_img_height - 1u);
+    gs_id.y = clamp (gs_id.y, 0u, prop.gaussscale_img_height - 1u);
+
+    uint y_idx = y_id.y * prop.in_img_width + prop.in_offset_x + y_id.x;
+    uvec2 in_pack = in_buf_y.data[y_idx];
+    vec4 in0 = unpackUnorm4x8 (in_pack.x);
+    vec4 in1 = unpackUnorm4x8 (in_pack.y);
+
+    uint gs_idx = gs_id.y * prop.gaussscale_img_width + gs_id.x;
+    vec4 gs0 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx]);
+    vec4 gs1 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == prop.gaussscale_img_width - 1u) ? gs0.wwww : gs1;
+
+    vec4 inter = (gs0 + vec4 (gs0.yzw, gs1.x)) * 0.5f;
+    vec4 inter00 = vec4 (gs0.x, inter.x, gs0.y, inter.y);
+    vec4 inter01 = vec4 (gs0.z, inter.z, gs0.w, inter.w);
+
+    vec4 lap0 = (in0 - inter00) * 0.5f + norm_half_gl;
+    vec4 lap1 = (in1 - inter01) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    uint out_idx = y_id.y * prop.merge_width + y_id.x;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+
+    y_idx = (y_id.y >= prop.in_img_height - 1u) ? y_idx : y_idx + prop.in_img_width;
+    in_pack = in_buf_y.data[y_idx];
+    in0 = unpackUnorm4x8 (in_pack.x);
+    in1 = unpackUnorm4x8 (in_pack.y);
+
+    gs_idx = (gs_id.y >= prop.gaussscale_img_height - 1u) ? gs_idx : gs_idx + prop.gaussscale_img_width;
+    gs0 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx]);
+    gs1 = unpackUnorm4x8 (gaussscale_buf_y.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == prop.gaussscale_img_width - 1u) ? gs0.wwww : gs1;
+
+    inter = (gs0 + vec4 (gs0.yzw, gs1.x)) * 0.5f;
+    vec4 inter10 = (inter00 + vec4 (gs0.x, inter.x, gs0.y, inter.y)) * 0.5f;
+    vec4 inter11 = (inter01 + vec4 (gs0.z, inter.z, gs0.w, inter.w)) * 0.5f;
+
+    lap0 = (in0 - inter10) * 0.5f + norm_half_gl;
+    lap1 = (in1 - inter11) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    out_idx = (y_id.y >= prop.in_img_height - 1u) ? out_idx : out_idx + prop.merge_width;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+}
+
+void lap_trans_uv (uvec2 uv_id, uvec2 gs_id)
+{
+    uv_id.y = clamp (uv_id.y, 0u, prop.in_img_height / 2u - 1u);
+    gs_id.y = clamp (gs_id.y, 0u, prop.gaussscale_img_height / 2u - 1u);
+
+    uint uv_idx = uv_id.y * prop.in_img_width + prop.in_offset_x + uv_id.x;
+    uvec2 in_pack = in_buf_uv.data[uv_idx];
+    vec4 in0 = unpackUnorm4x8 (in_pack.x);
+    vec4 in1 = unpackUnorm4x8 (in_pack.y);
+
+    uint gs_idx = gs_id.y * prop.gaussscale_img_width + gs_id.x;
+    vec4 gs0 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx]);
+    vec4 gs1 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == prop.gaussscale_img_width - 1u) ? gs0.zwzw : gs1;
+
+    vec4 inter = (gs0 + vec4 (gs0.zw, gs1.xy)) * 0.5f;
+    vec4 inter00 = vec4 (gs0.xy, inter.xy);
+    vec4 inter01 = vec4 (gs0.zw, inter.zw);
+
+    vec4 lap0 = (in0 - inter00) * 0.5f + norm_half_gl;
+    vec4 lap1 = (in1 - inter01) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    uint out_idx = uv_id.y * prop.merge_width + uv_id.x;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+
+    uv_idx = (uv_id.y >= (prop.in_img_height / 2u - 1u)) ? uv_idx : uv_idx + prop.in_img_width;
+    in_pack = in_buf_uv.data[uv_idx];
+    in0 = unpackUnorm4x8 (in_pack.x);
+    in1 = unpackUnorm4x8 (in_pack.y);
+
+    gs_idx = (gs_id.y >= (prop.gaussscale_img_height / 2u - 1u)) ? gs_idx : gs_idx + prop.gaussscale_img_width;
+    gs0 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx]);
+    gs1 = unpackUnorm4x8 (gaussscale_buf_uv.data[gs_idx + 1u]);
+    gs1 = (gs_id.x == prop.gaussscale_img_width - 1u) ? gs0.zwzw : gs1;
+
+    inter = (gs0 + vec4 (gs0.zw, gs1.xy)) * 0.5f;
+    vec4 inter10 = (inter00 + vec4 (gs0.xy, inter.xy)) * 0.5f;
+    vec4 inter11 = (inter01 + vec4 (gs0.zw, inter.zw)) * 0.5f;
+
+    lap0 = (in0 - inter10) * 0.5f + norm_half_gl;
+    lap1 = (in1 - inter11) * 0.5f + norm_half_gl;
+    lap0 = clamp (lap0, 0.0f, 1.0f);
+    lap1 = clamp (lap1, 0.0f, 1.0f);
+
+    out_idx += prop.merge_width;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (lap0), packUnorm4x8 (lap1));
+}
diff --git a/shaders/spv/shader_lap_trans_pyr.comp.spv b/shaders/spv/shader_lap_trans_pyr.comp.spv
new file mode 100644
index 0000000..d137ab2
--- /dev/null
+++ b/shaders/spv/shader_lap_trans_pyr.comp.spv
@@ -0,0 +1,536 @@
+	// 7.8.2870
+	0x07230203,0x00010000,0x00080007,0x000002c3,0x00000000,0x00020011,0x00000001,0x0006000b,
+	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x00000015,0x00060010,0x00000004,
+	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000001,0x00000136,0x00040005,
+	0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c,0x5f70616c,0x6e617274,0x28795f73,
+	0x3b327576,0x3b327576,0x00000000,0x00040005,0x0000000a,0x64695f79,0x00000000,0x00040005,
+	0x0000000b,0x695f7367,0x00000064,0x00080005,0x00000010,0x5f70616c,0x6e617274,0x76755f73,
+	0x32757628,0x3275763b,0x0000003b,0x00040005,0x0000000e,0x695f7675,0x00000064,0x00040005,
+	0x0000000f,0x695f7367,0x00000064,0x00040005,0x00000012,0x64695f67,0x00000000,0x00080005,
+	0x00000015,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00040005,
+	0x00000018,0x64695f79,0x00000000,0x00050005,0x00000025,0x68737550,0x736e6f43,0x00007374,
+	0x00070006,0x00000025,0x00000000,0x695f6e69,0x775f676d,0x68746469,0x00000000,0x00070006,
+	0x00000025,0x00000001,0x695f6e69,0x685f676d,0x68676965,0x00000074,0x00060006,0x00000025,
+	0x00000002,0x6f5f6e69,0x65736666,0x00785f74,0x00090006,0x00000025,0x00000003,0x73756167,
+	0x61637373,0x695f656c,0x775f676d,0x68746469,0x00000000,0x00090006,0x00000025,0x00000004,
+	0x73756167,0x61637373,0x695f656c,0x685f676d,0x68676965,0x00000074,0x00060006,0x00000025,
+	0x00000005,0x6772656d,0x69775f65,0x00687464,0x00040005,0x00000027,0x706f7270,0x00000000,
+	0x00040005,0x00000030,0x695f7367,0x00000064,0x00040005,0x00000040,0x61726170,0x0000006d,
+	0x00040005,0x00000042,0x61726170,0x0000006d,0x00040005,0x0000004d,0x61726170,0x0000006d,
+	0x00040005,0x0000004f,0x61726170,0x0000006d,0x00040005,0x00000052,0x695f7675,0x00000064,
+	0x00040005,0x0000005c,0x61726170,0x0000006d,0x00040005,0x0000005e,0x61726170,0x0000006d,
+	0x00040005,0x00000071,0x64695f79,0x00000078,0x00040005,0x0000007f,0x705f6e69,0x006b6361,
+	0x00040005,0x00000081,0x75426e49,0x00005966,0x00050006,0x00000081,0x00000000,0x61746164,
+	0x00000000,0x00050005,0x00000083,0x625f6e69,0x795f6675,0x00000000,0x00030005,0x0000008b,
+	0x00306e69,0x00030005,0x0000008f,0x00316e69,0x00040005,0x00000093,0x695f7367,0x00007864,
+	0x00030005,0x0000009c,0x00307367,0x00060005,0x0000009e,0x73756147,0x61635373,0x7542656c,
+	0x00005966,0x00050006,0x0000009e,0x00000000,0x61746164,0x00000000,0x00070005,0x000000a0,
+	0x73756167,0x61637373,0x625f656c,0x795f6675,0x00000000,0x00030005,0x000000a6,0x00317367,
+	0x00040005,0x000000bb,0x65746e69,0x00000072,0x00040005,0x000000ca,0x65746e69,0x00303072,
+	0x00040005,0x000000d4,0x65746e69,0x00313072,0x00040005,0x000000df,0x3070616c,0x00000000,
+	0x00040005,0x000000e7,0x3170616c,0x00000000,0x00040005,0x000000f8,0x5f74756f,0x00786469,
+	0x00040005,0x00000102,0x4274754f,0x00596675,0x00050006,0x00000102,0x00000000,0x61746164,
+	0x00000000,0x00050005,0x00000104,0x5f74756f,0x5f667562,0x00000079,0x00040005,0x00000157,
+	0x65746e69,0x00303172,0x00040005,0x00000164,0x65746e69,0x00313172,0x00040005,0x000001ac,
+	0x695f7675,0x00007864,0x00040005,0x000001b8,0x705f6e69,0x006b6361,0x00040005,0x000001ba,
+	0x75426e49,0x00565566,0x00050006,0x000001ba,0x00000000,0x61746164,0x00000000,0x00050005,
+	0x000001bc,0x625f6e69,0x755f6675,0x00000076,0x00030005,0x000001c0,0x00306e69,0x00030005,
+	0x000001c4,0x00316e69,0x00040005,0x000001c8,0x695f7367,0x00007864,0x00030005,0x000001d1,
+	0x00307367,0x00060005,0x000001d3,0x73756147,0x61635373,0x7542656c,0x00565566,0x00050006,
+	0x000001d3,0x00000000,0x61746164,0x00000000,0x00070005,0x000001d5,0x73756167,0x61637373,
+	0x625f656c,0x755f6675,0x00000076,0x00030005,0x000001da,0x00317367,0x00040005,0x000001ee,
+	0x65746e69,0x00000072,0x00040005,0x000001fc,0x65746e69,0x00303072,0x00040005,0x00000206,
+	0x65746e69,0x00313072,0x00040005,0x00000210,0x3070616c,0x00000000,0x00040005,0x00000217,
+	0x3170616c,0x00000000,0x00040005,0x00000226,0x5f74756f,0x00786469,0x00050005,0x00000230,
+	0x4274754f,0x56556675,0x00000000,0x00050006,0x00000230,0x00000000,0x61746164,0x00000000,
+	0x00050005,0x00000232,0x5f74756f,0x5f667562,0x00007675,0x00040005,0x00000288,0x65746e69,
+	0x00303172,0x00040005,0x00000295,0x65746e69,0x00313172,0x00040047,0x00000015,0x0000000b,
+	0x0000001c,0x00050048,0x00000025,0x00000000,0x00000023,0x00000000,0x00050048,0x00000025,
+	0x00000001,0x00000023,0x00000004,0x00050048,0x00000025,0x00000002,0x00000023,0x00000008,
+	0x00050048,0x00000025,0x00000003,0x00000023,0x0000000c,0x00050048,0x00000025,0x00000004,
+	0x00000023,0x00000010,0x00050048,0x00000025,0x00000005,0x00000023,0x00000014,0x00030047,
+	0x00000025,0x00000002,0x00040047,0x00000080,0x00000006,0x00000008,0x00040048,0x00000081,
+	0x00000000,0x00000018,0x00050048,0x00000081,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x00000081,0x00000003,0x00040047,0x00000083,0x00000022,0x00000000,0x00040047,0x00000083,
+	0x00000021,0x00000000,0x00040047,0x0000009d,0x00000006,0x00000004,0x00040048,0x0000009e,
+	0x00000000,0x00000018,0x00050048,0x0000009e,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x0000009e,0x00000003,0x00040047,0x000000a0,0x00000022,0x00000000,0x00040047,0x000000a0,
+	0x00000021,0x00000002,0x00040047,0x00000101,0x00000006,0x00000008,0x00040048,0x00000102,
+	0x00000000,0x00000019,0x00050048,0x00000102,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x00000102,0x00000003,0x00040047,0x00000104,0x00000022,0x00000000,0x00040047,0x00000104,
+	0x00000021,0x00000004,0x00040047,0x000001b9,0x00000006,0x00000008,0x00040048,0x000001ba,
+	0x00000000,0x00000018,0x00050048,0x000001ba,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x000001ba,0x00000003,0x00040047,0x000001bc,0x00000022,0x00000000,0x00040047,0x000001bc,
+	0x00000021,0x00000001,0x00040047,0x000001d2,0x00000006,0x00000004,0x00040048,0x000001d3,
+	0x00000000,0x00000018,0x00050048,0x000001d3,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x000001d3,0x00000003,0x00040047,0x000001d5,0x00000022,0x00000000,0x00040047,0x000001d5,
+	0x00000021,0x00000003,0x00040047,0x0000022f,0x00000006,0x00000008,0x00040048,0x00000230,
+	0x00000000,0x00000019,0x00050048,0x00000230,0x00000000,0x00000023,0x00000000,0x00030047,
+	0x00000230,0x00000003,0x00040047,0x00000232,0x00000022,0x00000000,0x00040047,0x00000232,
+	0x00000021,0x00000005,0x00040047,0x000002c2,0x0000000b,0x00000019,0x00020013,0x00000002,
+	0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,0x00040017,
+	0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00050021,
+	0x00000009,0x00000002,0x00000008,0x00000008,0x00040017,0x00000013,0x00000006,0x00000003,
+	0x00040020,0x00000014,0x00000001,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000001,
+	0x0004002b,0x00000006,0x00000019,0x00000000,0x00040020,0x0000001a,0x00000007,0x00000006,
+	0x0004002b,0x00000006,0x0000001d,0x00000001,0x0004002b,0x00000006,0x00000020,0x00000004,
+	0x0008001e,0x00000025,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,
+	0x00040020,0x00000026,0x00000009,0x00000025,0x0004003b,0x00000026,0x00000027,0x00000009,
+	0x00040015,0x00000028,0x00000020,0x00000001,0x0004002b,0x00000028,0x00000029,0x00000005,
+	0x00040020,0x0000002a,0x00000009,0x00000006,0x0004002b,0x00000006,0x00000035,0x00000002,
+	0x0004002b,0x00000028,0x0000003a,0x00000003,0x0004002b,0x00000028,0x00000063,0x00000001,
+	0x0004002b,0x00000028,0x0000006b,0x00000004,0x0004002b,0x00000028,0x00000074,0x00000000,
+	0x0004002b,0x00000028,0x00000078,0x00000002,0x0003001d,0x00000080,0x00000007,0x0003001e,
+	0x00000081,0x00000080,0x00040020,0x00000082,0x00000002,0x00000081,0x0004003b,0x00000082,
+	0x00000083,0x00000002,0x00040020,0x00000085,0x00000002,0x00000007,0x00030016,0x00000088,
+	0x00000020,0x00040017,0x00000089,0x00000088,0x00000004,0x00040020,0x0000008a,0x00000007,
+	0x00000089,0x0003001d,0x0000009d,0x00000006,0x0003001e,0x0000009e,0x0000009d,0x00040020,
+	0x0000009f,0x00000002,0x0000009e,0x0004003b,0x0000009f,0x000000a0,0x00000002,0x00040020,
+	0x000000a2,0x00000002,0x00000006,0x00020014,0x000000b1,0x00040017,0x000000bd,0x00000088,
+	0x00000003,0x00040020,0x000000c0,0x00000007,0x00000088,0x0004002b,0x00000088,0x000000c8,
+	0x3f000000,0x0004002b,0x00000006,0x000000d9,0x00000003,0x0004002b,0x00000088,0x000000e4,
+	0x3f008081,0x0004002b,0x00000088,0x000000ef,0x00000000,0x0004002b,0x00000088,0x000000f0,
+	0x3f800000,0x0003001d,0x00000101,0x00000007,0x0003001e,0x00000102,0x00000101,0x00040020,
+	0x00000103,0x00000002,0x00000102,0x0004003b,0x00000103,0x00000104,0x00000002,0x0003001d,
+	0x000001b9,0x00000007,0x0003001e,0x000001ba,0x000001b9,0x00040020,0x000001bb,0x00000002,
+	0x000001ba,0x0004003b,0x000001bb,0x000001bc,0x00000002,0x0003001d,0x000001d2,0x00000006,
+	0x0003001e,0x000001d3,0x000001d2,0x00040020,0x000001d4,0x00000002,0x000001d3,0x0004003b,
+	0x000001d4,0x000001d5,0x00000002,0x00040017,0x000001f0,0x00000088,0x00000002,0x0003001d,
+	0x0000022f,0x00000007,0x0003001e,0x00000230,0x0000022f,0x00040020,0x00000231,0x00000002,
+	0x00000230,0x0004003b,0x00000231,0x00000232,0x00000002,0x0004002b,0x00000006,0x000002c1,
+	0x00000008,0x0006002c,0x00000013,0x000002c2,0x000002c1,0x000002c1,0x0000001d,0x00050036,
+	0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,
+	0x00000012,0x00000007,0x0004003b,0x00000008,0x00000018,0x00000007,0x0004003b,0x00000008,
+	0x00000030,0x00000007,0x0004003b,0x00000008,0x00000040,0x00000007,0x0004003b,0x00000008,
+	0x00000042,0x00000007,0x0004003b,0x00000008,0x0000004d,0x00000007,0x0004003b,0x00000008,
+	0x0000004f,0x00000007,0x0004003b,0x00000008,0x00000052,0x00000007,0x0004003b,0x00000008,
+	0x0000005c,0x00000007,0x0004003b,0x00000008,0x0000005e,0x00000007,0x0004003d,0x00000013,
+	0x00000016,0x00000015,0x0007004f,0x00000007,0x00000017,0x00000016,0x00000016,0x00000000,
+	0x00000001,0x0003003e,0x00000012,0x00000017,0x00050041,0x0000001a,0x0000001b,0x00000012,
+	0x00000019,0x0004003d,0x00000006,0x0000001c,0x0000001b,0x00050041,0x0000001a,0x0000001e,
+	0x00000012,0x0000001d,0x0004003d,0x00000006,0x0000001f,0x0000001e,0x00050084,0x00000006,
+	0x00000021,0x0000001f,0x00000020,0x00050050,0x00000007,0x00000022,0x0000001c,0x00000021,
+	0x0003003e,0x00000018,0x00000022,0x00050041,0x0000001a,0x00000023,0x00000018,0x00000019,
+	0x0004003d,0x00000006,0x00000024,0x00000023,0x00050041,0x0000002a,0x0000002b,0x00000027,
+	0x00000029,0x0004003d,0x00000006,0x0000002c,0x0000002b,0x00050082,0x00000006,0x0000002d,
+	0x0000002c,0x0000001d,0x0008000c,0x00000006,0x0000002e,0x00000001,0x0000002c,0x00000024,
+	0x00000019,0x0000002d,0x00050041,0x0000001a,0x0000002f,0x00000018,0x00000019,0x0003003e,
+	0x0000002f,0x0000002e,0x00050041,0x0000001a,0x00000031,0x00000012,0x00000019,0x0004003d,
+	0x00000006,0x00000032,0x00000031,0x00050041,0x0000001a,0x00000033,0x00000012,0x0000001d,
+	0x0004003d,0x00000006,0x00000034,0x00000033,0x00050084,0x00000006,0x00000036,0x00000034,
+	0x00000035,0x00050050,0x00000007,0x00000037,0x00000032,0x00000036,0x0003003e,0x00000030,
+	0x00000037,0x00050041,0x0000001a,0x00000038,0x00000030,0x00000019,0x0004003d,0x00000006,
+	0x00000039,0x00000038,0x00050041,0x0000002a,0x0000003b,0x00000027,0x0000003a,0x0004003d,
+	0x00000006,0x0000003c,0x0000003b,0x00050082,0x00000006,0x0000003d,0x0000003c,0x0000001d,
+	0x0008000c,0x00000006,0x0000003e,0x00000001,0x0000002c,0x00000039,0x00000019,0x0000003d,
+	0x00050041,0x0000001a,0x0000003f,0x00000030,0x00000019,0x0003003e,0x0000003f,0x0000003e,
+	0x0004003d,0x00000007,0x00000041,0x00000018,0x0003003e,0x00000040,0x00000041,0x0004003d,
+	0x00000007,0x00000043,0x00000030,0x0003003e,0x00000042,0x00000043,0x00060039,0x00000002,
+	0x00000044,0x0000000c,0x00000040,0x00000042,0x00050041,0x0000001a,0x00000045,0x00000018,
+	0x0000001d,0x0004003d,0x00000006,0x00000046,0x00000045,0x00050080,0x00000006,0x00000047,
+	0x00000046,0x00000035,0x00050041,0x0000001a,0x00000048,0x00000018,0x0000001d,0x0003003e,
+	0x00000048,0x00000047,0x00050041,0x0000001a,0x00000049,0x00000030,0x0000001d,0x0004003d,
+	0x00000006,0x0000004a,0x00000049,0x00050080,0x00000006,0x0000004b,0x0000004a,0x0000001d,
+	0x00050041,0x0000001a,0x0000004c,0x00000030,0x0000001d,0x0003003e,0x0000004c,0x0000004b,
+	0x0004003d,0x00000007,0x0000004e,0x00000018,0x0003003e,0x0000004d,0x0000004e,0x0004003d,
+	0x00000007,0x00000050,0x00000030,0x0003003e,0x0000004f,0x00000050,0x00060039,0x00000002,
+	0x00000051,0x0000000c,0x0000004d,0x0000004f,0x00050041,0x0000001a,0x00000053,0x00000018,
+	0x00000019,0x0004003d,0x00000006,0x00000054,0x00000053,0x00050041,0x0000001a,0x00000055,
+	0x00000012,0x0000001d,0x0004003d,0x00000006,0x00000056,0x00000055,0x00050084,0x00000006,
+	0x00000057,0x00000056,0x00000035,0x00050050,0x00000007,0x00000058,0x00000054,0x00000057,
+	0x0003003e,0x00000052,0x00000058,0x00050041,0x0000001a,0x00000059,0x00000012,0x0000001d,
+	0x0004003d,0x00000006,0x0000005a,0x00000059,0x00050041,0x0000001a,0x0000005b,0x00000030,
+	0x0000001d,0x0003003e,0x0000005b,0x0000005a,0x0004003d,0x00000007,0x0000005d,0x00000052,
+	0x0003003e,0x0000005c,0x0000005d,0x0004003d,0x00000007,0x0000005f,0x00000030,0x0003003e,
+	0x0000005e,0x0000005f,0x00060039,0x00000002,0x00000060,0x00000010,0x0000005c,0x0000005e,
+	0x000100fd,0x00010038,0x00050036,0x00000002,0x0000000c,0x00000000,0x00000009,0x00030037,
+	0x00000008,0x0000000a,0x00030037,0x00000008,0x0000000b,0x000200f8,0x0000000d,0x0004003b,
+	0x0000001a,0x00000071,0x00000007,0x0004003b,0x00000008,0x0000007f,0x00000007,0x0004003b,
+	0x0000008a,0x0000008b,0x00000007,0x0004003b,0x0000008a,0x0000008f,0x00000007,0x0004003b,
+	0x0000001a,0x00000093,0x00000007,0x0004003b,0x0000008a,0x0000009c,0x00000007,0x0004003b,
+	0x0000008a,0x000000a6,0x00000007,0x0004003b,0x0000008a,0x000000b3,0x00000007,0x0004003b,
+	0x0000008a,0x000000bb,0x00000007,0x0004003b,0x0000008a,0x000000ca,0x00000007,0x0004003b,
+	0x0000008a,0x000000d4,0x00000007,0x0004003b,0x0000008a,0x000000df,0x00000007,0x0004003b,
+	0x0000008a,0x000000e7,0x00000007,0x0004003b,0x0000001a,0x000000f8,0x00000007,0x0004003b,
+	0x0000001a,0x00000112,0x00000007,0x0004003b,0x0000001a,0x0000012b,0x00000007,0x0004003b,
+	0x0000008a,0x00000144,0x00000007,0x0004003b,0x0000008a,0x00000157,0x00000007,0x0004003b,
+	0x0000008a,0x00000164,0x00000007,0x0004003b,0x0000001a,0x0000018b,0x00000007,0x00050041,
+	0x0000001a,0x00000061,0x0000000a,0x0000001d,0x0004003d,0x00000006,0x00000062,0x00000061,
+	0x00050041,0x0000002a,0x00000064,0x00000027,0x00000063,0x0004003d,0x00000006,0x00000065,
+	0x00000064,0x00050082,0x00000006,0x00000066,0x00000065,0x0000001d,0x0008000c,0x00000006,
+	0x00000067,0x00000001,0x0000002c,0x00000062,0x00000019,0x00000066,0x00050041,0x0000001a,
+	0x00000068,0x0000000a,0x0000001d,0x0003003e,0x00000068,0x00000067,0x00050041,0x0000001a,
+	0x00000069,0x0000000b,0x0000001d,0x0004003d,0x00000006,0x0000006a,0x00000069,0x00050041,
+	0x0000002a,0x0000006c,0x00000027,0x0000006b,0x0004003d,0x00000006,0x0000006d,0x0000006c,
+	0x00050082,0x00000006,0x0000006e,0x0000006d,0x0000001d,0x0008000c,0x00000006,0x0000006f,
+	0x00000001,0x0000002c,0x0000006a,0x00000019,0x0000006e,0x00050041,0x0000001a,0x00000070,
+	0x0000000b,0x0000001d,0x0003003e,0x00000070,0x0000006f,0x00050041,0x0000001a,0x00000072,
+	0x0000000a,0x0000001d,0x0004003d,0x00000006,0x00000073,0x00000072,0x00050041,0x0000002a,
+	0x00000075,0x00000027,0x00000074,0x0004003d,0x00000006,0x00000076,0x00000075,0x00050084,
+	0x00000006,0x00000077,0x00000073,0x00000076,0x00050041,0x0000002a,0x00000079,0x00000027,
+	0x00000078,0x0004003d,0x00000006,0x0000007a,0x00000079,0x00050080,0x00000006,0x0000007b,
+	0x00000077,0x0000007a,0x00050041,0x0000001a,0x0000007c,0x0000000a,0x00000019,0x0004003d,
+	0x00000006,0x0000007d,0x0000007c,0x00050080,0x00000006,0x0000007e,0x0000007b,0x0000007d,
+	0x0003003e,0x00000071,0x0000007e,0x0004003d,0x00000006,0x00000084,0x00000071,0x00060041,
+	0x00000085,0x00000086,0x00000083,0x00000074,0x00000084,0x0004003d,0x00000007,0x00000087,
+	0x00000086,0x0003003e,0x0000007f,0x00000087,0x00050041,0x0000001a,0x0000008c,0x0000007f,
+	0x00000019,0x0004003d,0x00000006,0x0000008d,0x0000008c,0x0006000c,0x00000089,0x0000008e,
+	0x00000001,0x00000040,0x0000008d,0x0003003e,0x0000008b,0x0000008e,0x00050041,0x0000001a,
+	0x00000090,0x0000007f,0x0000001d,0x0004003d,0x00000006,0x00000091,0x00000090,0x0006000c,
+	0x00000089,0x00000092,0x00000001,0x00000040,0x00000091,0x0003003e,0x0000008f,0x00000092,
+	0x00050041,0x0000001a,0x00000094,0x0000000b,0x0000001d,0x0004003d,0x00000006,0x00000095,
+	0x00000094,0x00050041,0x0000002a,0x00000096,0x00000027,0x0000003a,0x0004003d,0x00000006,
+	0x00000097,0x00000096,0x00050084,0x00000006,0x00000098,0x00000095,0x00000097,0x00050041,
+	0x0000001a,0x00000099,0x0000000b,0x00000019,0x0004003d,0x00000006,0x0000009a,0x00000099,
+	0x00050080,0x00000006,0x0000009b,0x00000098,0x0000009a,0x0003003e,0x00000093,0x0000009b,
+	0x0004003d,0x00000006,0x000000a1,0x00000093,0x00060041,0x000000a2,0x000000a3,0x000000a0,
+	0x00000074,0x000000a1,0x0004003d,0x00000006,0x000000a4,0x000000a3,0x0006000c,0x00000089,
+	0x000000a5,0x00000001,0x00000040,0x000000a4,0x0003003e,0x0000009c,0x000000a5,0x0004003d,
+	0x00000006,0x000000a7,0x00000093,0x00050080,0x00000006,0x000000a8,0x000000a7,0x0000001d,
+	0x00060041,0x000000a2,0x000000a9,0x000000a0,0x00000074,0x000000a8,0x0004003d,0x00000006,
+	0x000000aa,0x000000a9,0x0006000c,0x00000089,0x000000ab,0x00000001,0x00000040,0x000000aa,
+	0x0003003e,0x000000a6,0x000000ab,0x00050041,0x0000001a,0x000000ac,0x0000000b,0x00000019,
+	0x0004003d,0x00000006,0x000000ad,0x000000ac,0x00050041,0x0000002a,0x000000ae,0x00000027,
+	0x0000003a,0x0004003d,0x00000006,0x000000af,0x000000ae,0x00050082,0x00000006,0x000000b0,
+	0x000000af,0x0000001d,0x000500aa,0x000000b1,0x000000b2,0x000000ad,0x000000b0,0x000300f7,
+	0x000000b5,0x00000000,0x000400fa,0x000000b2,0x000000b4,0x000000b8,0x000200f8,0x000000b4,
+	0x0004003d,0x00000089,0x000000b6,0x0000009c,0x0009004f,0x00000089,0x000000b7,0x000000b6,
+	0x000000b6,0x00000003,0x00000003,0x00000003,0x00000003,0x0003003e,0x000000b3,0x000000b7,
+	0x000200f9,0x000000b5,0x000200f8,0x000000b8,0x0004003d,0x00000089,0x000000b9,0x000000a6,
+	0x0003003e,0x000000b3,0x000000b9,0x000200f9,0x000000b5,0x000200f8,0x000000b5,0x0004003d,
+	0x00000089,0x000000ba,0x000000b3,0x0003003e,0x000000a6,0x000000ba,0x0004003d,0x00000089,
+	0x000000bc,0x0000009c,0x0004003d,0x00000089,0x000000be,0x0000009c,0x0008004f,0x000000bd,
+	0x000000bf,0x000000be,0x000000be,0x00000001,0x00000002,0x00000003,0x00050041,0x000000c0,
+	0x000000c1,0x000000a6,0x00000019,0x0004003d,0x00000088,0x000000c2,0x000000c1,0x00050051,
+	0x00000088,0x000000c3,0x000000bf,0x00000000,0x00050051,0x00000088,0x000000c4,0x000000bf,
+	0x00000001,0x00050051,0x00000088,0x000000c5,0x000000bf,0x00000002,0x00070050,0x00000089,
+	0x000000c6,0x000000c3,0x000000c4,0x000000c5,0x000000c2,0x00050081,0x00000089,0x000000c7,
+	0x000000bc,0x000000c6,0x0005008e,0x00000089,0x000000c9,0x000000c7,0x000000c8,0x0003003e,
+	0x000000bb,0x000000c9,0x00050041,0x000000c0,0x000000cb,0x0000009c,0x00000019,0x0004003d,
+	0x00000088,0x000000cc,0x000000cb,0x00050041,0x000000c0,0x000000cd,0x000000bb,0x00000019,
+	0x0004003d,0x00000088,0x000000ce,0x000000cd,0x00050041,0x000000c0,0x000000cf,0x0000009c,
+	0x0000001d,0x0004003d,0x00000088,0x000000d0,0x000000cf,0x00050041,0x000000c0,0x000000d1,
+	0x000000bb,0x0000001d,0x0004003d,0x00000088,0x000000d2,0x000000d1,0x00070050,0x00000089,
+	0x000000d3,0x000000cc,0x000000ce,0x000000d0,0x000000d2,0x0003003e,0x000000ca,0x000000d3,
+	0x00050041,0x000000c0,0x000000d5,0x0000009c,0x00000035,0x0004003d,0x00000088,0x000000d6,
+	0x000000d5,0x00050041,0x000000c0,0x000000d7,0x000000bb,0x00000035,0x0004003d,0x00000088,
+	0x000000d8,0x000000d7,0x00050041,0x000000c0,0x000000da,0x0000009c,0x000000d9,0x0004003d,
+	0x00000088,0x000000db,0x000000da,0x00050041,0x000000c0,0x000000dc,0x000000bb,0x000000d9,
+	0x0004003d,0x00000088,0x000000dd,0x000000dc,0x00070050,0x00000089,0x000000de,0x000000d6,
+	0x000000d8,0x000000db,0x000000dd,0x0003003e,0x000000d4,0x000000de,0x0004003d,0x00000089,
+	0x000000e0,0x0000008b,0x0004003d,0x00000089,0x000000e1,0x000000ca,0x00050083,0x00000089,
+	0x000000e2,0x000000e0,0x000000e1,0x0005008e,0x00000089,0x000000e3,0x000000e2,0x000000c8,
+	0x00070050,0x00000089,0x000000e5,0x000000e4,0x000000e4,0x000000e4,0x000000e4,0x00050081,
+	0x00000089,0x000000e6,0x000000e3,0x000000e5,0x0003003e,0x000000df,0x000000e6,0x0004003d,
+	0x00000089,0x000000e8,0x0000008f,0x0004003d,0x00000089,0x000000e9,0x000000d4,0x00050083,
+	0x00000089,0x000000ea,0x000000e8,0x000000e9,0x0005008e,0x00000089,0x000000eb,0x000000ea,
+	0x000000c8,0x00070050,0x00000089,0x000000ec,0x000000e4,0x000000e4,0x000000e4,0x000000e4,
+	0x00050081,0x00000089,0x000000ed,0x000000eb,0x000000ec,0x0003003e,0x000000e7,0x000000ed,
+	0x0004003d,0x00000089,0x000000ee,0x000000df,0x00070050,0x00000089,0x000000f1,0x000000ef,
+	0x000000ef,0x000000ef,0x000000ef,0x00070050,0x00000089,0x000000f2,0x000000f0,0x000000f0,
+	0x000000f0,0x000000f0,0x0008000c,0x00000089,0x000000f3,0x00000001,0x0000002b,0x000000ee,
+	0x000000f1,0x000000f2,0x0003003e,0x000000df,0x000000f3,0x0004003d,0x00000089,0x000000f4,
+	0x000000e7,0x00070050,0x00000089,0x000000f5,0x000000ef,0x000000ef,0x000000ef,0x000000ef,
+	0x00070050,0x00000089,0x000000f6,0x000000f0,0x000000f0,0x000000f0,0x000000f0,0x0008000c,
+	0x00000089,0x000000f7,0x00000001,0x0000002b,0x000000f4,0x000000f5,0x000000f6,0x0003003e,
+	0x000000e7,0x000000f7,0x00050041,0x0000001a,0x000000f9,0x0000000a,0x0000001d,0x0004003d,
+	0x00000006,0x000000fa,0x000000f9,0x00050041,0x0000002a,0x000000fb,0x00000027,0x00000029,
+	0x0004003d,0x00000006,0x000000fc,0x000000fb,0x00050084,0x00000006,0x000000fd,0x000000fa,
+	0x000000fc,0x00050041,0x0000001a,0x000000fe,0x0000000a,0x00000019,0x0004003d,0x00000006,
+	0x000000ff,0x000000fe,0x00050080,0x00000006,0x00000100,0x000000fd,0x000000ff,0x0003003e,
+	0x000000f8,0x00000100,0x0004003d,0x00000006,0x00000105,0x000000f8,0x0004003d,0x00000089,
+	0x00000106,0x000000df,0x0006000c,0x00000006,0x00000107,0x00000001,0x00000037,0x00000106,
+	0x0004003d,0x00000089,0x00000108,0x000000e7,0x0006000c,0x00000006,0x00000109,0x00000001,
+	0x00000037,0x00000108,0x00050050,0x00000007,0x0000010a,0x00000107,0x00000109,0x00060041,
+	0x00000085,0x0000010b,0x00000104,0x00000074,0x00000105,0x0003003e,0x0000010b,0x0000010a,
+	0x00050041,0x0000001a,0x0000010c,0x0000000a,0x0000001d,0x0004003d,0x00000006,0x0000010d,
+	0x0000010c,0x00050041,0x0000002a,0x0000010e,0x00000027,0x00000063,0x0004003d,0x00000006,
+	0x0000010f,0x0000010e,0x00050082,0x00000006,0x00000110,0x0000010f,0x0000001d,0x000500ae,
+	0x000000b1,0x00000111,0x0000010d,0x00000110,0x000300f7,0x00000114,0x00000000,0x000400fa,
+	0x00000111,0x00000113,0x00000116,0x000200f8,0x00000113,0x0004003d,0x00000006,0x00000115,
+	0x00000071,0x0003003e,0x00000112,0x00000115,0x000200f9,0x00000114,0x000200f8,0x00000116,
+	0x0004003d,0x00000006,0x00000117,0x00000071,0x00050041,0x0000002a,0x00000118,0x00000027,
+	0x00000074,0x0004003d,0x00000006,0x00000119,0x00000118,0x00050080,0x00000006,0x0000011a,
+	0x00000117,0x00000119,0x0003003e,0x00000112,0x0000011a,0x000200f9,0x00000114,0x000200f8,
+	0x00000114,0x0004003d,0x00000006,0x0000011b,0x00000112,0x0003003e,0x00000071,0x0000011b,
+	0x0004003d,0x00000006,0x0000011c,0x00000071,0x00060041,0x00000085,0x0000011d,0x00000083,
+	0x00000074,0x0000011c,0x0004003d,0x00000007,0x0000011e,0x0000011d,0x0003003e,0x0000007f,
+	0x0000011e,0x00050041,0x0000001a,0x0000011f,0x0000007f,0x00000019,0x0004003d,0x00000006,
+	0x00000120,0x0000011f,0x0006000c,0x00000089,0x00000121,0x00000001,0x00000040,0x00000120,
+	0x0003003e,0x0000008b,0x00000121,0x00050041,0x0000001a,0x00000122,0x0000007f,0x0000001d,
+	0x0004003d,0x00000006,0x00000123,0x00000122,0x0006000c,0x00000089,0x00000124,0x00000001,
+	0x00000040,0x00000123,0x0003003e,0x0000008f,0x00000124,0x00050041,0x0000001a,0x00000125,
+	0x0000000b,0x0000001d,0x0004003d,0x00000006,0x00000126,0x00000125,0x00050041,0x0000002a,
+	0x00000127,0x00000027,0x0000006b,0x0004003d,0x00000006,0x00000128,0x00000127,0x00050082,
+	0x00000006,0x00000129,0x00000128,0x0000001d,0x000500ae,0x000000b1,0x0000012a,0x00000126,
+	0x00000129,0x000300f7,0x0000012d,0x00000000,0x000400fa,0x0000012a,0x0000012c,0x0000012f,
+	0x000200f8,0x0000012c,0x0004003d,0x00000006,0x0000012e,0x00000093,0x0003003e,0x0000012b,
+	0x0000012e,0x000200f9,0x0000012d,0x000200f8,0x0000012f,0x0004003d,0x00000006,0x00000130,
+	0x00000093,0x00050041,0x0000002a,0x00000131,0x00000027,0x0000003a,0x0004003d,0x00000006,
+	0x00000132,0x00000131,0x00050080,0x00000006,0x00000133,0x00000130,0x00000132,0x0003003e,
+	0x0000012b,0x00000133,0x000200f9,0x0000012d,0x000200f8,0x0000012d,0x0004003d,0x00000006,
+	0x00000134,0x0000012b,0x0003003e,0x00000093,0x00000134,0x0004003d,0x00000006,0x00000135,
+	0x00000093,0x00060041,0x000000a2,0x00000136,0x000000a0,0x00000074,0x00000135,0x0004003d,
+	0x00000006,0x00000137,0x00000136,0x0006000c,0x00000089,0x00000138,0x00000001,0x00000040,
+	0x00000137,0x0003003e,0x0000009c,0x00000138,0x0004003d,0x00000006,0x00000139,0x00000093,
+	0x00050080,0x00000006,0x0000013a,0x00000139,0x0000001d,0x00060041,0x000000a2,0x0000013b,
+	0x000000a0,0x00000074,0x0000013a,0x0004003d,0x00000006,0x0000013c,0x0000013b,0x0006000c,
+	0x00000089,0x0000013d,0x00000001,0x00000040,0x0000013c,0x0003003e,0x000000a6,0x0000013d,
+	0x00050041,0x0000001a,0x0000013e,0x0000000b,0x00000019,0x0004003d,0x00000006,0x0000013f,
+	0x0000013e,0x00050041,0x0000002a,0x00000140,0x00000027,0x0000003a,0x0004003d,0x00000006,
+	0x00000141,0x00000140,0x00050082,0x00000006,0x00000142,0x00000141,0x0000001d,0x000500aa,
+	0x000000b1,0x00000143,0x0000013f,0x00000142,0x000300f7,0x00000146,0x00000000,0x000400fa,
+	0x00000143,0x00000145,0x00000149,0x000200f8,0x00000145,0x0004003d,0x00000089,0x00000147,
+	0x0000009c,0x0009004f,0x00000089,0x00000148,0x00000147,0x00000147,0x00000003,0x00000003,
+	0x00000003,0x00000003,0x0003003e,0x00000144,0x00000148,0x000200f9,0x00000146,0x000200f8,
+	0x00000149,0x0004003d,0x00000089,0x0000014a,0x000000a6,0x0003003e,0x00000144,0x0000014a,
+	0x000200f9,0x00000146,0x000200f8,0x00000146,0x0004003d,0x00000089,0x0000014b,0x00000144,
+	0x0003003e,0x000000a6,0x0000014b,0x0004003d,0x00000089,0x0000014c,0x0000009c,0x0004003d,
+	0x00000089,0x0000014d,0x0000009c,0x0008004f,0x000000bd,0x0000014e,0x0000014d,0x0000014d,
+	0x00000001,0x00000002,0x00000003,0x00050041,0x000000c0,0x0000014f,0x000000a6,0x00000019,
+	0x0004003d,0x00000088,0x00000150,0x0000014f,0x00050051,0x00000088,0x00000151,0x0000014e,
+	0x00000000,0x00050051,0x00000088,0x00000152,0x0000014e,0x00000001,0x00050051,0x00000088,
+	0x00000153,0x0000014e,0x00000002,0x00070050,0x00000089,0x00000154,0x00000151,0x00000152,
+	0x00000153,0x00000150,0x00050081,0x00000089,0x00000155,0x0000014c,0x00000154,0x0005008e,
+	0x00000089,0x00000156,0x00000155,0x000000c8,0x0003003e,0x000000bb,0x00000156,0x0004003d,
+	0x00000089,0x00000158,0x000000ca,0x00050041,0x000000c0,0x00000159,0x0000009c,0x00000019,
+	0x0004003d,0x00000088,0x0000015a,0x00000159,0x00050041,0x000000c0,0x0000015b,0x000000bb,
+	0x00000019,0x0004003d,0x00000088,0x0000015c,0x0000015b,0x00050041,0x000000c0,0x0000015d,
+	0x0000009c,0x0000001d,0x0004003d,0x00000088,0x0000015e,0x0000015d,0x00050041,0x000000c0,
+	0x0000015f,0x000000bb,0x0000001d,0x0004003d,0x00000088,0x00000160,0x0000015f,0x00070050,
+	0x00000089,0x00000161,0x0000015a,0x0000015c,0x0000015e,0x00000160,0x00050081,0x00000089,
+	0x00000162,0x00000158,0x00000161,0x0005008e,0x00000089,0x00000163,0x00000162,0x000000c8,
+	0x0003003e,0x00000157,0x00000163,0x0004003d,0x00000089,0x00000165,0x000000d4,0x00050041,
+	0x000000c0,0x00000166,0x0000009c,0x00000035,0x0004003d,0x00000088,0x00000167,0x00000166,
+	0x00050041,0x000000c0,0x00000168,0x000000bb,0x00000035,0x0004003d,0x00000088,0x00000169,
+	0x00000168,0x00050041,0x000000c0,0x0000016a,0x0000009c,0x000000d9,0x0004003d,0x00000088,
+	0x0000016b,0x0000016a,0x00050041,0x000000c0,0x0000016c,0x000000bb,0x000000d9,0x0004003d,
+	0x00000088,0x0000016d,0x0000016c,0x00070050,0x00000089,0x0000016e,0x00000167,0x00000169,
+	0x0000016b,0x0000016d,0x00050081,0x00000089,0x0000016f,0x00000165,0x0000016e,0x0005008e,
+	0x00000089,0x00000170,0x0000016f,0x000000c8,0x0003003e,0x00000164,0x00000170,0x0004003d,
+	0x00000089,0x00000171,0x0000008b,0x0004003d,0x00000089,0x00000172,0x00000157,0x00050083,
+	0x00000089,0x00000173,0x00000171,0x00000172,0x0005008e,0x00000089,0x00000174,0x00000173,
+	0x000000c8,0x00070050,0x00000089,0x00000175,0x000000e4,0x000000e4,0x000000e4,0x000000e4,
+	0x00050081,0x00000089,0x00000176,0x00000174,0x00000175,0x0003003e,0x000000df,0x00000176,
+	0x0004003d,0x00000089,0x00000177,0x0000008f,0x0004003d,0x00000089,0x00000178,0x00000164,
+	0x00050083,0x00000089,0x00000179,0x00000177,0x00000178,0x0005008e,0x00000089,0x0000017a,
+	0x00000179,0x000000c8,0x00070050,0x00000089,0x0000017b,0x000000e4,0x000000e4,0x000000e4,
+	0x000000e4,0x00050081,0x00000089,0x0000017c,0x0000017a,0x0000017b,0x0003003e,0x000000e7,
+	0x0000017c,0x0004003d,0x00000089,0x0000017d,0x000000df,0x00070050,0x00000089,0x0000017e,
+	0x000000ef,0x000000ef,0x000000ef,0x000000ef,0x00070050,0x00000089,0x0000017f,0x000000f0,
+	0x000000f0,0x000000f0,0x000000f0,0x0008000c,0x00000089,0x00000180,0x00000001,0x0000002b,
+	0x0000017d,0x0000017e,0x0000017f,0x0003003e,0x000000df,0x00000180,0x0004003d,0x00000089,
+	0x00000181,0x000000e7,0x00070050,0x00000089,0x00000182,0x000000ef,0x000000ef,0x000000ef,
+	0x000000ef,0x00070050,0x00000089,0x00000183,0x000000f0,0x000000f0,0x000000f0,0x000000f0,
+	0x0008000c,0x00000089,0x00000184,0x00000001,0x0000002b,0x00000181,0x00000182,0x00000183,
+	0x0003003e,0x000000e7,0x00000184,0x00050041,0x0000001a,0x00000185,0x0000000a,0x0000001d,
+	0x0004003d,0x00000006,0x00000186,0x00000185,0x00050041,0x0000002a,0x00000187,0x00000027,
+	0x00000063,0x0004003d,0x00000006,0x00000188,0x00000187,0x00050082,0x00000006,0x00000189,
+	0x00000188,0x0000001d,0x000500ae,0x000000b1,0x0000018a,0x00000186,0x00000189,0x000300f7,
+	0x0000018d,0x00000000,0x000400fa,0x0000018a,0x0000018c,0x0000018f,0x000200f8,0x0000018c,
+	0x0004003d,0x00000006,0x0000018e,0x000000f8,0x0003003e,0x0000018b,0x0000018e,0x000200f9,
+	0x0000018d,0x000200f8,0x0000018f,0x0004003d,0x00000006,0x00000190,0x000000f8,0x00050041,
+	0x0000002a,0x00000191,0x00000027,0x00000029,0x0004003d,0x00000006,0x00000192,0x00000191,
+	0x00050080,0x00000006,0x00000193,0x00000190,0x00000192,0x0003003e,0x0000018b,0x00000193,
+	0x000200f9,0x0000018d,0x000200f8,0x0000018d,0x0004003d,0x00000006,0x00000194,0x0000018b,
+	0x0003003e,0x000000f8,0x00000194,0x0004003d,0x00000006,0x00000195,0x000000f8,0x0004003d,
+	0x00000089,0x00000196,0x000000df,0x0006000c,0x00000006,0x00000197,0x00000001,0x00000037,
+	0x00000196,0x0004003d,0x00000089,0x00000198,0x000000e7,0x0006000c,0x00000006,0x00000199,
+	0x00000001,0x00000037,0x00000198,0x00050050,0x00000007,0x0000019a,0x00000197,0x00000199,
+	0x00060041,0x00000085,0x0000019b,0x00000104,0x00000074,0x00000195,0x0003003e,0x0000019b,
+	0x0000019a,0x000100fd,0x00010038,0x00050036,0x00000002,0x00000010,0x00000000,0x00000009,
+	0x00030037,0x00000008,0x0000000e,0x00030037,0x00000008,0x0000000f,0x000200f8,0x00000011,
+	0x0004003b,0x0000001a,0x000001ac,0x00000007,0x0004003b,0x00000008,0x000001b8,0x00000007,
+	0x0004003b,0x0000008a,0x000001c0,0x00000007,0x0004003b,0x0000008a,0x000001c4,0x00000007,
+	0x0004003b,0x0000001a,0x000001c8,0x00000007,0x0004003b,0x0000008a,0x000001d1,0x00000007,
+	0x0004003b,0x0000008a,0x000001da,0x00000007,0x0004003b,0x0000008a,0x000001e6,0x00000007,
+	0x0004003b,0x0000008a,0x000001ee,0x00000007,0x0004003b,0x0000008a,0x000001fc,0x00000007,
+	0x0004003b,0x0000008a,0x00000206,0x00000007,0x0004003b,0x0000008a,0x00000210,0x00000007,
+	0x0004003b,0x0000008a,0x00000217,0x00000007,0x0004003b,0x0000001a,0x00000226,0x00000007,
+	0x0004003b,0x0000001a,0x00000241,0x00000007,0x0004003b,0x0000001a,0x0000025b,0x00000007,
+	0x0004003b,0x0000008a,0x00000274,0x00000007,0x0004003b,0x0000008a,0x00000288,0x00000007,
+	0x0004003b,0x0000008a,0x00000295,0x00000007,0x00050041,0x0000001a,0x0000019c,0x0000000e,
+	0x0000001d,0x0004003d,0x00000006,0x0000019d,0x0000019c,0x00050041,0x0000002a,0x0000019e,
+	0x00000027,0x00000063,0x0004003d,0x00000006,0x0000019f,0x0000019e,0x00050086,0x00000006,
+	0x000001a0,0x0000019f,0x00000035,0x00050082,0x00000006,0x000001a1,0x000001a0,0x0000001d,
+	0x0008000c,0x00000006,0x000001a2,0x00000001,0x0000002c,0x0000019d,0x00000019,0x000001a1,
+	0x00050041,0x0000001a,0x000001a3,0x0000000e,0x0000001d,0x0003003e,0x000001a3,0x000001a2,
+	0x00050041,0x0000001a,0x000001a4,0x0000000f,0x0000001d,0x0004003d,0x00000006,0x000001a5,
+	0x000001a4,0x00050041,0x0000002a,0x000001a6,0x00000027,0x0000006b,0x0004003d,0x00000006,
+	0x000001a7,0x000001a6,0x00050086,0x00000006,0x000001a8,0x000001a7,0x00000035,0x00050082,
+	0x00000006,0x000001a9,0x000001a8,0x0000001d,0x0008000c,0x00000006,0x000001aa,0x00000001,
+	0x0000002c,0x000001a5,0x00000019,0x000001a9,0x00050041,0x0000001a,0x000001ab,0x0000000f,
+	0x0000001d,0x0003003e,0x000001ab,0x000001aa,0x00050041,0x0000001a,0x000001ad,0x0000000e,
+	0x0000001d,0x0004003d,0x00000006,0x000001ae,0x000001ad,0x00050041,0x0000002a,0x000001af,
+	0x00000027,0x00000074,0x0004003d,0x00000006,0x000001b0,0x000001af,0x00050084,0x00000006,
+	0x000001b1,0x000001ae,0x000001b0,0x00050041,0x0000002a,0x000001b2,0x00000027,0x00000078,
+	0x0004003d,0x00000006,0x000001b3,0x000001b2,0x00050080,0x00000006,0x000001b4,0x000001b1,
+	0x000001b3,0x00050041,0x0000001a,0x000001b5,0x0000000e,0x00000019,0x0004003d,0x00000006,
+	0x000001b6,0x000001b5,0x00050080,0x00000006,0x000001b7,0x000001b4,0x000001b6,0x0003003e,
+	0x000001ac,0x000001b7,0x0004003d,0x00000006,0x000001bd,0x000001ac,0x00060041,0x00000085,
+	0x000001be,0x000001bc,0x00000074,0x000001bd,0x0004003d,0x00000007,0x000001bf,0x000001be,
+	0x0003003e,0x000001b8,0x000001bf,0x00050041,0x0000001a,0x000001c1,0x000001b8,0x00000019,
+	0x0004003d,0x00000006,0x000001c2,0x000001c1,0x0006000c,0x00000089,0x000001c3,0x00000001,
+	0x00000040,0x000001c2,0x0003003e,0x000001c0,0x000001c3,0x00050041,0x0000001a,0x000001c5,
+	0x000001b8,0x0000001d,0x0004003d,0x00000006,0x000001c6,0x000001c5,0x0006000c,0x00000089,
+	0x000001c7,0x00000001,0x00000040,0x000001c6,0x0003003e,0x000001c4,0x000001c7,0x00050041,
+	0x0000001a,0x000001c9,0x0000000f,0x0000001d,0x0004003d,0x00000006,0x000001ca,0x000001c9,
+	0x00050041,0x0000002a,0x000001cb,0x00000027,0x0000003a,0x0004003d,0x00000006,0x000001cc,
+	0x000001cb,0x00050084,0x00000006,0x000001cd,0x000001ca,0x000001cc,0x00050041,0x0000001a,
+	0x000001ce,0x0000000f,0x00000019,0x0004003d,0x00000006,0x000001cf,0x000001ce,0x00050080,
+	0x00000006,0x000001d0,0x000001cd,0x000001cf,0x0003003e,0x000001c8,0x000001d0,0x0004003d,
+	0x00000006,0x000001d6,0x000001c8,0x00060041,0x000000a2,0x000001d7,0x000001d5,0x00000074,
+	0x000001d6,0x0004003d,0x00000006,0x000001d8,0x000001d7,0x0006000c,0x00000089,0x000001d9,
+	0x00000001,0x00000040,0x000001d8,0x0003003e,0x000001d1,0x000001d9,0x0004003d,0x00000006,
+	0x000001db,0x000001c8,0x00050080,0x00000006,0x000001dc,0x000001db,0x0000001d,0x00060041,
+	0x000000a2,0x000001dd,0x000001d5,0x00000074,0x000001dc,0x0004003d,0x00000006,0x000001de,
+	0x000001dd,0x0006000c,0x00000089,0x000001df,0x00000001,0x00000040,0x000001de,0x0003003e,
+	0x000001da,0x000001df,0x00050041,0x0000001a,0x000001e0,0x0000000f,0x00000019,0x0004003d,
+	0x00000006,0x000001e1,0x000001e0,0x00050041,0x0000002a,0x000001e2,0x00000027,0x0000003a,
+	0x0004003d,0x00000006,0x000001e3,0x000001e2,0x00050082,0x00000006,0x000001e4,0x000001e3,
+	0x0000001d,0x000500aa,0x000000b1,0x000001e5,0x000001e1,0x000001e4,0x000300f7,0x000001e8,
+	0x00000000,0x000400fa,0x000001e5,0x000001e7,0x000001eb,0x000200f8,0x000001e7,0x0004003d,
+	0x00000089,0x000001e9,0x000001d1,0x0009004f,0x00000089,0x000001ea,0x000001e9,0x000001e9,
+	0x00000002,0x00000003,0x00000002,0x00000003,0x0003003e,0x000001e6,0x000001ea,0x000200f9,
+	0x000001e8,0x000200f8,0x000001eb,0x0004003d,0x00000089,0x000001ec,0x000001da,0x0003003e,
+	0x000001e6,0x000001ec,0x000200f9,0x000001e8,0x000200f8,0x000001e8,0x0004003d,0x00000089,
+	0x000001ed,0x000001e6,0x0003003e,0x000001da,0x000001ed,0x0004003d,0x00000089,0x000001ef,
+	0x000001d1,0x0004003d,0x00000089,0x000001f1,0x000001d1,0x0007004f,0x000001f0,0x000001f2,
+	0x000001f1,0x000001f1,0x00000002,0x00000003,0x0004003d,0x00000089,0x000001f3,0x000001da,
+	0x0007004f,0x000001f0,0x000001f4,0x000001f3,0x000001f3,0x00000000,0x00000001,0x00050051,
+	0x00000088,0x000001f5,0x000001f2,0x00000000,0x00050051,0x00000088,0x000001f6,0x000001f2,
+	0x00000001,0x00050051,0x00000088,0x000001f7,0x000001f4,0x00000000,0x00050051,0x00000088,
+	0x000001f8,0x000001f4,0x00000001,0x00070050,0x00000089,0x000001f9,0x000001f5,0x000001f6,
+	0x000001f7,0x000001f8,0x00050081,0x00000089,0x000001fa,0x000001ef,0x000001f9,0x0005008e,
+	0x00000089,0x000001fb,0x000001fa,0x000000c8,0x0003003e,0x000001ee,0x000001fb,0x0004003d,
+	0x00000089,0x000001fd,0x000001d1,0x0007004f,0x000001f0,0x000001fe,0x000001fd,0x000001fd,
+	0x00000000,0x00000001,0x0004003d,0x00000089,0x000001ff,0x000001ee,0x0007004f,0x000001f0,
+	0x00000200,0x000001ff,0x000001ff,0x00000000,0x00000001,0x00050051,0x00000088,0x00000201,
+	0x000001fe,0x00000000,0x00050051,0x00000088,0x00000202,0x000001fe,0x00000001,0x00050051,
+	0x00000088,0x00000203,0x00000200,0x00000000,0x00050051,0x00000088,0x00000204,0x00000200,
+	0x00000001,0x00070050,0x00000089,0x00000205,0x00000201,0x00000202,0x00000203,0x00000204,
+	0x0003003e,0x000001fc,0x00000205,0x0004003d,0x00000089,0x00000207,0x000001d1,0x0007004f,
+	0x000001f0,0x00000208,0x00000207,0x00000207,0x00000002,0x00000003,0x0004003d,0x00000089,
+	0x00000209,0x000001ee,0x0007004f,0x000001f0,0x0000020a,0x00000209,0x00000209,0x00000002,
+	0x00000003,0x00050051,0x00000088,0x0000020b,0x00000208,0x00000000,0x00050051,0x00000088,
+	0x0000020c,0x00000208,0x00000001,0x00050051,0x00000088,0x0000020d,0x0000020a,0x00000000,
+	0x00050051,0x00000088,0x0000020e,0x0000020a,0x00000001,0x00070050,0x00000089,0x0000020f,
+	0x0000020b,0x0000020c,0x0000020d,0x0000020e,0x0003003e,0x00000206,0x0000020f,0x0004003d,
+	0x00000089,0x00000211,0x000001c0,0x0004003d,0x00000089,0x00000212,0x000001fc,0x00050083,
+	0x00000089,0x00000213,0x00000211,0x00000212,0x0005008e,0x00000089,0x00000214,0x00000213,
+	0x000000c8,0x00070050,0x00000089,0x00000215,0x000000e4,0x000000e4,0x000000e4,0x000000e4,
+	0x00050081,0x00000089,0x00000216,0x00000214,0x00000215,0x0003003e,0x00000210,0x00000216,
+	0x0004003d,0x00000089,0x00000218,0x000001c4,0x0004003d,0x00000089,0x00000219,0x00000206,
+	0x00050083,0x00000089,0x0000021a,0x00000218,0x00000219,0x0005008e,0x00000089,0x0000021b,
+	0x0000021a,0x000000c8,0x00070050,0x00000089,0x0000021c,0x000000e4,0x000000e4,0x000000e4,
+	0x000000e4,0x00050081,0x00000089,0x0000021d,0x0000021b,0x0000021c,0x0003003e,0x00000217,
+	0x0000021d,0x0004003d,0x00000089,0x0000021e,0x00000210,0x00070050,0x00000089,0x0000021f,
+	0x000000ef,0x000000ef,0x000000ef,0x000000ef,0x00070050,0x00000089,0x00000220,0x000000f0,
+	0x000000f0,0x000000f0,0x000000f0,0x0008000c,0x00000089,0x00000221,0x00000001,0x0000002b,
+	0x0000021e,0x0000021f,0x00000220,0x0003003e,0x00000210,0x00000221,0x0004003d,0x00000089,
+	0x00000222,0x00000217,0x00070050,0x00000089,0x00000223,0x000000ef,0x000000ef,0x000000ef,
+	0x000000ef,0x00070050,0x00000089,0x00000224,0x000000f0,0x000000f0,0x000000f0,0x000000f0,
+	0x0008000c,0x00000089,0x00000225,0x00000001,0x0000002b,0x00000222,0x00000223,0x00000224,
+	0x0003003e,0x00000217,0x00000225,0x00050041,0x0000001a,0x00000227,0x0000000e,0x0000001d,
+	0x0004003d,0x00000006,0x00000228,0x00000227,0x00050041,0x0000002a,0x00000229,0x00000027,
+	0x00000029,0x0004003d,0x00000006,0x0000022a,0x00000229,0x00050084,0x00000006,0x0000022b,
+	0x00000228,0x0000022a,0x00050041,0x0000001a,0x0000022c,0x0000000e,0x00000019,0x0004003d,
+	0x00000006,0x0000022d,0x0000022c,0x00050080,0x00000006,0x0000022e,0x0000022b,0x0000022d,
+	0x0003003e,0x00000226,0x0000022e,0x0004003d,0x00000006,0x00000233,0x00000226,0x0004003d,
+	0x00000089,0x00000234,0x00000210,0x0006000c,0x00000006,0x00000235,0x00000001,0x00000037,
+	0x00000234,0x0004003d,0x00000089,0x00000236,0x00000217,0x0006000c,0x00000006,0x00000237,
+	0x00000001,0x00000037,0x00000236,0x00050050,0x00000007,0x00000238,0x00000235,0x00000237,
+	0x00060041,0x00000085,0x00000239,0x00000232,0x00000074,0x00000233,0x0003003e,0x00000239,
+	0x00000238,0x00050041,0x0000001a,0x0000023a,0x0000000e,0x0000001d,0x0004003d,0x00000006,
+	0x0000023b,0x0000023a,0x00050041,0x0000002a,0x0000023c,0x00000027,0x00000063,0x0004003d,
+	0x00000006,0x0000023d,0x0000023c,0x00050086,0x00000006,0x0000023e,0x0000023d,0x00000035,
+	0x00050082,0x00000006,0x0000023f,0x0000023e,0x0000001d,0x000500ae,0x000000b1,0x00000240,
+	0x0000023b,0x0000023f,0x000300f7,0x00000243,0x00000000,0x000400fa,0x00000240,0x00000242,
+	0x00000245,0x000200f8,0x00000242,0x0004003d,0x00000006,0x00000244,0x000001ac,0x0003003e,
+	0x00000241,0x00000244,0x000200f9,0x00000243,0x000200f8,0x00000245,0x0004003d,0x00000006,
+	0x00000246,0x000001ac,0x00050041,0x0000002a,0x00000247,0x00000027,0x00000074,0x0004003d,
+	0x00000006,0x00000248,0x00000247,0x00050080,0x00000006,0x00000249,0x00000246,0x00000248,
+	0x0003003e,0x00000241,0x00000249,0x000200f9,0x00000243,0x000200f8,0x00000243,0x0004003d,
+	0x00000006,0x0000024a,0x00000241,0x0003003e,0x000001ac,0x0000024a,0x0004003d,0x00000006,
+	0x0000024b,0x000001ac,0x00060041,0x00000085,0x0000024c,0x000001bc,0x00000074,0x0000024b,
+	0x0004003d,0x00000007,0x0000024d,0x0000024c,0x0003003e,0x000001b8,0x0000024d,0x00050041,
+	0x0000001a,0x0000024e,0x000001b8,0x00000019,0x0004003d,0x00000006,0x0000024f,0x0000024e,
+	0x0006000c,0x00000089,0x00000250,0x00000001,0x00000040,0x0000024f,0x0003003e,0x000001c0,
+	0x00000250,0x00050041,0x0000001a,0x00000251,0x000001b8,0x0000001d,0x0004003d,0x00000006,
+	0x00000252,0x00000251,0x0006000c,0x00000089,0x00000253,0x00000001,0x00000040,0x00000252,
+	0x0003003e,0x000001c4,0x00000253,0x00050041,0x0000001a,0x00000254,0x0000000f,0x0000001d,
+	0x0004003d,0x00000006,0x00000255,0x00000254,0x00050041,0x0000002a,0x00000256,0x00000027,
+	0x0000006b,0x0004003d,0x00000006,0x00000257,0x00000256,0x00050086,0x00000006,0x00000258,
+	0x00000257,0x00000035,0x00050082,0x00000006,0x00000259,0x00000258,0x0000001d,0x000500ae,
+	0x000000b1,0x0000025a,0x00000255,0x00000259,0x000300f7,0x0000025d,0x00000000,0x000400fa,
+	0x0000025a,0x0000025c,0x0000025f,0x000200f8,0x0000025c,0x0004003d,0x00000006,0x0000025e,
+	0x000001c8,0x0003003e,0x0000025b,0x0000025e,0x000200f9,0x0000025d,0x000200f8,0x0000025f,
+	0x0004003d,0x00000006,0x00000260,0x000001c8,0x00050041,0x0000002a,0x00000261,0x00000027,
+	0x0000003a,0x0004003d,0x00000006,0x00000262,0x00000261,0x00050080,0x00000006,0x00000263,
+	0x00000260,0x00000262,0x0003003e,0x0000025b,0x00000263,0x000200f9,0x0000025d,0x000200f8,
+	0x0000025d,0x0004003d,0x00000006,0x00000264,0x0000025b,0x0003003e,0x000001c8,0x00000264,
+	0x0004003d,0x00000006,0x00000265,0x000001c8,0x00060041,0x000000a2,0x00000266,0x000001d5,
+	0x00000074,0x00000265,0x0004003d,0x00000006,0x00000267,0x00000266,0x0006000c,0x00000089,
+	0x00000268,0x00000001,0x00000040,0x00000267,0x0003003e,0x000001d1,0x00000268,0x0004003d,
+	0x00000006,0x00000269,0x000001c8,0x00050080,0x00000006,0x0000026a,0x00000269,0x0000001d,
+	0x00060041,0x000000a2,0x0000026b,0x000001d5,0x00000074,0x0000026a,0x0004003d,0x00000006,
+	0x0000026c,0x0000026b,0x0006000c,0x00000089,0x0000026d,0x00000001,0x00000040,0x0000026c,
+	0x0003003e,0x000001da,0x0000026d,0x00050041,0x0000001a,0x0000026e,0x0000000f,0x00000019,
+	0x0004003d,0x00000006,0x0000026f,0x0000026e,0x00050041,0x0000002a,0x00000270,0x00000027,
+	0x0000003a,0x0004003d,0x00000006,0x00000271,0x00000270,0x00050082,0x00000006,0x00000272,
+	0x00000271,0x0000001d,0x000500aa,0x000000b1,0x00000273,0x0000026f,0x00000272,0x000300f7,
+	0x00000276,0x00000000,0x000400fa,0x00000273,0x00000275,0x00000279,0x000200f8,0x00000275,
+	0x0004003d,0x00000089,0x00000277,0x000001d1,0x0009004f,0x00000089,0x00000278,0x00000277,
+	0x00000277,0x00000002,0x00000003,0x00000002,0x00000003,0x0003003e,0x00000274,0x00000278,
+	0x000200f9,0x00000276,0x000200f8,0x00000279,0x0004003d,0x00000089,0x0000027a,0x000001da,
+	0x0003003e,0x00000274,0x0000027a,0x000200f9,0x00000276,0x000200f8,0x00000276,0x0004003d,
+	0x00000089,0x0000027b,0x00000274,0x0003003e,0x000001da,0x0000027b,0x0004003d,0x00000089,
+	0x0000027c,0x000001d1,0x0004003d,0x00000089,0x0000027d,0x000001d1,0x0007004f,0x000001f0,
+	0x0000027e,0x0000027d,0x0000027d,0x00000002,0x00000003,0x0004003d,0x00000089,0x0000027f,
+	0x000001da,0x0007004f,0x000001f0,0x00000280,0x0000027f,0x0000027f,0x00000000,0x00000001,
+	0x00050051,0x00000088,0x00000281,0x0000027e,0x00000000,0x00050051,0x00000088,0x00000282,
+	0x0000027e,0x00000001,0x00050051,0x00000088,0x00000283,0x00000280,0x00000000,0x00050051,
+	0x00000088,0x00000284,0x00000280,0x00000001,0x00070050,0x00000089,0x00000285,0x00000281,
+	0x00000282,0x00000283,0x00000284,0x00050081,0x00000089,0x00000286,0x0000027c,0x00000285,
+	0x0005008e,0x00000089,0x00000287,0x00000286,0x000000c8,0x0003003e,0x000001ee,0x00000287,
+	0x0004003d,0x00000089,0x00000289,0x000001fc,0x0004003d,0x00000089,0x0000028a,0x000001d1,
+	0x0007004f,0x000001f0,0x0000028b,0x0000028a,0x0000028a,0x00000000,0x00000001,0x0004003d,
+	0x00000089,0x0000028c,0x000001ee,0x0007004f,0x000001f0,0x0000028d,0x0000028c,0x0000028c,
+	0x00000000,0x00000001,0x00050051,0x00000088,0x0000028e,0x0000028b,0x00000000,0x00050051,
+	0x00000088,0x0000028f,0x0000028b,0x00000001,0x00050051,0x00000088,0x00000290,0x0000028d,
+	0x00000000,0x00050051,0x00000088,0x00000291,0x0000028d,0x00000001,0x00070050,0x00000089,
+	0x00000292,0x0000028e,0x0000028f,0x00000290,0x00000291,0x00050081,0x00000089,0x00000293,
+	0x00000289,0x00000292,0x0005008e,0x00000089,0x00000294,0x00000293,0x000000c8,0x0003003e,
+	0x00000288,0x00000294,0x0004003d,0x00000089,0x00000296,0x00000206,0x0004003d,0x00000089,
+	0x00000297,0x000001d1,0x0007004f,0x000001f0,0x00000298,0x00000297,0x00000297,0x00000002,
+	0x00000003,0x0004003d,0x00000089,0x00000299,0x000001ee,0x0007004f,0x000001f0,0x0000029a,
+	0x00000299,0x00000299,0x00000002,0x00000003,0x00050051,0x00000088,0x0000029b,0x00000298,
+	0x00000000,0x00050051,0x00000088,0x0000029c,0x00000298,0x00000001,0x00050051,0x00000088,
+	0x0000029d,0x0000029a,0x00000000,0x00050051,0x00000088,0x0000029e,0x0000029a,0x00000001,
+	0x00070050,0x00000089,0x0000029f,0x0000029b,0x0000029c,0x0000029d,0x0000029e,0x00050081,
+	0x00000089,0x000002a0,0x00000296,0x0000029f,0x0005008e,0x00000089,0x000002a1,0x000002a0,
+	0x000000c8,0x0003003e,0x00000295,0x000002a1,0x0004003d,0x00000089,0x000002a2,0x000001c0,
+	0x0004003d,0x00000089,0x000002a3,0x00000288,0x00050083,0x00000089,0x000002a4,0x000002a2,
+	0x000002a3,0x0005008e,0x00000089,0x000002a5,0x000002a4,0x000000c8,0x00070050,0x00000089,
+	0x000002a6,0x000000e4,0x000000e4,0x000000e4,0x000000e4,0x00050081,0x00000089,0x000002a7,
+	0x000002a5,0x000002a6,0x0003003e,0x00000210,0x000002a7,0x0004003d,0x00000089,0x000002a8,
+	0x000001c4,0x0004003d,0x00000089,0x000002a9,0x00000295,0x00050083,0x00000089,0x000002aa,
+	0x000002a8,0x000002a9,0x0005008e,0x00000089,0x000002ab,0x000002aa,0x000000c8,0x00070050,
+	0x00000089,0x000002ac,0x000000e4,0x000000e4,0x000000e4,0x000000e4,0x00050081,0x00000089,
+	0x000002ad,0x000002ab,0x000002ac,0x0003003e,0x00000217,0x000002ad,0x0004003d,0x00000089,
+	0x000002ae,0x00000210,0x00070050,0x00000089,0x000002af,0x000000ef,0x000000ef,0x000000ef,
+	0x000000ef,0x00070050,0x00000089,0x000002b0,0x000000f0,0x000000f0,0x000000f0,0x000000f0,
+	0x0008000c,0x00000089,0x000002b1,0x00000001,0x0000002b,0x000002ae,0x000002af,0x000002b0,
+	0x0003003e,0x00000210,0x000002b1,0x0004003d,0x00000089,0x000002b2,0x00000217,0x00070050,
+	0x00000089,0x000002b3,0x000000ef,0x000000ef,0x000000ef,0x000000ef,0x00070050,0x00000089,
+	0x000002b4,0x000000f0,0x000000f0,0x000000f0,0x000000f0,0x0008000c,0x00000089,0x000002b5,
+	0x00000001,0x0000002b,0x000002b2,0x000002b3,0x000002b4,0x0003003e,0x00000217,0x000002b5,
+	0x00050041,0x0000002a,0x000002b6,0x00000027,0x00000029,0x0004003d,0x00000006,0x000002b7,
+	0x000002b6,0x0004003d,0x00000006,0x000002b8,0x00000226,0x00050080,0x00000006,0x000002b9,
+	0x000002b8,0x000002b7,0x0003003e,0x00000226,0x000002b9,0x0004003d,0x00000006,0x000002ba,
+	0x00000226,0x0004003d,0x00000089,0x000002bb,0x00000210,0x0006000c,0x00000006,0x000002bc,
+	0x00000001,0x00000037,0x000002bb,0x0004003d,0x00000089,0x000002bd,0x00000217,0x0006000c,
+	0x00000006,0x000002be,0x00000001,0x00000037,0x000002bd,0x00050050,0x00000007,0x000002bf,
+	0x000002bc,0x000002be,0x00060041,0x00000085,0x000002c0,0x00000232,0x00000074,0x000002ba,
+	0x0003003e,0x000002c0,0x000002bf,0x000100fd,0x00010038
diff --git a/shaders/spv/shader_reconstruct_pyr.comp b/shaders/spv/shader_reconstruct_pyr.comp
new file mode 100644
index 0000000..7929989
--- /dev/null
+++ b/shaders/spv/shader_reconstruct_pyr.comp
@@ -0,0 +1,220 @@
+#version 310 es
+
+layout (local_size_x = 8, local_size_y = 8) in;
+
+layout (binding = 0) readonly buffer Lap0BufY {
+    uvec2 data[];
+} lap0_buf_y;
+
+layout (binding = 1) readonly buffer Lap0BufUV {
+    uvec2 data[];
+} lap0_buf_uv;
+
+layout (binding = 2) readonly buffer Lap1BufY {
+    uvec2 data[];
+} lap1_buf_y;
+
+layout (binding = 3) readonly buffer Lap1BufUV {
+    uvec2 data[];
+} lap1_buf_uv;
+
+layout (binding = 4) writeonly buffer OutBufY {
+    uvec2 data[];
+} out_buf_y;
+
+layout (binding = 5) writeonly buffer OutBufUV {
+    uvec2 data[];
+} out_buf_uv;
+
+layout (binding = 6) readonly buffer PrevBlendBufY {
+    uint data[];
+} prev_blend_y;
+
+layout (binding = 7) readonly buffer PrevBlendBufUV {
+    uint data[];
+} prev_blend_uv;
+
+layout (binding = 8) readonly buffer MaskBuf {
+    uvec2 data[];
+} mask_buf;
+
+layout (push_constant) uniform PushConsts {
+    uint lap_img_width;
+    uint lap_img_height;
+    uint out_img_width;
+    uint out_offset_x;
+    uint prev_blend_img_width;
+    uint prev_blend_img_height;
+} prop;
+
+// normalization of gray level
+const float norm_gl = 256.0f / 255.0f;
+
+void reconstruct_y (uvec2 y_id, uvec2 blend_id);
+void reconstruct_uv (uvec2 uv_id, uvec2 blend_id);
+
+void main ()
+{
+    uvec2 g_id = gl_GlobalInvocationID.xy;
+
+    uvec2 y_id = uvec2 (g_id.x, g_id.y * 4u);
+    y_id.x = clamp (y_id.x, 0u, prop.lap_img_width - 1u);
+
+    uvec2 blend_id = uvec2 (g_id.x, g_id.y * 2u);
+    blend_id.x = clamp (blend_id.x, 0u, prop.prev_blend_img_width - 1u);
+    reconstruct_y (y_id, blend_id);
+
+    y_id.y += 2u;
+    blend_id.y += 1u;
+    reconstruct_y (y_id, blend_id);
+
+    uvec2 uv_id = uvec2 (g_id.x, g_id.y * 2u);
+    uv_id.x = clamp (uv_id.x, 0u, prop.lap_img_width - 1u);
+    blend_id = g_id;
+    blend_id.x = clamp (blend_id.x, 0u, prop.prev_blend_img_width - 1u);
+    reconstruct_uv (uv_id, blend_id);
+}
+
+void reconstruct_y (uvec2 y_id, uvec2 blend_id)
+{
+    y_id.y = clamp (y_id.y, 0u, prop.lap_img_height - 1u);
+    blend_id.y = clamp (blend_id.y, 0u, prop.prev_blend_img_height - 2u);
+
+    uvec2 mask = mask_buf.data[y_id.x];
+    vec4 mask0 = unpackUnorm4x8 (mask.x);
+    vec4 mask1 = unpackUnorm4x8 (mask.y);
+
+    uint idx = y_id.y * prop.lap_img_width + y_id.x;
+    uvec2 lap = lap0_buf_y.data[idx];
+    vec4 lap00 = unpackUnorm4x8 (lap.x);
+    vec4 lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_y.data[idx];
+    vec4 lap10 = unpackUnorm4x8 (lap.x);
+    vec4 lap11 = unpackUnorm4x8 (lap.y);
+
+    vec4 lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    vec4 lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    uint prev_blend_idx = blend_id.y * prop.prev_blend_img_width + blend_id.x;
+    vec4 prev_blend0 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx]);
+    vec4 prev_blend1 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prop.prev_blend_img_width - 1u) ? prev_blend0.wwww : prev_blend1;
+
+    vec4 inter = (prev_blend0 + vec4 (prev_blend0.yzw, prev_blend1.x)) * 0.5f;
+    vec4 prev_blend_inter00 = vec4 (prev_blend0.x, inter.x, prev_blend0.y, inter.y);
+    vec4 prev_blend_inter01 = vec4 (prev_blend0.z, inter.z, prev_blend0.w, inter.w);
+
+    vec4 out0 = prev_blend_inter00 + lap_blend0 * 2.0f - norm_gl;
+    vec4 out1 = prev_blend_inter01 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    uint out_idx = y_id.y * prop.out_img_width + prop.out_offset_x + y_id.x;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+
+    idx = (y_id.y >= prop.lap_img_height - 1u) ? idx : idx + prop.lap_img_width;
+    lap = lap0_buf_y.data[idx];
+    lap00 = unpackUnorm4x8 (lap.x);
+    lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_y.data[idx];
+    lap10 = unpackUnorm4x8 (lap.x);
+    lap11 = unpackUnorm4x8 (lap.y);
+
+    lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    prev_blend_idx = (blend_id.y >= prop.prev_blend_img_height - 1u) ?
+                     prev_blend_idx : prev_blend_idx + prop.prev_blend_img_width;
+    prev_blend0 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx]);
+    prev_blend1 = unpackUnorm4x8 (prev_blend_y.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prop.prev_blend_img_width - 1u) ? prev_blend0.wwww : prev_blend1;
+
+    inter = (prev_blend0 + vec4 (prev_blend0.yzw, prev_blend1.x)) * 0.5f;
+    vec4 prev_blend_inter10 = vec4 (prev_blend0.x, inter.x, prev_blend0.y, inter.y);
+    vec4 prev_blend_inter11 = vec4 (prev_blend0.z, inter.z, prev_blend0.w, inter.w);
+    prev_blend_inter10 = (prev_blend_inter00 + prev_blend_inter10) * 0.5f;
+    prev_blend_inter11 = (prev_blend_inter01 + prev_blend_inter11) * 0.5f;
+
+    out0 = prev_blend_inter10 + lap_blend0 * 2.0f - norm_gl;
+    out1 = prev_blend_inter11 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    out_idx = (y_id.y >= prop.lap_img_height - 1u) ? out_idx : out_idx + prop.out_img_width;
+    out_buf_y.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+}
+
+void reconstruct_uv (uvec2 uv_id, uvec2 blend_id)
+{
+    uv_id.y = clamp (uv_id.y, 0u, prop.lap_img_height / 2u - 2u);
+    blend_id.y = clamp (blend_id.y, 0u, prop.prev_blend_img_height / 2u - 1u);
+
+    uvec2 mask = mask_buf.data[uv_id.x];
+    vec4 mask0 = unpackUnorm4x8 (mask.x);
+    vec4 mask1 = unpackUnorm4x8 (mask.y);
+
+    uint idx = uv_id.y * prop.lap_img_width + uv_id.x;
+    uvec2 lap = lap0_buf_uv.data[idx];
+    vec4 lap00 = unpackUnorm4x8 (lap.x);
+    vec4 lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_uv.data[idx];
+    vec4 lap10 = unpackUnorm4x8 (lap.x);
+    vec4 lap11 = unpackUnorm4x8 (lap.y);
+
+    mask0.yw = mask0.xz;
+    mask1.yw = mask1.xz;
+    vec4 lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    vec4 lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    uint prev_blend_idx = blend_id.y * prop.prev_blend_img_width + blend_id.x;
+    vec4 prev_blend0 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx]);
+    vec4 prev_blend1 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prop.prev_blend_img_width - 1u) ? prev_blend0.zwzw : prev_blend1;
+
+    vec4 inter = (prev_blend0 + vec4 (prev_blend0.zw, prev_blend1.xy)) * 0.5f;
+    vec4 prev_blend_inter00 = vec4 (prev_blend0.xy, inter.xy);
+    vec4 prev_blend_inter01 = vec4 (prev_blend0.zw, inter.zw);
+
+    vec4 out0 = prev_blend_inter00 + lap_blend0 * 2.0f - norm_gl;
+    vec4 out1 = prev_blend_inter01 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    uint out_idx = uv_id.y * prop.out_img_width + prop.out_offset_x + uv_id.x;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+
+    idx = (uv_id.y >= (prop.lap_img_height / 2u - 1u)) ? idx : idx + prop.lap_img_width;
+    lap = lap0_buf_uv.data[idx];
+    lap00 = unpackUnorm4x8 (lap.x);
+    lap01 = unpackUnorm4x8 (lap.y);
+
+    lap = lap1_buf_uv.data[idx];
+    lap10 = unpackUnorm4x8 (lap.x);
+    lap11 = unpackUnorm4x8 (lap.y);
+
+    lap_blend0 = (lap00 - lap10) * mask0 + lap10;
+    lap_blend1 = (lap01 - lap11) * mask1 + lap11;
+
+    prev_blend_idx = (blend_id.y >= (prop.prev_blend_img_height / 2u - 1u)) ?
+                     prev_blend_idx : prev_blend_idx + prop.prev_blend_img_width;
+    prev_blend0 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx]);
+    prev_blend1 = unpackUnorm4x8 (prev_blend_uv.data[prev_blend_idx + 1u]);
+    prev_blend1 = (blend_id.x == prop.prev_blend_img_width - 1u) ? prev_blend0.zwzw : prev_blend1;
+
+    inter = (prev_blend0 + vec4 (prev_blend0.zw, prev_blend1.xy)) * 0.5f;
+    vec4 prev_blend_inter10 = vec4 (prev_blend0.xy, inter.xy);
+    vec4 prev_blend_inter11 = vec4 (prev_blend0.zw, inter.zw);
+    prev_blend_inter10 = (prev_blend_inter00 + prev_blend_inter10) * 0.5f;
+    prev_blend_inter11 = (prev_blend_inter01 + prev_blend_inter11) * 0.5f;
+
+    out0 = prev_blend_inter10 + lap_blend0 * 2.0f - norm_gl;
+    out1 = prev_blend_inter11 + lap_blend1 * 2.0f - norm_gl;
+    out0 = clamp (out0, 0.0f, 1.0f);
+    out1 = clamp (out1, 0.0f, 1.0f);
+
+    out_idx += prop.out_img_width;
+    out_buf_uv.data[out_idx] = uvec2 (packUnorm4x8 (out0), packUnorm4x8 (out1));
+}
diff --git a/shaders/spv/shader_reconstruct_pyr.comp.spv b/shaders/spv/shader_reconstruct_pyr.comp.spv
new file mode 100644
index 0000000..00ccea9
--- /dev/null
+++ b/shaders/spv/shader_reconstruct_pyr.comp.spv
@@ -0,0 +1,670 @@
+	// 7.8.2870
+	0x07230203,0x00010000,0x00080007,0x00000366,0x00000000,0x00020011,0x00000001,0x0006000b,
+	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
+	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x00000015,0x00060010,0x00000004,
+	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000001,0x00000136,0x00040005,
+	0x00000004,0x6e69616d,0x00000000,0x00080005,0x0000000c,0x6f636572,0x7274736e,0x5f746375,
+	0x75762879,0x75763b32,0x00003b32,0x00040005,0x0000000a,0x64695f79,0x00000000,0x00050005,
+	0x0000000b,0x6e656c62,0x64695f64,0x00000000,0x00080005,0x00000010,0x6f636572,0x7274736e,
+	0x5f746375,0x76287675,0x763b3275,0x003b3275,0x00040005,0x0000000e,0x695f7675,0x00000064,
+	0x00050005,0x0000000f,0x6e656c62,0x64695f64,0x00000000,0x00040005,0x00000012,0x64695f67,
+	0x00000000,0x00080005,0x00000015,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,
+	0x00000044,0x00040005,0x00000018,0x64695f79,0x00000000,0x00050005,0x00000025,0x68737550,
+	0x736e6f43,0x00007374,0x00070006,0x00000025,0x00000000,0x5f70616c,0x5f676d69,0x74646977,
+	0x00000068,0x00070006,0x00000025,0x00000001,0x5f70616c,0x5f676d69,0x67696568,0x00007468,
+	0x00070006,0x00000025,0x00000002,0x5f74756f,0x5f676d69,0x74646977,0x00000068,0x00070006,
+	0x00000025,0x00000003,0x5f74756f,0x7366666f,0x785f7465,0x00000000,0x00090006,0x00000025,
+	0x00000004,0x76657270,0x656c625f,0x695f646e,0x775f676d,0x68746469,0x00000000,0x00090006,
+	0x00000025,0x00000005,0x76657270,0x656c625f,0x695f646e,0x685f676d,0x68676965,0x00000074,
+	0x00040005,0x00000027,0x706f7270,0x00000000,0x00050005,0x00000030,0x6e656c62,0x64695f64,
+	0x00000000,0x00040005,0x00000040,0x61726170,0x0000006d,0x00040005,0x00000042,0x61726170,
+	0x0000006d,0x00040005,0x0000004d,0x61726170,0x0000006d,0x00040005,0x0000004f,0x61726170,
+	0x0000006d,0x00040005,0x00000052,0x695f7675,0x00000064,0x00040005,0x00000068,0x61726170,
+	0x0000006d,0x00040005,0x0000006a,0x61726170,0x0000006d,0x00040005,0x0000007d,0x6b73616d,
+	0x00000000,0x00040005,0x0000007f,0x6b73614d,0x00667542,0x00050006,0x0000007f,0x00000000,
+	0x61746164,0x00000000,0x00050005,0x00000081,0x6b73616d,0x6675625f,0x00000000,0x00040005,
+	0x0000008a,0x6b73616d,0x00000030,0x00040005,0x0000008e,0x6b73616d,0x00000031,0x00030005,
+	0x00000092,0x00786469,0x00030005,0x0000009b,0x0070616c,0x00050005,0x0000009d,0x3070614c,
+	0x59667542,0x00000000,0x00050006,0x0000009d,0x00000000,0x61746164,0x00000000,0x00050005,
+	0x0000009f,0x3070616c,0x6675625f,0x0000795f,0x00040005,0x000000a3,0x3070616c,0x00000030,
+	0x00040005,0x000000a7,0x3070616c,0x00000031,0x00050005,0x000000ac,0x3170614c,0x59667542,
+	0x00000000,0x00050006,0x000000ac,0x00000000,0x61746164,0x00000000,0x00050005,0x000000ae,
+	0x3170616c,0x6675625f,0x0000795f,0x00040005,0x000000b2,0x3170616c,0x00000030,0x00040005,
+	0x000000b6,0x3170616c,0x00000031,0x00050005,0x000000ba,0x5f70616c,0x6e656c62,0x00003064,
+	0x00050005,0x000000c2,0x5f70616c,0x6e656c62,0x00003164,0x00060005,0x000000ca,0x76657270,
+	0x656c625f,0x695f646e,0x00007864,0x00050005,0x000000d3,0x76657270,0x656c625f,0x0030646e,
+	0x00060005,0x000000d5,0x76657250,0x6e656c42,0x66754264,0x00000059,0x00050006,0x000000d5,
+	0x00000000,0x61746164,0x00000000,0x00060005,0x000000d7,0x76657270,0x656c625f,0x795f646e,
+	0x00000000,0x00050005,0x000000dd,0x76657270,0x656c625f,0x0031646e,0x00040005,0x000000f2,
+	0x65746e69,0x00000072,0x00070005,0x00000101,0x76657270,0x656c625f,0x695f646e,0x7265746e,
+	0x00003030,0x00070005,0x0000010b,0x76657270,0x656c625f,0x695f646e,0x7265746e,0x00003130,
+	0x00040005,0x00000116,0x3074756f,0x00000000,0x00040005,0x0000011f,0x3174756f,0x00000000,
+	0x00040005,0x00000130,0x5f74756f,0x00786469,0x00040005,0x0000013f,0x4274754f,0x00596675,
+	0x00050006,0x0000013f,0x00000000,0x61746164,0x00000000,0x00050005,0x00000141,0x5f74756f,
+	0x5f667562,0x00000079,0x00070005,0x000001ab,0x76657270,0x656c625f,0x695f646e,0x7265746e,
+	0x00003031,0x00070005,0x000001b5,0x76657270,0x656c625f,0x695f646e,0x7265746e,0x00003131,
+	0x00040005,0x00000202,0x6b73616d,0x00000000,0x00040005,0x00000207,0x6b73616d,0x00000030,
+	0x00040005,0x0000020b,0x6b73616d,0x00000031,0x00030005,0x0000020f,0x00786469,0x00030005,
+	0x00000218,0x0070616c,0x00050005,0x0000021a,0x3070614c,0x55667542,0x00000056,0x00050006,
+	0x0000021a,0x00000000,0x61746164,0x00000000,0x00050005,0x0000021c,0x3070616c,0x6675625f,
+	0x0076755f,0x00040005,0x00000220,0x3070616c,0x00000030,0x00040005,0x00000224,0x3070616c,
+	0x00000031,0x00050005,0x00000229,0x3170614c,0x55667542,0x00000056,0x00050006,0x00000229,
+	0x00000000,0x61746164,0x00000000,0x00050005,0x0000022b,0x3170616c,0x6675625f,0x0076755f,
+	0x00040005,0x0000022f,0x3170616c,0x00000030,0x00040005,0x00000233,0x3170616c,0x00000031,
+	0x00050005,0x00000240,0x5f70616c,0x6e656c62,0x00003064,0x00050005,0x00000248,0x5f70616c,
+	0x6e656c62,0x00003164,0x00060005,0x00000250,0x76657270,0x656c625f,0x695f646e,0x00007864,
+	0x00050005,0x00000259,0x76657270,0x656c625f,0x0030646e,0x00060005,0x0000025b,0x76657250,
+	0x6e656c42,0x66754264,0x00005655,0x00050006,0x0000025b,0x00000000,0x61746164,0x00000000,
+	0x00060005,0x0000025d,0x76657270,0x656c625f,0x755f646e,0x00000076,0x00050005,0x00000262,
+	0x76657270,0x656c625f,0x0031646e,0x00040005,0x00000276,0x65746e69,0x00000072,0x00070005,
+	0x00000283,0x76657270,0x656c625f,0x695f646e,0x7265746e,0x00003030,0x00070005,0x0000028d,
+	0x76657270,0x656c625f,0x695f646e,0x7265746e,0x00003130,0x00040005,0x00000297,0x3074756f,
+	0x00000000,0x00040005,0x0000029e,0x3174756f,0x00000000,0x00040005,0x000002ad,0x5f74756f,
+	0x00786469,0x00050005,0x000002ba,0x4274754f,0x56556675,0x00000000,0x00050006,0x000002ba,
+	0x00000000,0x61746164,0x00000000,0x00050005,0x000002bc,0x5f74756f,0x5f667562,0x00007675,
+	0x00070005,0x00000329,0x76657270,0x656c625f,0x695f646e,0x7265746e,0x00003031,0x00070005,
+	0x00000333,0x76657270,0x656c625f,0x695f646e,0x7265746e,0x00003131,0x00040047,0x00000015,
+	0x0000000b,0x0000001c,0x00050048,0x00000025,0x00000000,0x00000023,0x00000000,0x00050048,
+	0x00000025,0x00000001,0x00000023,0x00000004,0x00050048,0x00000025,0x00000002,0x00000023,
+	0x00000008,0x00050048,0x00000025,0x00000003,0x00000023,0x0000000c,0x00050048,0x00000025,
+	0x00000004,0x00000023,0x00000010,0x00050048,0x00000025,0x00000005,0x00000023,0x00000014,
+	0x00030047,0x00000025,0x00000002,0x00040047,0x0000007e,0x00000006,0x00000008,0x00040048,
+	0x0000007f,0x00000000,0x00000018,0x00050048,0x0000007f,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x0000007f,0x00000003,0x00040047,0x00000081,0x00000022,0x00000000,0x00040047,
+	0x00000081,0x00000021,0x00000008,0x00040047,0x0000009c,0x00000006,0x00000008,0x00040048,
+	0x0000009d,0x00000000,0x00000018,0x00050048,0x0000009d,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x0000009d,0x00000003,0x00040047,0x0000009f,0x00000022,0x00000000,0x00040047,
+	0x0000009f,0x00000021,0x00000000,0x00040047,0x000000ab,0x00000006,0x00000008,0x00040048,
+	0x000000ac,0x00000000,0x00000018,0x00050048,0x000000ac,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x000000ac,0x00000003,0x00040047,0x000000ae,0x00000022,0x00000000,0x00040047,
+	0x000000ae,0x00000021,0x00000002,0x00040047,0x000000d4,0x00000006,0x00000004,0x00040048,
+	0x000000d5,0x00000000,0x00000018,0x00050048,0x000000d5,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x000000d5,0x00000003,0x00040047,0x000000d7,0x00000022,0x00000000,0x00040047,
+	0x000000d7,0x00000021,0x00000006,0x00040047,0x0000013e,0x00000006,0x00000008,0x00040048,
+	0x0000013f,0x00000000,0x00000019,0x00050048,0x0000013f,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x0000013f,0x00000003,0x00040047,0x00000141,0x00000022,0x00000000,0x00040047,
+	0x00000141,0x00000021,0x00000004,0x00040047,0x00000219,0x00000006,0x00000008,0x00040048,
+	0x0000021a,0x00000000,0x00000018,0x00050048,0x0000021a,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x0000021a,0x00000003,0x00040047,0x0000021c,0x00000022,0x00000000,0x00040047,
+	0x0000021c,0x00000021,0x00000001,0x00040047,0x00000228,0x00000006,0x00000008,0x00040048,
+	0x00000229,0x00000000,0x00000018,0x00050048,0x00000229,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x00000229,0x00000003,0x00040047,0x0000022b,0x00000022,0x00000000,0x00040047,
+	0x0000022b,0x00000021,0x00000003,0x00040047,0x0000025a,0x00000006,0x00000004,0x00040048,
+	0x0000025b,0x00000000,0x00000018,0x00050048,0x0000025b,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x0000025b,0x00000003,0x00040047,0x0000025d,0x00000022,0x00000000,0x00040047,
+	0x0000025d,0x00000021,0x00000007,0x00040047,0x000002b9,0x00000006,0x00000008,0x00040048,
+	0x000002ba,0x00000000,0x00000019,0x00050048,0x000002ba,0x00000000,0x00000023,0x00000000,
+	0x00030047,0x000002ba,0x00000003,0x00040047,0x000002bc,0x00000022,0x00000000,0x00040047,
+	0x000002bc,0x00000021,0x00000005,0x00040047,0x00000365,0x0000000b,0x00000019,0x00020013,
+	0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000000,
+	0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,
+	0x00050021,0x00000009,0x00000002,0x00000008,0x00000008,0x00040017,0x00000013,0x00000006,
+	0x00000003,0x00040020,0x00000014,0x00000001,0x00000013,0x0004003b,0x00000014,0x00000015,
+	0x00000001,0x0004002b,0x00000006,0x00000019,0x00000000,0x00040020,0x0000001a,0x00000007,
+	0x00000006,0x0004002b,0x00000006,0x0000001d,0x00000001,0x0004002b,0x00000006,0x00000020,
+	0x00000004,0x0008001e,0x00000025,0x00000006,0x00000006,0x00000006,0x00000006,0x00000006,
+	0x00000006,0x00040020,0x00000026,0x00000009,0x00000025,0x0004003b,0x00000026,0x00000027,
+	0x00000009,0x00040015,0x00000028,0x00000020,0x00000001,0x0004002b,0x00000028,0x00000029,
+	0x00000000,0x00040020,0x0000002a,0x00000009,0x00000006,0x0004002b,0x00000006,0x00000035,
+	0x00000002,0x0004002b,0x00000028,0x0000003a,0x00000004,0x0004002b,0x00000028,0x0000006f,
+	0x00000001,0x0004002b,0x00000028,0x00000077,0x00000005,0x0003001d,0x0000007e,0x00000007,
+	0x0003001e,0x0000007f,0x0000007e,0x00040020,0x00000080,0x00000002,0x0000007f,0x0004003b,
+	0x00000080,0x00000081,0x00000002,0x00040020,0x00000084,0x00000002,0x00000007,0x00030016,
+	0x00000087,0x00000020,0x00040017,0x00000088,0x00000087,0x00000004,0x00040020,0x00000089,
+	0x00000007,0x00000088,0x0003001d,0x0000009c,0x00000007,0x0003001e,0x0000009d,0x0000009c,
+	0x00040020,0x0000009e,0x00000002,0x0000009d,0x0004003b,0x0000009e,0x0000009f,0x00000002,
+	0x0003001d,0x000000ab,0x00000007,0x0003001e,0x000000ac,0x000000ab,0x00040020,0x000000ad,
+	0x00000002,0x000000ac,0x0004003b,0x000000ad,0x000000ae,0x00000002,0x0003001d,0x000000d4,
+	0x00000006,0x0003001e,0x000000d5,0x000000d4,0x00040020,0x000000d6,0x00000002,0x000000d5,
+	0x0004003b,0x000000d6,0x000000d7,0x00000002,0x00040020,0x000000d9,0x00000002,0x00000006,
+	0x00020014,0x000000e8,0x00040017,0x000000f4,0x00000087,0x00000003,0x00040020,0x000000f7,
+	0x00000007,0x00000087,0x0004002b,0x00000087,0x000000ff,0x3f000000,0x0004002b,0x00000006,
+	0x00000110,0x00000003,0x0004002b,0x00000087,0x00000119,0x40000000,0x0004002b,0x00000087,
+	0x0000011c,0x3f808081,0x0004002b,0x00000087,0x00000127,0x00000000,0x0004002b,0x00000087,
+	0x00000128,0x3f800000,0x0004002b,0x00000028,0x00000133,0x00000002,0x0004002b,0x00000028,
+	0x00000137,0x00000003,0x0003001d,0x0000013e,0x00000007,0x0003001e,0x0000013f,0x0000013e,
+	0x00040020,0x00000140,0x00000002,0x0000013f,0x0004003b,0x00000140,0x00000141,0x00000002,
+	0x0003001d,0x00000219,0x00000007,0x0003001e,0x0000021a,0x00000219,0x00040020,0x0000021b,
+	0x00000002,0x0000021a,0x0004003b,0x0000021b,0x0000021c,0x00000002,0x0003001d,0x00000228,
+	0x00000007,0x0003001e,0x00000229,0x00000228,0x00040020,0x0000022a,0x00000002,0x00000229,
+	0x0004003b,0x0000022a,0x0000022b,0x00000002,0x00040017,0x00000237,0x00000087,0x00000002,
+	0x0003001d,0x0000025a,0x00000006,0x0003001e,0x0000025b,0x0000025a,0x00040020,0x0000025c,
+	0x00000002,0x0000025b,0x0004003b,0x0000025c,0x0000025d,0x00000002,0x0003001d,0x000002b9,
+	0x00000007,0x0003001e,0x000002ba,0x000002b9,0x00040020,0x000002bb,0x00000002,0x000002ba,
+	0x0004003b,0x000002bb,0x000002bc,0x00000002,0x0004002b,0x00000006,0x00000364,0x00000008,
+	0x0006002c,0x00000013,0x00000365,0x00000364,0x00000364,0x0000001d,0x00050036,0x00000002,
+	0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000012,
+	0x00000007,0x0004003b,0x00000008,0x00000018,0x00000007,0x0004003b,0x00000008,0x00000030,
+	0x00000007,0x0004003b,0x00000008,0x00000040,0x00000007,0x0004003b,0x00000008,0x00000042,
+	0x00000007,0x0004003b,0x00000008,0x0000004d,0x00000007,0x0004003b,0x00000008,0x0000004f,
+	0x00000007,0x0004003b,0x00000008,0x00000052,0x00000007,0x0004003b,0x00000008,0x00000068,
+	0x00000007,0x0004003b,0x00000008,0x0000006a,0x00000007,0x0004003d,0x00000013,0x00000016,
+	0x00000015,0x0007004f,0x00000007,0x00000017,0x00000016,0x00000016,0x00000000,0x00000001,
+	0x0003003e,0x00000012,0x00000017,0x00050041,0x0000001a,0x0000001b,0x00000012,0x00000019,
+	0x0004003d,0x00000006,0x0000001c,0x0000001b,0x00050041,0x0000001a,0x0000001e,0x00000012,
+	0x0000001d,0x0004003d,0x00000006,0x0000001f,0x0000001e,0x00050084,0x00000006,0x00000021,
+	0x0000001f,0x00000020,0x00050050,0x00000007,0x00000022,0x0000001c,0x00000021,0x0003003e,
+	0x00000018,0x00000022,0x00050041,0x0000001a,0x00000023,0x00000018,0x00000019,0x0004003d,
+	0x00000006,0x00000024,0x00000023,0x00050041,0x0000002a,0x0000002b,0x00000027,0x00000029,
+	0x0004003d,0x00000006,0x0000002c,0x0000002b,0x00050082,0x00000006,0x0000002d,0x0000002c,
+	0x0000001d,0x0008000c,0x00000006,0x0000002e,0x00000001,0x0000002c,0x00000024,0x00000019,
+	0x0000002d,0x00050041,0x0000001a,0x0000002f,0x00000018,0x00000019,0x0003003e,0x0000002f,
+	0x0000002e,0x00050041,0x0000001a,0x00000031,0x00000012,0x00000019,0x0004003d,0x00000006,
+	0x00000032,0x00000031,0x00050041,0x0000001a,0x00000033,0x00000012,0x0000001d,0x0004003d,
+	0x00000006,0x00000034,0x00000033,0x00050084,0x00000006,0x00000036,0x00000034,0x00000035,
+	0x00050050,0x00000007,0x00000037,0x00000032,0x00000036,0x0003003e,0x00000030,0x00000037,
+	0x00050041,0x0000001a,0x00000038,0x00000030,0x00000019,0x0004003d,0x00000006,0x00000039,
+	0x00000038,0x00050041,0x0000002a,0x0000003b,0x00000027,0x0000003a,0x0004003d,0x00000006,
+	0x0000003c,0x0000003b,0x00050082,0x00000006,0x0000003d,0x0000003c,0x0000001d,0x0008000c,
+	0x00000006,0x0000003e,0x00000001,0x0000002c,0x00000039,0x00000019,0x0000003d,0x00050041,
+	0x0000001a,0x0000003f,0x00000030,0x00000019,0x0003003e,0x0000003f,0x0000003e,0x0004003d,
+	0x00000007,0x00000041,0x00000018,0x0003003e,0x00000040,0x00000041,0x0004003d,0x00000007,
+	0x00000043,0x00000030,0x0003003e,0x00000042,0x00000043,0x00060039,0x00000002,0x00000044,
+	0x0000000c,0x00000040,0x00000042,0x00050041,0x0000001a,0x00000045,0x00000018,0x0000001d,
+	0x0004003d,0x00000006,0x00000046,0x00000045,0x00050080,0x00000006,0x00000047,0x00000046,
+	0x00000035,0x00050041,0x0000001a,0x00000048,0x00000018,0x0000001d,0x0003003e,0x00000048,
+	0x00000047,0x00050041,0x0000001a,0x00000049,0x00000030,0x0000001d,0x0004003d,0x00000006,
+	0x0000004a,0x00000049,0x00050080,0x00000006,0x0000004b,0x0000004a,0x0000001d,0x00050041,
+	0x0000001a,0x0000004c,0x00000030,0x0000001d,0x0003003e,0x0000004c,0x0000004b,0x0004003d,
+	0x00000007,0x0000004e,0x00000018,0x0003003e,0x0000004d,0x0000004e,0x0004003d,0x00000007,
+	0x00000050,0x00000030,0x0003003e,0x0000004f,0x00000050,0x00060039,0x00000002,0x00000051,
+	0x0000000c,0x0000004d,0x0000004f,0x00050041,0x0000001a,0x00000053,0x00000012,0x00000019,
+	0x0004003d,0x00000006,0x00000054,0x00000053,0x00050041,0x0000001a,0x00000055,0x00000012,
+	0x0000001d,0x0004003d,0x00000006,0x00000056,0x00000055,0x00050084,0x00000006,0x00000057,
+	0x00000056,0x00000035,0x00050050,0x00000007,0x00000058,0x00000054,0x00000057,0x0003003e,
+	0x00000052,0x00000058,0x00050041,0x0000001a,0x00000059,0x00000052,0x00000019,0x0004003d,
+	0x00000006,0x0000005a,0x00000059,0x00050041,0x0000002a,0x0000005b,0x00000027,0x00000029,
+	0x0004003d,0x00000006,0x0000005c,0x0000005b,0x00050082,0x00000006,0x0000005d,0x0000005c,
+	0x0000001d,0x0008000c,0x00000006,0x0000005e,0x00000001,0x0000002c,0x0000005a,0x00000019,
+	0x0000005d,0x00050041,0x0000001a,0x0000005f,0x00000052,0x00000019,0x0003003e,0x0000005f,
+	0x0000005e,0x0004003d,0x00000007,0x00000060,0x00000012,0x0003003e,0x00000030,0x00000060,
+	0x00050041,0x0000001a,0x00000061,0x00000030,0x00000019,0x0004003d,0x00000006,0x00000062,
+	0x00000061,0x00050041,0x0000002a,0x00000063,0x00000027,0x0000003a,0x0004003d,0x00000006,
+	0x00000064,0x00000063,0x00050082,0x00000006,0x00000065,0x00000064,0x0000001d,0x0008000c,
+	0x00000006,0x00000066,0x00000001,0x0000002c,0x00000062,0x00000019,0x00000065,0x00050041,
+	0x0000001a,0x00000067,0x00000030,0x00000019,0x0003003e,0x00000067,0x00000066,0x0004003d,
+	0x00000007,0x00000069,0x00000052,0x0003003e,0x00000068,0x00000069,0x0004003d,0x00000007,
+	0x0000006b,0x00000030,0x0003003e,0x0000006a,0x0000006b,0x00060039,0x00000002,0x0000006c,
+	0x00000010,0x00000068,0x0000006a,0x000100fd,0x00010038,0x00050036,0x00000002,0x0000000c,
+	0x00000000,0x00000009,0x00030037,0x00000008,0x0000000a,0x00030037,0x00000008,0x0000000b,
+	0x000200f8,0x0000000d,0x0004003b,0x00000008,0x0000007d,0x00000007,0x0004003b,0x00000089,
+	0x0000008a,0x00000007,0x0004003b,0x00000089,0x0000008e,0x00000007,0x0004003b,0x0000001a,
+	0x00000092,0x00000007,0x0004003b,0x00000008,0x0000009b,0x00000007,0x0004003b,0x00000089,
+	0x000000a3,0x00000007,0x0004003b,0x00000089,0x000000a7,0x00000007,0x0004003b,0x00000089,
+	0x000000b2,0x00000007,0x0004003b,0x00000089,0x000000b6,0x00000007,0x0004003b,0x00000089,
+	0x000000ba,0x00000007,0x0004003b,0x00000089,0x000000c2,0x00000007,0x0004003b,0x0000001a,
+	0x000000ca,0x00000007,0x0004003b,0x00000089,0x000000d3,0x00000007,0x0004003b,0x00000089,
+	0x000000dd,0x00000007,0x0004003b,0x00000089,0x000000ea,0x00000007,0x0004003b,0x00000089,
+	0x000000f2,0x00000007,0x0004003b,0x00000089,0x00000101,0x00000007,0x0004003b,0x00000089,
+	0x0000010b,0x00000007,0x0004003b,0x00000089,0x00000116,0x00000007,0x0004003b,0x00000089,
+	0x0000011f,0x00000007,0x0004003b,0x0000001a,0x00000130,0x00000007,0x0004003b,0x0000001a,
+	0x0000014f,0x00000007,0x0004003b,0x0000001a,0x0000017f,0x00000007,0x0004003b,0x00000089,
+	0x00000198,0x00000007,0x0004003b,0x00000089,0x000001ab,0x00000007,0x0004003b,0x00000089,
+	0x000001b5,0x00000007,0x0004003b,0x0000001a,0x000001e1,0x00000007,0x00050041,0x0000001a,
+	0x0000006d,0x0000000a,0x0000001d,0x0004003d,0x00000006,0x0000006e,0x0000006d,0x00050041,
+	0x0000002a,0x00000070,0x00000027,0x0000006f,0x0004003d,0x00000006,0x00000071,0x00000070,
+	0x00050082,0x00000006,0x00000072,0x00000071,0x0000001d,0x0008000c,0x00000006,0x00000073,
+	0x00000001,0x0000002c,0x0000006e,0x00000019,0x00000072,0x00050041,0x0000001a,0x00000074,
+	0x0000000a,0x0000001d,0x0003003e,0x00000074,0x00000073,0x00050041,0x0000001a,0x00000075,
+	0x0000000b,0x0000001d,0x0004003d,0x00000006,0x00000076,0x00000075,0x00050041,0x0000002a,
+	0x00000078,0x00000027,0x00000077,0x0004003d,0x00000006,0x00000079,0x00000078,0x00050082,
+	0x00000006,0x0000007a,0x00000079,0x00000035,0x0008000c,0x00000006,0x0000007b,0x00000001,
+	0x0000002c,0x00000076,0x00000019,0x0000007a,0x00050041,0x0000001a,0x0000007c,0x0000000b,
+	0x0000001d,0x0003003e,0x0000007c,0x0000007b,0x00050041,0x0000001a,0x00000082,0x0000000a,
+	0x00000019,0x0004003d,0x00000006,0x00000083,0x00000082,0x00060041,0x00000084,0x00000085,
+	0x00000081,0x00000029,0x00000083,0x0004003d,0x00000007,0x00000086,0x00000085,0x0003003e,
+	0x0000007d,0x00000086,0x00050041,0x0000001a,0x0000008b,0x0000007d,0x00000019,0x0004003d,
+	0x00000006,0x0000008c,0x0000008b,0x0006000c,0x00000088,0x0000008d,0x00000001,0x00000040,
+	0x0000008c,0x0003003e,0x0000008a,0x0000008d,0x00050041,0x0000001a,0x0000008f,0x0000007d,
+	0x0000001d,0x0004003d,0x00000006,0x00000090,0x0000008f,0x0006000c,0x00000088,0x00000091,
+	0x00000001,0x00000040,0x00000090,0x0003003e,0x0000008e,0x00000091,0x00050041,0x0000001a,
+	0x00000093,0x0000000a,0x0000001d,0x0004003d,0x00000006,0x00000094,0x00000093,0x00050041,
+	0x0000002a,0x00000095,0x00000027,0x00000029,0x0004003d,0x00000006,0x00000096,0x00000095,
+	0x00050084,0x00000006,0x00000097,0x00000094,0x00000096,0x00050041,0x0000001a,0x00000098,
+	0x0000000a,0x00000019,0x0004003d,0x00000006,0x00000099,0x00000098,0x00050080,0x00000006,
+	0x0000009a,0x00000097,0x00000099,0x0003003e,0x00000092,0x0000009a,0x0004003d,0x00000006,
+	0x000000a0,0x00000092,0x00060041,0x00000084,0x000000a1,0x0000009f,0x00000029,0x000000a0,
+	0x0004003d,0x00000007,0x000000a2,0x000000a1,0x0003003e,0x0000009b,0x000000a2,0x00050041,
+	0x0000001a,0x000000a4,0x0000009b,0x00000019,0x0004003d,0x00000006,0x000000a5,0x000000a4,
+	0x0006000c,0x00000088,0x000000a6,0x00000001,0x00000040,0x000000a5,0x0003003e,0x000000a3,
+	0x000000a6,0x00050041,0x0000001a,0x000000a8,0x0000009b,0x0000001d,0x0004003d,0x00000006,
+	0x000000a9,0x000000a8,0x0006000c,0x00000088,0x000000aa,0x00000001,0x00000040,0x000000a9,
+	0x0003003e,0x000000a7,0x000000aa,0x0004003d,0x00000006,0x000000af,0x00000092,0x00060041,
+	0x00000084,0x000000b0,0x000000ae,0x00000029,0x000000af,0x0004003d,0x00000007,0x000000b1,
+	0x000000b0,0x0003003e,0x0000009b,0x000000b1,0x00050041,0x0000001a,0x000000b3,0x0000009b,
+	0x00000019,0x0004003d,0x00000006,0x000000b4,0x000000b3,0x0006000c,0x00000088,0x000000b5,
+	0x00000001,0x00000040,0x000000b4,0x0003003e,0x000000b2,0x000000b5,0x00050041,0x0000001a,
+	0x000000b7,0x0000009b,0x0000001d,0x0004003d,0x00000006,0x000000b8,0x000000b7,0x0006000c,
+	0x00000088,0x000000b9,0x00000001,0x00000040,0x000000b8,0x0003003e,0x000000b6,0x000000b9,
+	0x0004003d,0x00000088,0x000000bb,0x000000a3,0x0004003d,0x00000088,0x000000bc,0x000000b2,
+	0x00050083,0x00000088,0x000000bd,0x000000bb,0x000000bc,0x0004003d,0x00000088,0x000000be,
+	0x0000008a,0x00050085,0x00000088,0x000000bf,0x000000bd,0x000000be,0x0004003d,0x00000088,
+	0x000000c0,0x000000b2,0x00050081,0x00000088,0x000000c1,0x000000bf,0x000000c0,0x0003003e,
+	0x000000ba,0x000000c1,0x0004003d,0x00000088,0x000000c3,0x000000a7,0x0004003d,0x00000088,
+	0x000000c4,0x000000b6,0x00050083,0x00000088,0x000000c5,0x000000c3,0x000000c4,0x0004003d,
+	0x00000088,0x000000c6,0x0000008e,0x00050085,0x00000088,0x000000c7,0x000000c5,0x000000c6,
+	0x0004003d,0x00000088,0x000000c8,0x000000b6,0x00050081,0x00000088,0x000000c9,0x000000c7,
+	0x000000c8,0x0003003e,0x000000c2,0x000000c9,0x00050041,0x0000001a,0x000000cb,0x0000000b,
+	0x0000001d,0x0004003d,0x00000006,0x000000cc,0x000000cb,0x00050041,0x0000002a,0x000000cd,
+	0x00000027,0x0000003a,0x0004003d,0x00000006,0x000000ce,0x000000cd,0x00050084,0x00000006,
+	0x000000cf,0x000000cc,0x000000ce,0x00050041,0x0000001a,0x000000d0,0x0000000b,0x00000019,
+	0x0004003d,0x00000006,0x000000d1,0x000000d0,0x00050080,0x00000006,0x000000d2,0x000000cf,
+	0x000000d1,0x0003003e,0x000000ca,0x000000d2,0x0004003d,0x00000006,0x000000d8,0x000000ca,
+	0x00060041,0x000000d9,0x000000da,0x000000d7,0x00000029,0x000000d8,0x0004003d,0x00000006,
+	0x000000db,0x000000da,0x0006000c,0x00000088,0x000000dc,0x00000001,0x00000040,0x000000db,
+	0x0003003e,0x000000d3,0x000000dc,0x0004003d,0x00000006,0x000000de,0x000000ca,0x00050080,
+	0x00000006,0x000000df,0x000000de,0x0000001d,0x00060041,0x000000d9,0x000000e0,0x000000d7,
+	0x00000029,0x000000df,0x0004003d,0x00000006,0x000000e1,0x000000e0,0x0006000c,0x00000088,
+	0x000000e2,0x00000001,0x00000040,0x000000e1,0x0003003e,0x000000dd,0x000000e2,0x00050041,
+	0x0000001a,0x000000e3,0x0000000b,0x00000019,0x0004003d,0x00000006,0x000000e4,0x000000e3,
+	0x00050041,0x0000002a,0x000000e5,0x00000027,0x0000003a,0x0004003d,0x00000006,0x000000e6,
+	0x000000e5,0x00050082,0x00000006,0x000000e7,0x000000e6,0x0000001d,0x000500aa,0x000000e8,
+	0x000000e9,0x000000e4,0x000000e7,0x000300f7,0x000000ec,0x00000000,0x000400fa,0x000000e9,
+	0x000000eb,0x000000ef,0x000200f8,0x000000eb,0x0004003d,0x00000088,0x000000ed,0x000000d3,
+	0x0009004f,0x00000088,0x000000ee,0x000000ed,0x000000ed,0x00000003,0x00000003,0x00000003,
+	0x00000003,0x0003003e,0x000000ea,0x000000ee,0x000200f9,0x000000ec,0x000200f8,0x000000ef,
+	0x0004003d,0x00000088,0x000000f0,0x000000dd,0x0003003e,0x000000ea,0x000000f0,0x000200f9,
+	0x000000ec,0x000200f8,0x000000ec,0x0004003d,0x00000088,0x000000f1,0x000000ea,0x0003003e,
+	0x000000dd,0x000000f1,0x0004003d,0x00000088,0x000000f3,0x000000d3,0x0004003d,0x00000088,
+	0x000000f5,0x000000d3,0x0008004f,0x000000f4,0x000000f6,0x000000f5,0x000000f5,0x00000001,
+	0x00000002,0x00000003,0x00050041,0x000000f7,0x000000f8,0x000000dd,0x00000019,0x0004003d,
+	0x00000087,0x000000f9,0x000000f8,0x00050051,0x00000087,0x000000fa,0x000000f6,0x00000000,
+	0x00050051,0x00000087,0x000000fb,0x000000f6,0x00000001,0x00050051,0x00000087,0x000000fc,
+	0x000000f6,0x00000002,0x00070050,0x00000088,0x000000fd,0x000000fa,0x000000fb,0x000000fc,
+	0x000000f9,0x00050081,0x00000088,0x000000fe,0x000000f3,0x000000fd,0x0005008e,0x00000088,
+	0x00000100,0x000000fe,0x000000ff,0x0003003e,0x000000f2,0x00000100,0x00050041,0x000000f7,
+	0x00000102,0x000000d3,0x00000019,0x0004003d,0x00000087,0x00000103,0x00000102,0x00050041,
+	0x000000f7,0x00000104,0x000000f2,0x00000019,0x0004003d,0x00000087,0x00000105,0x00000104,
+	0x00050041,0x000000f7,0x00000106,0x000000d3,0x0000001d,0x0004003d,0x00000087,0x00000107,
+	0x00000106,0x00050041,0x000000f7,0x00000108,0x000000f2,0x0000001d,0x0004003d,0x00000087,
+	0x00000109,0x00000108,0x00070050,0x00000088,0x0000010a,0x00000103,0x00000105,0x00000107,
+	0x00000109,0x0003003e,0x00000101,0x0000010a,0x00050041,0x000000f7,0x0000010c,0x000000d3,
+	0x00000035,0x0004003d,0x00000087,0x0000010d,0x0000010c,0x00050041,0x000000f7,0x0000010e,
+	0x000000f2,0x00000035,0x0004003d,0x00000087,0x0000010f,0x0000010e,0x00050041,0x000000f7,
+	0x00000111,0x000000d3,0x00000110,0x0004003d,0x00000087,0x00000112,0x00000111,0x00050041,
+	0x000000f7,0x00000113,0x000000f2,0x00000110,0x0004003d,0x00000087,0x00000114,0x00000113,
+	0x00070050,0x00000088,0x00000115,0x0000010d,0x0000010f,0x00000112,0x00000114,0x0003003e,
+	0x0000010b,0x00000115,0x0004003d,0x00000088,0x00000117,0x00000101,0x0004003d,0x00000088,
+	0x00000118,0x000000ba,0x0005008e,0x00000088,0x0000011a,0x00000118,0x00000119,0x00050081,
+	0x00000088,0x0000011b,0x00000117,0x0000011a,0x00070050,0x00000088,0x0000011d,0x0000011c,
+	0x0000011c,0x0000011c,0x0000011c,0x00050083,0x00000088,0x0000011e,0x0000011b,0x0000011d,
+	0x0003003e,0x00000116,0x0000011e,0x0004003d,0x00000088,0x00000120,0x0000010b,0x0004003d,
+	0x00000088,0x00000121,0x000000c2,0x0005008e,0x00000088,0x00000122,0x00000121,0x00000119,
+	0x00050081,0x00000088,0x00000123,0x00000120,0x00000122,0x00070050,0x00000088,0x00000124,
+	0x0000011c,0x0000011c,0x0000011c,0x0000011c,0x00050083,0x00000088,0x00000125,0x00000123,
+	0x00000124,0x0003003e,0x0000011f,0x00000125,0x0004003d,0x00000088,0x00000126,0x00000116,
+	0x00070050,0x00000088,0x00000129,0x00000127,0x00000127,0x00000127,0x00000127,0x00070050,
+	0x00000088,0x0000012a,0x00000128,0x00000128,0x00000128,0x00000128,0x0008000c,0x00000088,
+	0x0000012b,0x00000001,0x0000002b,0x00000126,0x00000129,0x0000012a,0x0003003e,0x00000116,
+	0x0000012b,0x0004003d,0x00000088,0x0000012c,0x0000011f,0x00070050,0x00000088,0x0000012d,
+	0x00000127,0x00000127,0x00000127,0x00000127,0x00070050,0x00000088,0x0000012e,0x00000128,
+	0x00000128,0x00000128,0x00000128,0x0008000c,0x00000088,0x0000012f,0x00000001,0x0000002b,
+	0x0000012c,0x0000012d,0x0000012e,0x0003003e,0x0000011f,0x0000012f,0x00050041,0x0000001a,
+	0x00000131,0x0000000a,0x0000001d,0x0004003d,0x00000006,0x00000132,0x00000131,0x00050041,
+	0x0000002a,0x00000134,0x00000027,0x00000133,0x0004003d,0x00000006,0x00000135,0x00000134,
+	0x00050084,0x00000006,0x00000136,0x00000132,0x00000135,0x00050041,0x0000002a,0x00000138,
+	0x00000027,0x00000137,0x0004003d,0x00000006,0x00000139,0x00000138,0x00050080,0x00000006,
+	0x0000013a,0x00000136,0x00000139,0x00050041,0x0000001a,0x0000013b,0x0000000a,0x00000019,
+	0x0004003d,0x00000006,0x0000013c,0x0000013b,0x00050080,0x00000006,0x0000013d,0x0000013a,
+	0x0000013c,0x0003003e,0x00000130,0x0000013d,0x0004003d,0x00000006,0x00000142,0x00000130,
+	0x0004003d,0x00000088,0x00000143,0x00000116,0x0006000c,0x00000006,0x00000144,0x00000001,
+	0x00000037,0x00000143,0x0004003d,0x00000088,0x00000145,0x0000011f,0x0006000c,0x00000006,
+	0x00000146,0x00000001,0x00000037,0x00000145,0x00050050,0x00000007,0x00000147,0x00000144,
+	0x00000146,0x00060041,0x00000084,0x00000148,0x00000141,0x00000029,0x00000142,0x0003003e,
+	0x00000148,0x00000147,0x00050041,0x0000001a,0x00000149,0x0000000a,0x0000001d,0x0004003d,
+	0x00000006,0x0000014a,0x00000149,0x00050041,0x0000002a,0x0000014b,0x00000027,0x0000006f,
+	0x0004003d,0x00000006,0x0000014c,0x0000014b,0x00050082,0x00000006,0x0000014d,0x0000014c,
+	0x0000001d,0x000500ae,0x000000e8,0x0000014e,0x0000014a,0x0000014d,0x000300f7,0x00000151,
+	0x00000000,0x000400fa,0x0000014e,0x00000150,0x00000153,0x000200f8,0x00000150,0x0004003d,
+	0x00000006,0x00000152,0x00000092,0x0003003e,0x0000014f,0x00000152,0x000200f9,0x00000151,
+	0x000200f8,0x00000153,0x0004003d,0x00000006,0x00000154,0x00000092,0x00050041,0x0000002a,
+	0x00000155,0x00000027,0x00000029,0x0004003d,0x00000006,0x00000156,0x00000155,0x00050080,
+	0x00000006,0x00000157,0x00000154,0x00000156,0x0003003e,0x0000014f,0x00000157,0x000200f9,
+	0x00000151,0x000200f8,0x00000151,0x0004003d,0x00000006,0x00000158,0x0000014f,0x0003003e,
+	0x00000092,0x00000158,0x0004003d,0x00000006,0x00000159,0x00000092,0x00060041,0x00000084,
+	0x0000015a,0x0000009f,0x00000029,0x00000159,0x0004003d,0x00000007,0x0000015b,0x0000015a,
+	0x0003003e,0x0000009b,0x0000015b,0x00050041,0x0000001a,0x0000015c,0x0000009b,0x00000019,
+	0x0004003d,0x00000006,0x0000015d,0x0000015c,0x0006000c,0x00000088,0x0000015e,0x00000001,
+	0x00000040,0x0000015d,0x0003003e,0x000000a3,0x0000015e,0x00050041,0x0000001a,0x0000015f,
+	0x0000009b,0x0000001d,0x0004003d,0x00000006,0x00000160,0x0000015f,0x0006000c,0x00000088,
+	0x00000161,0x00000001,0x00000040,0x00000160,0x0003003e,0x000000a7,0x00000161,0x0004003d,
+	0x00000006,0x00000162,0x00000092,0x00060041,0x00000084,0x00000163,0x000000ae,0x00000029,
+	0x00000162,0x0004003d,0x00000007,0x00000164,0x00000163,0x0003003e,0x0000009b,0x00000164,
+	0x00050041,0x0000001a,0x00000165,0x0000009b,0x00000019,0x0004003d,0x00000006,0x00000166,
+	0x00000165,0x0006000c,0x00000088,0x00000167,0x00000001,0x00000040,0x00000166,0x0003003e,
+	0x000000b2,0x00000167,0x00050041,0x0000001a,0x00000168,0x0000009b,0x0000001d,0x0004003d,
+	0x00000006,0x00000169,0x00000168,0x0006000c,0x00000088,0x0000016a,0x00000001,0x00000040,
+	0x00000169,0x0003003e,0x000000b6,0x0000016a,0x0004003d,0x00000088,0x0000016b,0x000000a3,
+	0x0004003d,0x00000088,0x0000016c,0x000000b2,0x00050083,0x00000088,0x0000016d,0x0000016b,
+	0x0000016c,0x0004003d,0x00000088,0x0000016e,0x0000008a,0x00050085,0x00000088,0x0000016f,
+	0x0000016d,0x0000016e,0x0004003d,0x00000088,0x00000170,0x000000b2,0x00050081,0x00000088,
+	0x00000171,0x0000016f,0x00000170,0x0003003e,0x000000ba,0x00000171,0x0004003d,0x00000088,
+	0x00000172,0x000000a7,0x0004003d,0x00000088,0x00000173,0x000000b6,0x00050083,0x00000088,
+	0x00000174,0x00000172,0x00000173,0x0004003d,0x00000088,0x00000175,0x0000008e,0x00050085,
+	0x00000088,0x00000176,0x00000174,0x00000175,0x0004003d,0x00000088,0x00000177,0x000000b6,
+	0x00050081,0x00000088,0x00000178,0x00000176,0x00000177,0x0003003e,0x000000c2,0x00000178,
+	0x00050041,0x0000001a,0x00000179,0x0000000b,0x0000001d,0x0004003d,0x00000006,0x0000017a,
+	0x00000179,0x00050041,0x0000002a,0x0000017b,0x00000027,0x00000077,0x0004003d,0x00000006,
+	0x0000017c,0x0000017b,0x00050082,0x00000006,0x0000017d,0x0000017c,0x0000001d,0x000500ae,
+	0x000000e8,0x0000017e,0x0000017a,0x0000017d,0x000300f7,0x00000181,0x00000000,0x000400fa,
+	0x0000017e,0x00000180,0x00000183,0x000200f8,0x00000180,0x0004003d,0x00000006,0x00000182,
+	0x000000ca,0x0003003e,0x0000017f,0x00000182,0x000200f9,0x00000181,0x000200f8,0x00000183,
+	0x0004003d,0x00000006,0x00000184,0x000000ca,0x00050041,0x0000002a,0x00000185,0x00000027,
+	0x0000003a,0x0004003d,0x00000006,0x00000186,0x00000185,0x00050080,0x00000006,0x00000187,
+	0x00000184,0x00000186,0x0003003e,0x0000017f,0x00000187,0x000200f9,0x00000181,0x000200f8,
+	0x00000181,0x0004003d,0x00000006,0x00000188,0x0000017f,0x0003003e,0x000000ca,0x00000188,
+	0x0004003d,0x00000006,0x00000189,0x000000ca,0x00060041,0x000000d9,0x0000018a,0x000000d7,
+	0x00000029,0x00000189,0x0004003d,0x00000006,0x0000018b,0x0000018a,0x0006000c,0x00000088,
+	0x0000018c,0x00000001,0x00000040,0x0000018b,0x0003003e,0x000000d3,0x0000018c,0x0004003d,
+	0x00000006,0x0000018d,0x000000ca,0x00050080,0x00000006,0x0000018e,0x0000018d,0x0000001d,
+	0x00060041,0x000000d9,0x0000018f,0x000000d7,0x00000029,0x0000018e,0x0004003d,0x00000006,
+	0x00000190,0x0000018f,0x0006000c,0x00000088,0x00000191,0x00000001,0x00000040,0x00000190,
+	0x0003003e,0x000000dd,0x00000191,0x00050041,0x0000001a,0x00000192,0x0000000b,0x00000019,
+	0x0004003d,0x00000006,0x00000193,0x00000192,0x00050041,0x0000002a,0x00000194,0x00000027,
+	0x0000003a,0x0004003d,0x00000006,0x00000195,0x00000194,0x00050082,0x00000006,0x00000196,
+	0x00000195,0x0000001d,0x000500aa,0x000000e8,0x00000197,0x00000193,0x00000196,0x000300f7,
+	0x0000019a,0x00000000,0x000400fa,0x00000197,0x00000199,0x0000019d,0x000200f8,0x00000199,
+	0x0004003d,0x00000088,0x0000019b,0x000000d3,0x0009004f,0x00000088,0x0000019c,0x0000019b,
+	0x0000019b,0x00000003,0x00000003,0x00000003,0x00000003,0x0003003e,0x00000198,0x0000019c,
+	0x000200f9,0x0000019a,0x000200f8,0x0000019d,0x0004003d,0x00000088,0x0000019e,0x000000dd,
+	0x0003003e,0x00000198,0x0000019e,0x000200f9,0x0000019a,0x000200f8,0x0000019a,0x0004003d,
+	0x00000088,0x0000019f,0x00000198,0x0003003e,0x000000dd,0x0000019f,0x0004003d,0x00000088,
+	0x000001a0,0x000000d3,0x0004003d,0x00000088,0x000001a1,0x000000d3,0x0008004f,0x000000f4,
+	0x000001a2,0x000001a1,0x000001a1,0x00000001,0x00000002,0x00000003,0x00050041,0x000000f7,
+	0x000001a3,0x000000dd,0x00000019,0x0004003d,0x00000087,0x000001a4,0x000001a3,0x00050051,
+	0x00000087,0x000001a5,0x000001a2,0x00000000,0x00050051,0x00000087,0x000001a6,0x000001a2,
+	0x00000001,0x00050051,0x00000087,0x000001a7,0x000001a2,0x00000002,0x00070050,0x00000088,
+	0x000001a8,0x000001a5,0x000001a6,0x000001a7,0x000001a4,0x00050081,0x00000088,0x000001a9,
+	0x000001a0,0x000001a8,0x0005008e,0x00000088,0x000001aa,0x000001a9,0x000000ff,0x0003003e,
+	0x000000f2,0x000001aa,0x00050041,0x000000f7,0x000001ac,0x000000d3,0x00000019,0x0004003d,
+	0x00000087,0x000001ad,0x000001ac,0x00050041,0x000000f7,0x000001ae,0x000000f2,0x00000019,
+	0x0004003d,0x00000087,0x000001af,0x000001ae,0x00050041,0x000000f7,0x000001b0,0x000000d3,
+	0x0000001d,0x0004003d,0x00000087,0x000001b1,0x000001b0,0x00050041,0x000000f7,0x000001b2,
+	0x000000f2,0x0000001d,0x0004003d,0x00000087,0x000001b3,0x000001b2,0x00070050,0x00000088,
+	0x000001b4,0x000001ad,0x000001af,0x000001b1,0x000001b3,0x0003003e,0x000001ab,0x000001b4,
+	0x00050041,0x000000f7,0x000001b6,0x000000d3,0x00000035,0x0004003d,0x00000087,0x000001b7,
+	0x000001b6,0x00050041,0x000000f7,0x000001b8,0x000000f2,0x00000035,0x0004003d,0x00000087,
+	0x000001b9,0x000001b8,0x00050041,0x000000f7,0x000001ba,0x000000d3,0x00000110,0x0004003d,
+	0x00000087,0x000001bb,0x000001ba,0x00050041,0x000000f7,0x000001bc,0x000000f2,0x00000110,
+	0x0004003d,0x00000087,0x000001bd,0x000001bc,0x00070050,0x00000088,0x000001be,0x000001b7,
+	0x000001b9,0x000001bb,0x000001bd,0x0003003e,0x000001b5,0x000001be,0x0004003d,0x00000088,
+	0x000001bf,0x00000101,0x0004003d,0x00000088,0x000001c0,0x000001ab,0x00050081,0x00000088,
+	0x000001c1,0x000001bf,0x000001c0,0x0005008e,0x00000088,0x000001c2,0x000001c1,0x000000ff,
+	0x0003003e,0x000001ab,0x000001c2,0x0004003d,0x00000088,0x000001c3,0x0000010b,0x0004003d,
+	0x00000088,0x000001c4,0x000001b5,0x00050081,0x00000088,0x000001c5,0x000001c3,0x000001c4,
+	0x0005008e,0x00000088,0x000001c6,0x000001c5,0x000000ff,0x0003003e,0x000001b5,0x000001c6,
+	0x0004003d,0x00000088,0x000001c7,0x000001ab,0x0004003d,0x00000088,0x000001c8,0x000000ba,
+	0x0005008e,0x00000088,0x000001c9,0x000001c8,0x00000119,0x00050081,0x00000088,0x000001ca,
+	0x000001c7,0x000001c9,0x00070050,0x00000088,0x000001cb,0x0000011c,0x0000011c,0x0000011c,
+	0x0000011c,0x00050083,0x00000088,0x000001cc,0x000001ca,0x000001cb,0x0003003e,0x00000116,
+	0x000001cc,0x0004003d,0x00000088,0x000001cd,0x000001b5,0x0004003d,0x00000088,0x000001ce,
+	0x000000c2,0x0005008e,0x00000088,0x000001cf,0x000001ce,0x00000119,0x00050081,0x00000088,
+	0x000001d0,0x000001cd,0x000001cf,0x00070050,0x00000088,0x000001d1,0x0000011c,0x0000011c,
+	0x0000011c,0x0000011c,0x00050083,0x00000088,0x000001d2,0x000001d0,0x000001d1,0x0003003e,
+	0x0000011f,0x000001d2,0x0004003d,0x00000088,0x000001d3,0x00000116,0x00070050,0x00000088,
+	0x000001d4,0x00000127,0x00000127,0x00000127,0x00000127,0x00070050,0x00000088,0x000001d5,
+	0x00000128,0x00000128,0x00000128,0x00000128,0x0008000c,0x00000088,0x000001d6,0x00000001,
+	0x0000002b,0x000001d3,0x000001d4,0x000001d5,0x0003003e,0x00000116,0x000001d6,0x0004003d,
+	0x00000088,0x000001d7,0x0000011f,0x00070050,0x00000088,0x000001d8,0x00000127,0x00000127,
+	0x00000127,0x00000127,0x00070050,0x00000088,0x000001d9,0x00000128,0x00000128,0x00000128,
+	0x00000128,0x0008000c,0x00000088,0x000001da,0x00000001,0x0000002b,0x000001d7,0x000001d8,
+	0x000001d9,0x0003003e,0x0000011f,0x000001da,0x00050041,0x0000001a,0x000001db,0x0000000a,
+	0x0000001d,0x0004003d,0x00000006,0x000001dc,0x000001db,0x00050041,0x0000002a,0x000001dd,
+	0x00000027,0x0000006f,0x0004003d,0x00000006,0x000001de,0x000001dd,0x00050082,0x00000006,
+	0x000001df,0x000001de,0x0000001d,0x000500ae,0x000000e8,0x000001e0,0x000001dc,0x000001df,
+	0x000300f7,0x000001e3,0x00000000,0x000400fa,0x000001e0,0x000001e2,0x000001e5,0x000200f8,
+	0x000001e2,0x0004003d,0x00000006,0x000001e4,0x00000130,0x0003003e,0x000001e1,0x000001e4,
+	0x000200f9,0x000001e3,0x000200f8,0x000001e5,0x0004003d,0x00000006,0x000001e6,0x00000130,
+	0x00050041,0x0000002a,0x000001e7,0x00000027,0x00000133,0x0004003d,0x00000006,0x000001e8,
+	0x000001e7,0x00050080,0x00000006,0x000001e9,0x000001e6,0x000001e8,0x0003003e,0x000001e1,
+	0x000001e9,0x000200f9,0x000001e3,0x000200f8,0x000001e3,0x0004003d,0x00000006,0x000001ea,
+	0x000001e1,0x0003003e,0x00000130,0x000001ea,0x0004003d,0x00000006,0x000001eb,0x00000130,
+	0x0004003d,0x00000088,0x000001ec,0x00000116,0x0006000c,0x00000006,0x000001ed,0x00000001,
+	0x00000037,0x000001ec,0x0004003d,0x00000088,0x000001ee,0x0000011f,0x0006000c,0x00000006,
+	0x000001ef,0x00000001,0x00000037,0x000001ee,0x00050050,0x00000007,0x000001f0,0x000001ed,
+	0x000001ef,0x00060041,0x00000084,0x000001f1,0x00000141,0x00000029,0x000001eb,0x0003003e,
+	0x000001f1,0x000001f0,0x000100fd,0x00010038,0x00050036,0x00000002,0x00000010,0x00000000,
+	0x00000009,0x00030037,0x00000008,0x0000000e,0x00030037,0x00000008,0x0000000f,0x000200f8,
+	0x00000011,0x0004003b,0x00000008,0x00000202,0x00000007,0x0004003b,0x00000089,0x00000207,
+	0x00000007,0x0004003b,0x00000089,0x0000020b,0x00000007,0x0004003b,0x0000001a,0x0000020f,
+	0x00000007,0x0004003b,0x00000008,0x00000218,0x00000007,0x0004003b,0x00000089,0x00000220,
+	0x00000007,0x0004003b,0x00000089,0x00000224,0x00000007,0x0004003b,0x00000089,0x0000022f,
+	0x00000007,0x0004003b,0x00000089,0x00000233,0x00000007,0x0004003b,0x00000089,0x00000240,
+	0x00000007,0x0004003b,0x00000089,0x00000248,0x00000007,0x0004003b,0x0000001a,0x00000250,
+	0x00000007,0x0004003b,0x00000089,0x00000259,0x00000007,0x0004003b,0x00000089,0x00000262,
+	0x00000007,0x0004003b,0x00000089,0x0000026e,0x00000007,0x0004003b,0x00000089,0x00000276,
+	0x00000007,0x0004003b,0x00000089,0x00000283,0x00000007,0x0004003b,0x00000089,0x0000028d,
+	0x00000007,0x0004003b,0x00000089,0x00000297,0x00000007,0x0004003b,0x00000089,0x0000029e,
+	0x00000007,0x0004003b,0x0000001a,0x000002ad,0x00000007,0x0004003b,0x0000001a,0x000002cb,
+	0x00000007,0x0004003b,0x0000001a,0x000002fc,0x00000007,0x0004003b,0x00000089,0x00000315,
+	0x00000007,0x0004003b,0x00000089,0x00000329,0x00000007,0x0004003b,0x00000089,0x00000333,
+	0x00000007,0x00050041,0x0000001a,0x000001f2,0x0000000e,0x0000001d,0x0004003d,0x00000006,
+	0x000001f3,0x000001f2,0x00050041,0x0000002a,0x000001f4,0x00000027,0x0000006f,0x0004003d,
+	0x00000006,0x000001f5,0x000001f4,0x00050086,0x00000006,0x000001f6,0x000001f5,0x00000035,
+	0x00050082,0x00000006,0x000001f7,0x000001f6,0x00000035,0x0008000c,0x00000006,0x000001f8,
+	0x00000001,0x0000002c,0x000001f3,0x00000019,0x000001f7,0x00050041,0x0000001a,0x000001f9,
+	0x0000000e,0x0000001d,0x0003003e,0x000001f9,0x000001f8,0x00050041,0x0000001a,0x000001fa,
+	0x0000000f,0x0000001d,0x0004003d,0x00000006,0x000001fb,0x000001fa,0x00050041,0x0000002a,
+	0x000001fc,0x00000027,0x00000077,0x0004003d,0x00000006,0x000001fd,0x000001fc,0x00050086,
+	0x00000006,0x000001fe,0x000001fd,0x00000035,0x00050082,0x00000006,0x000001ff,0x000001fe,
+	0x0000001d,0x0008000c,0x00000006,0x00000200,0x00000001,0x0000002c,0x000001fb,0x00000019,
+	0x000001ff,0x00050041,0x0000001a,0x00000201,0x0000000f,0x0000001d,0x0003003e,0x00000201,
+	0x00000200,0x00050041,0x0000001a,0x00000203,0x0000000e,0x00000019,0x0004003d,0x00000006,
+	0x00000204,0x00000203,0x00060041,0x00000084,0x00000205,0x00000081,0x00000029,0x00000204,
+	0x0004003d,0x00000007,0x00000206,0x00000205,0x0003003e,0x00000202,0x00000206,0x00050041,
+	0x0000001a,0x00000208,0x00000202,0x00000019,0x0004003d,0x00000006,0x00000209,0x00000208,
+	0x0006000c,0x00000088,0x0000020a,0x00000001,0x00000040,0x00000209,0x0003003e,0x00000207,
+	0x0000020a,0x00050041,0x0000001a,0x0000020c,0x00000202,0x0000001d,0x0004003d,0x00000006,
+	0x0000020d,0x0000020c,0x0006000c,0x00000088,0x0000020e,0x00000001,0x00000040,0x0000020d,
+	0x0003003e,0x0000020b,0x0000020e,0x00050041,0x0000001a,0x00000210,0x0000000e,0x0000001d,
+	0x0004003d,0x00000006,0x00000211,0x00000210,0x00050041,0x0000002a,0x00000212,0x00000027,
+	0x00000029,0x0004003d,0x00000006,0x00000213,0x00000212,0x00050084,0x00000006,0x00000214,
+	0x00000211,0x00000213,0x00050041,0x0000001a,0x00000215,0x0000000e,0x00000019,0x0004003d,
+	0x00000006,0x00000216,0x00000215,0x00050080,0x00000006,0x00000217,0x00000214,0x00000216,
+	0x0003003e,0x0000020f,0x00000217,0x0004003d,0x00000006,0x0000021d,0x0000020f,0x00060041,
+	0x00000084,0x0000021e,0x0000021c,0x00000029,0x0000021d,0x0004003d,0x00000007,0x0000021f,
+	0x0000021e,0x0003003e,0x00000218,0x0000021f,0x00050041,0x0000001a,0x00000221,0x00000218,
+	0x00000019,0x0004003d,0x00000006,0x00000222,0x00000221,0x0006000c,0x00000088,0x00000223,
+	0x00000001,0x00000040,0x00000222,0x0003003e,0x00000220,0x00000223,0x00050041,0x0000001a,
+	0x00000225,0x00000218,0x0000001d,0x0004003d,0x00000006,0x00000226,0x00000225,0x0006000c,
+	0x00000088,0x00000227,0x00000001,0x00000040,0x00000226,0x0003003e,0x00000224,0x00000227,
+	0x0004003d,0x00000006,0x0000022c,0x0000020f,0x00060041,0x00000084,0x0000022d,0x0000022b,
+	0x00000029,0x0000022c,0x0004003d,0x00000007,0x0000022e,0x0000022d,0x0003003e,0x00000218,
+	0x0000022e,0x00050041,0x0000001a,0x00000230,0x00000218,0x00000019,0x0004003d,0x00000006,
+	0x00000231,0x00000230,0x0006000c,0x00000088,0x00000232,0x00000001,0x00000040,0x00000231,
+	0x0003003e,0x0000022f,0x00000232,0x00050041,0x0000001a,0x00000234,0x00000218,0x0000001d,
+	0x0004003d,0x00000006,0x00000235,0x00000234,0x0006000c,0x00000088,0x00000236,0x00000001,
+	0x00000040,0x00000235,0x0003003e,0x00000233,0x00000236,0x0004003d,0x00000088,0x00000238,
+	0x00000207,0x0007004f,0x00000237,0x00000239,0x00000238,0x00000238,0x00000000,0x00000002,
+	0x0004003d,0x00000088,0x0000023a,0x00000207,0x0009004f,0x00000088,0x0000023b,0x0000023a,
+	0x00000239,0x00000000,0x00000004,0x00000002,0x00000005,0x0003003e,0x00000207,0x0000023b,
+	0x0004003d,0x00000088,0x0000023c,0x0000020b,0x0007004f,0x00000237,0x0000023d,0x0000023c,
+	0x0000023c,0x00000000,0x00000002,0x0004003d,0x00000088,0x0000023e,0x0000020b,0x0009004f,
+	0x00000088,0x0000023f,0x0000023e,0x0000023d,0x00000000,0x00000004,0x00000002,0x00000005,
+	0x0003003e,0x0000020b,0x0000023f,0x0004003d,0x00000088,0x00000241,0x00000220,0x0004003d,
+	0x00000088,0x00000242,0x0000022f,0x00050083,0x00000088,0x00000243,0x00000241,0x00000242,
+	0x0004003d,0x00000088,0x00000244,0x00000207,0x00050085,0x00000088,0x00000245,0x00000243,
+	0x00000244,0x0004003d,0x00000088,0x00000246,0x0000022f,0x00050081,0x00000088,0x00000247,
+	0x00000245,0x00000246,0x0003003e,0x00000240,0x00000247,0x0004003d,0x00000088,0x00000249,
+	0x00000224,0x0004003d,0x00000088,0x0000024a,0x00000233,0x00050083,0x00000088,0x0000024b,
+	0x00000249,0x0000024a,0x0004003d,0x00000088,0x0000024c,0x0000020b,0x00050085,0x00000088,
+	0x0000024d,0x0000024b,0x0000024c,0x0004003d,0x00000088,0x0000024e,0x00000233,0x00050081,
+	0x00000088,0x0000024f,0x0000024d,0x0000024e,0x0003003e,0x00000248,0x0000024f,0x00050041,
+	0x0000001a,0x00000251,0x0000000f,0x0000001d,0x0004003d,0x00000006,0x00000252,0x00000251,
+	0x00050041,0x0000002a,0x00000253,0x00000027,0x0000003a,0x0004003d,0x00000006,0x00000254,
+	0x00000253,0x00050084,0x00000006,0x00000255,0x00000252,0x00000254,0x00050041,0x0000001a,
+	0x00000256,0x0000000f,0x00000019,0x0004003d,0x00000006,0x00000257,0x00000256,0x00050080,
+	0x00000006,0x00000258,0x00000255,0x00000257,0x0003003e,0x00000250,0x00000258,0x0004003d,
+	0x00000006,0x0000025e,0x00000250,0x00060041,0x000000d9,0x0000025f,0x0000025d,0x00000029,
+	0x0000025e,0x0004003d,0x00000006,0x00000260,0x0000025f,0x0006000c,0x00000088,0x00000261,
+	0x00000001,0x00000040,0x00000260,0x0003003e,0x00000259,0x00000261,0x0004003d,0x00000006,
+	0x00000263,0x00000250,0x00050080,0x00000006,0x00000264,0x00000263,0x0000001d,0x00060041,
+	0x000000d9,0x00000265,0x0000025d,0x00000029,0x00000264,0x0004003d,0x00000006,0x00000266,
+	0x00000265,0x0006000c,0x00000088,0x00000267,0x00000001,0x00000040,0x00000266,0x0003003e,
+	0x00000262,0x00000267,0x00050041,0x0000001a,0x00000268,0x0000000f,0x00000019,0x0004003d,
+	0x00000006,0x00000269,0x00000268,0x00050041,0x0000002a,0x0000026a,0x00000027,0x0000003a,
+	0x0004003d,0x00000006,0x0000026b,0x0000026a,0x00050082,0x00000006,0x0000026c,0x0000026b,
+	0x0000001d,0x000500aa,0x000000e8,0x0000026d,0x00000269,0x0000026c,0x000300f7,0x00000270,
+	0x00000000,0x000400fa,0x0000026d,0x0000026f,0x00000273,0x000200f8,0x0000026f,0x0004003d,
+	0x00000088,0x00000271,0x00000259,0x0009004f,0x00000088,0x00000272,0x00000271,0x00000271,
+	0x00000002,0x00000003,0x00000002,0x00000003,0x0003003e,0x0000026e,0x00000272,0x000200f9,
+	0x00000270,0x000200f8,0x00000273,0x0004003d,0x00000088,0x00000274,0x00000262,0x0003003e,
+	0x0000026e,0x00000274,0x000200f9,0x00000270,0x000200f8,0x00000270,0x0004003d,0x00000088,
+	0x00000275,0x0000026e,0x0003003e,0x00000262,0x00000275,0x0004003d,0x00000088,0x00000277,
+	0x00000259,0x0004003d,0x00000088,0x00000278,0x00000259,0x0007004f,0x00000237,0x00000279,
+	0x00000278,0x00000278,0x00000002,0x00000003,0x0004003d,0x00000088,0x0000027a,0x00000262,
+	0x0007004f,0x00000237,0x0000027b,0x0000027a,0x0000027a,0x00000000,0x00000001,0x00050051,
+	0x00000087,0x0000027c,0x00000279,0x00000000,0x00050051,0x00000087,0x0000027d,0x00000279,
+	0x00000001,0x00050051,0x00000087,0x0000027e,0x0000027b,0x00000000,0x00050051,0x00000087,
+	0x0000027f,0x0000027b,0x00000001,0x00070050,0x00000088,0x00000280,0x0000027c,0x0000027d,
+	0x0000027e,0x0000027f,0x00050081,0x00000088,0x00000281,0x00000277,0x00000280,0x0005008e,
+	0x00000088,0x00000282,0x00000281,0x000000ff,0x0003003e,0x00000276,0x00000282,0x0004003d,
+	0x00000088,0x00000284,0x00000259,0x0007004f,0x00000237,0x00000285,0x00000284,0x00000284,
+	0x00000000,0x00000001,0x0004003d,0x00000088,0x00000286,0x00000276,0x0007004f,0x00000237,
+	0x00000287,0x00000286,0x00000286,0x00000000,0x00000001,0x00050051,0x00000087,0x00000288,
+	0x00000285,0x00000000,0x00050051,0x00000087,0x00000289,0x00000285,0x00000001,0x00050051,
+	0x00000087,0x0000028a,0x00000287,0x00000000,0x00050051,0x00000087,0x0000028b,0x00000287,
+	0x00000001,0x00070050,0x00000088,0x0000028c,0x00000288,0x00000289,0x0000028a,0x0000028b,
+	0x0003003e,0x00000283,0x0000028c,0x0004003d,0x00000088,0x0000028e,0x00000259,0x0007004f,
+	0x00000237,0x0000028f,0x0000028e,0x0000028e,0x00000002,0x00000003,0x0004003d,0x00000088,
+	0x00000290,0x00000276,0x0007004f,0x00000237,0x00000291,0x00000290,0x00000290,0x00000002,
+	0x00000003,0x00050051,0x00000087,0x00000292,0x0000028f,0x00000000,0x00050051,0x00000087,
+	0x00000293,0x0000028f,0x00000001,0x00050051,0x00000087,0x00000294,0x00000291,0x00000000,
+	0x00050051,0x00000087,0x00000295,0x00000291,0x00000001,0x00070050,0x00000088,0x00000296,
+	0x00000292,0x00000293,0x00000294,0x00000295,0x0003003e,0x0000028d,0x00000296,0x0004003d,
+	0x00000088,0x00000298,0x00000283,0x0004003d,0x00000088,0x00000299,0x00000240,0x0005008e,
+	0x00000088,0x0000029a,0x00000299,0x00000119,0x00050081,0x00000088,0x0000029b,0x00000298,
+	0x0000029a,0x00070050,0x00000088,0x0000029c,0x0000011c,0x0000011c,0x0000011c,0x0000011c,
+	0x00050083,0x00000088,0x0000029d,0x0000029b,0x0000029c,0x0003003e,0x00000297,0x0000029d,
+	0x0004003d,0x00000088,0x0000029f,0x0000028d,0x0004003d,0x00000088,0x000002a0,0x00000248,
+	0x0005008e,0x00000088,0x000002a1,0x000002a0,0x00000119,0x00050081,0x00000088,0x000002a2,
+	0x0000029f,0x000002a1,0x00070050,0x00000088,0x000002a3,0x0000011c,0x0000011c,0x0000011c,
+	0x0000011c,0x00050083,0x00000088,0x000002a4,0x000002a2,0x000002a3,0x0003003e,0x0000029e,
+	0x000002a4,0x0004003d,0x00000088,0x000002a5,0x00000297,0x00070050,0x00000088,0x000002a6,
+	0x00000127,0x00000127,0x00000127,0x00000127,0x00070050,0x00000088,0x000002a7,0x00000128,
+	0x00000128,0x00000128,0x00000128,0x0008000c,0x00000088,0x000002a8,0x00000001,0x0000002b,
+	0x000002a5,0x000002a6,0x000002a7,0x0003003e,0x00000297,0x000002a8,0x0004003d,0x00000088,
+	0x000002a9,0x0000029e,0x00070050,0x00000088,0x000002aa,0x00000127,0x00000127,0x00000127,
+	0x00000127,0x00070050,0x00000088,0x000002ab,0x00000128,0x00000128,0x00000128,0x00000128,
+	0x0008000c,0x00000088,0x000002ac,0x00000001,0x0000002b,0x000002a9,0x000002aa,0x000002ab,
+	0x0003003e,0x0000029e,0x000002ac,0x00050041,0x0000001a,0x000002ae,0x0000000e,0x0000001d,
+	0x0004003d,0x00000006,0x000002af,0x000002ae,0x00050041,0x0000002a,0x000002b0,0x00000027,
+	0x00000133,0x0004003d,0x00000006,0x000002b1,0x000002b0,0x00050084,0x00000006,0x000002b2,
+	0x000002af,0x000002b1,0x00050041,0x0000002a,0x000002b3,0x00000027,0x00000137,0x0004003d,
+	0x00000006,0x000002b4,0x000002b3,0x00050080,0x00000006,0x000002b5,0x000002b2,0x000002b4,
+	0x00050041,0x0000001a,0x000002b6,0x0000000e,0x00000019,0x0004003d,0x00000006,0x000002b7,
+	0x000002b6,0x00050080,0x00000006,0x000002b8,0x000002b5,0x000002b7,0x0003003e,0x000002ad,
+	0x000002b8,0x0004003d,0x00000006,0x000002bd,0x000002ad,0x0004003d,0x00000088,0x000002be,
+	0x00000297,0x0006000c,0x00000006,0x000002bf,0x00000001,0x00000037,0x000002be,0x0004003d,
+	0x00000088,0x000002c0,0x0000029e,0x0006000c,0x00000006,0x000002c1,0x00000001,0x00000037,
+	0x000002c0,0x00050050,0x00000007,0x000002c2,0x000002bf,0x000002c1,0x00060041,0x00000084,
+	0x000002c3,0x000002bc,0x00000029,0x000002bd,0x0003003e,0x000002c3,0x000002c2,0x00050041,
+	0x0000001a,0x000002c4,0x0000000e,0x0000001d,0x0004003d,0x00000006,0x000002c5,0x000002c4,
+	0x00050041,0x0000002a,0x000002c6,0x00000027,0x0000006f,0x0004003d,0x00000006,0x000002c7,
+	0x000002c6,0x00050086,0x00000006,0x000002c8,0x000002c7,0x00000035,0x00050082,0x00000006,
+	0x000002c9,0x000002c8,0x0000001d,0x000500ae,0x000000e8,0x000002ca,0x000002c5,0x000002c9,
+	0x000300f7,0x000002cd,0x00000000,0x000400fa,0x000002ca,0x000002cc,0x000002cf,0x000200f8,
+	0x000002cc,0x0004003d,0x00000006,0x000002ce,0x0000020f,0x0003003e,0x000002cb,0x000002ce,
+	0x000200f9,0x000002cd,0x000200f8,0x000002cf,0x0004003d,0x00000006,0x000002d0,0x0000020f,
+	0x00050041,0x0000002a,0x000002d1,0x00000027,0x00000029,0x0004003d,0x00000006,0x000002d2,
+	0x000002d1,0x00050080,0x00000006,0x000002d3,0x000002d0,0x000002d2,0x0003003e,0x000002cb,
+	0x000002d3,0x000200f9,0x000002cd,0x000200f8,0x000002cd,0x0004003d,0x00000006,0x000002d4,
+	0x000002cb,0x0003003e,0x0000020f,0x000002d4,0x0004003d,0x00000006,0x000002d5,0x0000020f,
+	0x00060041,0x00000084,0x000002d6,0x0000021c,0x00000029,0x000002d5,0x0004003d,0x00000007,
+	0x000002d7,0x000002d6,0x0003003e,0x00000218,0x000002d7,0x00050041,0x0000001a,0x000002d8,
+	0x00000218,0x00000019,0x0004003d,0x00000006,0x000002d9,0x000002d8,0x0006000c,0x00000088,
+	0x000002da,0x00000001,0x00000040,0x000002d9,0x0003003e,0x00000220,0x000002da,0x00050041,
+	0x0000001a,0x000002db,0x00000218,0x0000001d,0x0004003d,0x00000006,0x000002dc,0x000002db,
+	0x0006000c,0x00000088,0x000002dd,0x00000001,0x00000040,0x000002dc,0x0003003e,0x00000224,
+	0x000002dd,0x0004003d,0x00000006,0x000002de,0x0000020f,0x00060041,0x00000084,0x000002df,
+	0x0000022b,0x00000029,0x000002de,0x0004003d,0x00000007,0x000002e0,0x000002df,0x0003003e,
+	0x00000218,0x000002e0,0x00050041,0x0000001a,0x000002e1,0x00000218,0x00000019,0x0004003d,
+	0x00000006,0x000002e2,0x000002e1,0x0006000c,0x00000088,0x000002e3,0x00000001,0x00000040,
+	0x000002e2,0x0003003e,0x0000022f,0x000002e3,0x00050041,0x0000001a,0x000002e4,0x00000218,
+	0x0000001d,0x0004003d,0x00000006,0x000002e5,0x000002e4,0x0006000c,0x00000088,0x000002e6,
+	0x00000001,0x00000040,0x000002e5,0x0003003e,0x00000233,0x000002e6,0x0004003d,0x00000088,
+	0x000002e7,0x00000220,0x0004003d,0x00000088,0x000002e8,0x0000022f,0x00050083,0x00000088,
+	0x000002e9,0x000002e7,0x000002e8,0x0004003d,0x00000088,0x000002ea,0x00000207,0x00050085,
+	0x00000088,0x000002eb,0x000002e9,0x000002ea,0x0004003d,0x00000088,0x000002ec,0x0000022f,
+	0x00050081,0x00000088,0x000002ed,0x000002eb,0x000002ec,0x0003003e,0x00000240,0x000002ed,
+	0x0004003d,0x00000088,0x000002ee,0x00000224,0x0004003d,0x00000088,0x000002ef,0x00000233,
+	0x00050083,0x00000088,0x000002f0,0x000002ee,0x000002ef,0x0004003d,0x00000088,0x000002f1,
+	0x0000020b,0x00050085,0x00000088,0x000002f2,0x000002f0,0x000002f1,0x0004003d,0x00000088,
+	0x000002f3,0x00000233,0x00050081,0x00000088,0x000002f4,0x000002f2,0x000002f3,0x0003003e,
+	0x00000248,0x000002f4,0x00050041,0x0000001a,0x000002f5,0x0000000f,0x0000001d,0x0004003d,
+	0x00000006,0x000002f6,0x000002f5,0x00050041,0x0000002a,0x000002f7,0x00000027,0x00000077,
+	0x0004003d,0x00000006,0x000002f8,0x000002f7,0x00050086,0x00000006,0x000002f9,0x000002f8,
+	0x00000035,0x00050082,0x00000006,0x000002fa,0x000002f9,0x0000001d,0x000500ae,0x000000e8,
+	0x000002fb,0x000002f6,0x000002fa,0x000300f7,0x000002fe,0x00000000,0x000400fa,0x000002fb,
+	0x000002fd,0x00000300,0x000200f8,0x000002fd,0x0004003d,0x00000006,0x000002ff,0x00000250,
+	0x0003003e,0x000002fc,0x000002ff,0x000200f9,0x000002fe,0x000200f8,0x00000300,0x0004003d,
+	0x00000006,0x00000301,0x00000250,0x00050041,0x0000002a,0x00000302,0x00000027,0x0000003a,
+	0x0004003d,0x00000006,0x00000303,0x00000302,0x00050080,0x00000006,0x00000304,0x00000301,
+	0x00000303,0x0003003e,0x000002fc,0x00000304,0x000200f9,0x000002fe,0x000200f8,0x000002fe,
+	0x0004003d,0x00000006,0x00000305,0x000002fc,0x0003003e,0x00000250,0x00000305,0x0004003d,
+	0x00000006,0x00000306,0x00000250,0x00060041,0x000000d9,0x00000307,0x0000025d,0x00000029,
+	0x00000306,0x0004003d,0x00000006,0x00000308,0x00000307,0x0006000c,0x00000088,0x00000309,
+	0x00000001,0x00000040,0x00000308,0x0003003e,0x00000259,0x00000309,0x0004003d,0x00000006,
+	0x0000030a,0x00000250,0x00050080,0x00000006,0x0000030b,0x0000030a,0x0000001d,0x00060041,
+	0x000000d9,0x0000030c,0x0000025d,0x00000029,0x0000030b,0x0004003d,0x00000006,0x0000030d,
+	0x0000030c,0x0006000c,0x00000088,0x0000030e,0x00000001,0x00000040,0x0000030d,0x0003003e,
+	0x00000262,0x0000030e,0x00050041,0x0000001a,0x0000030f,0x0000000f,0x00000019,0x0004003d,
+	0x00000006,0x00000310,0x0000030f,0x00050041,0x0000002a,0x00000311,0x00000027,0x0000003a,
+	0x0004003d,0x00000006,0x00000312,0x00000311,0x00050082,0x00000006,0x00000313,0x00000312,
+	0x0000001d,0x000500aa,0x000000e8,0x00000314,0x00000310,0x00000313,0x000300f7,0x00000317,
+	0x00000000,0x000400fa,0x00000314,0x00000316,0x0000031a,0x000200f8,0x00000316,0x0004003d,
+	0x00000088,0x00000318,0x00000259,0x0009004f,0x00000088,0x00000319,0x00000318,0x00000318,
+	0x00000002,0x00000003,0x00000002,0x00000003,0x0003003e,0x00000315,0x00000319,0x000200f9,
+	0x00000317,0x000200f8,0x0000031a,0x0004003d,0x00000088,0x0000031b,0x00000262,0x0003003e,
+	0x00000315,0x0000031b,0x000200f9,0x00000317,0x000200f8,0x00000317,0x0004003d,0x00000088,
+	0x0000031c,0x00000315,0x0003003e,0x00000262,0x0000031c,0x0004003d,0x00000088,0x0000031d,
+	0x00000259,0x0004003d,0x00000088,0x0000031e,0x00000259,0x0007004f,0x00000237,0x0000031f,
+	0x0000031e,0x0000031e,0x00000002,0x00000003,0x0004003d,0x00000088,0x00000320,0x00000262,
+	0x0007004f,0x00000237,0x00000321,0x00000320,0x00000320,0x00000000,0x00000001,0x00050051,
+	0x00000087,0x00000322,0x0000031f,0x00000000,0x00050051,0x00000087,0x00000323,0x0000031f,
+	0x00000001,0x00050051,0x00000087,0x00000324,0x00000321,0x00000000,0x00050051,0x00000087,
+	0x00000325,0x00000321,0x00000001,0x00070050,0x00000088,0x00000326,0x00000322,0x00000323,
+	0x00000324,0x00000325,0x00050081,0x00000088,0x00000327,0x0000031d,0x00000326,0x0005008e,
+	0x00000088,0x00000328,0x00000327,0x000000ff,0x0003003e,0x00000276,0x00000328,0x0004003d,
+	0x00000088,0x0000032a,0x00000259,0x0007004f,0x00000237,0x0000032b,0x0000032a,0x0000032a,
+	0x00000000,0x00000001,0x0004003d,0x00000088,0x0000032c,0x00000276,0x0007004f,0x00000237,
+	0x0000032d,0x0000032c,0x0000032c,0x00000000,0x00000001,0x00050051,0x00000087,0x0000032e,
+	0x0000032b,0x00000000,0x00050051,0x00000087,0x0000032f,0x0000032b,0x00000001,0x00050051,
+	0x00000087,0x00000330,0x0000032d,0x00000000,0x00050051,0x00000087,0x00000331,0x0000032d,
+	0x00000001,0x00070050,0x00000088,0x00000332,0x0000032e,0x0000032f,0x00000330,0x00000331,
+	0x0003003e,0x00000329,0x00000332,0x0004003d,0x00000088,0x00000334,0x00000259,0x0007004f,
+	0x00000237,0x00000335,0x00000334,0x00000334,0x00000002,0x00000003,0x0004003d,0x00000088,
+	0x00000336,0x00000276,0x0007004f,0x00000237,0x00000337,0x00000336,0x00000336,0x00000002,
+	0x00000003,0x00050051,0x00000087,0x00000338,0x00000335,0x00000000,0x00050051,0x00000087,
+	0x00000339,0x00000335,0x00000001,0x00050051,0x00000087,0x0000033a,0x00000337,0x00000000,
+	0x00050051,0x00000087,0x0000033b,0x00000337,0x00000001,0x00070050,0x00000088,0x0000033c,
+	0x00000338,0x00000339,0x0000033a,0x0000033b,0x0003003e,0x00000333,0x0000033c,0x0004003d,
+	0x00000088,0x0000033d,0x00000283,0x0004003d,0x00000088,0x0000033e,0x00000329,0x00050081,
+	0x00000088,0x0000033f,0x0000033d,0x0000033e,0x0005008e,0x00000088,0x00000340,0x0000033f,
+	0x000000ff,0x0003003e,0x00000329,0x00000340,0x0004003d,0x00000088,0x00000341,0x0000028d,
+	0x0004003d,0x00000088,0x00000342,0x00000333,0x00050081,0x00000088,0x00000343,0x00000341,
+	0x00000342,0x0005008e,0x00000088,0x00000344,0x00000343,0x000000ff,0x0003003e,0x00000333,
+	0x00000344,0x0004003d,0x00000088,0x00000345,0x00000329,0x0004003d,0x00000088,0x00000346,
+	0x00000240,0x0005008e,0x00000088,0x00000347,0x00000346,0x00000119,0x00050081,0x00000088,
+	0x00000348,0x00000345,0x00000347,0x00070050,0x00000088,0x00000349,0x0000011c,0x0000011c,
+	0x0000011c,0x0000011c,0x00050083,0x00000088,0x0000034a,0x00000348,0x00000349,0x0003003e,
+	0x00000297,0x0000034a,0x0004003d,0x00000088,0x0000034b,0x00000333,0x0004003d,0x00000088,
+	0x0000034c,0x00000248,0x0005008e,0x00000088,0x0000034d,0x0000034c,0x00000119,0x00050081,
+	0x00000088,0x0000034e,0x0000034b,0x0000034d,0x00070050,0x00000088,0x0000034f,0x0000011c,
+	0x0000011c,0x0000011c,0x0000011c,0x00050083,0x00000088,0x00000350,0x0000034e,0x0000034f,
+	0x0003003e,0x0000029e,0x00000350,0x0004003d,0x00000088,0x00000351,0x00000297,0x00070050,
+	0x00000088,0x00000352,0x00000127,0x00000127,0x00000127,0x00000127,0x00070050,0x00000088,
+	0x00000353,0x00000128,0x00000128,0x00000128,0x00000128,0x0008000c,0x00000088,0x00000354,
+	0x00000001,0x0000002b,0x00000351,0x00000352,0x00000353,0x0003003e,0x00000297,0x00000354,
+	0x0004003d,0x00000088,0x00000355,0x0000029e,0x00070050,0x00000088,0x00000356,0x00000127,
+	0x00000127,0x00000127,0x00000127,0x00070050,0x00000088,0x00000357,0x00000128,0x00000128,
+	0x00000128,0x00000128,0x0008000c,0x00000088,0x00000358,0x00000001,0x0000002b,0x00000355,
+	0x00000356,0x00000357,0x0003003e,0x0000029e,0x00000358,0x00050041,0x0000002a,0x00000359,
+	0x00000027,0x00000133,0x0004003d,0x00000006,0x0000035a,0x00000359,0x0004003d,0x00000006,
+	0x0000035b,0x000002ad,0x00050080,0x00000006,0x0000035c,0x0000035b,0x0000035a,0x0003003e,
+	0x000002ad,0x0000035c,0x0004003d,0x00000006,0x0000035d,0x000002ad,0x0004003d,0x00000088,
+	0x0000035e,0x00000297,0x0006000c,0x00000006,0x0000035f,0x00000001,0x00000037,0x0000035e,
+	0x0004003d,0x00000088,0x00000360,0x0000029e,0x0006000c,0x00000006,0x00000361,0x00000001,
+	0x00000037,0x00000360,0x00050050,0x00000007,0x00000362,0x0000035f,0x00000361,0x00060041,
+	0x00000084,0x00000363,0x000002bc,0x00000029,0x0000035d,0x0003003e,0x00000363,0x00000362,
+	0x000100fd,0x00010038
diff --git a/tests/.gitignore b/tests/.gitignore
index 61440c7..0c8a72d 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -7,3 +7,7 @@
 test-pipe-manager
 test-video-stabilization
 test-soft-image
+test-gles-handler
+test-render-surround-view
+test-surround-view
+test-vk-handler
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6e68880..eb27a9e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,126 +1,253 @@
-XCORE_DIR = $(top_srcdir)/xcore
-MODULES_DIR = $(top_srcdir)/modules
-
-TEST_BASE_CXXFLAGS = $(XCAM_CXXFLAGS)
-if HAVE_LIBDRM
-TEST_BASE_CXXFLAGS += $(LIBDRM_CFLAGS) $(LIBDRM_LIBS)
-endif
-
-if USE_LOCAL_ATOMISP
-TEST_BASE_CXXFLAGS += -I$(top_srcdir)/ext/atomisp
-endif
-
-TEST_BASE_CXXFLAGS += \
-	-I$(XCORE_DIR)   \
-	-I$(MODULES_DIR) \
-	$(NULL)
-
-TEST_BASE_LA = \
-	$(NULL)
-
 noinst_PROGRAMS = \
-	test-device-manager  \
-	test-soft-image  \
-	$(NULL)
-
-if ENABLE_IA_AIQ
-noinst_PROGRAMS += \
-	test-poll-thread     \
-	$(NULL)
-endif
+    test-soft-image     \
+    test-surround-view  \
+    test-device-manager \
+    $(NULL)
 
 if HAVE_LIBCL
 noinst_PROGRAMS += \
-	test-cl-image        \
-	test-binary-kernel   \
-	test-pipe-manager    \
-	test-image-blend     \
-	test-image-stitching \
-	test-video-stabilization \
-	$(NULL)
+    test-cl-image            \
+    test-image-blend         \
+    test-pipe-manager        \
+    test-binary-kernel       \
+    test-image-stitching     \
+    test-video-stabilization \
+    $(NULL)
+endif
 
-TEST_BASE_LA += $(top_builddir)/modules/ocl/libxcam_ocl.la
+if HAVE_GLES
+noinst_PROGRAMS += \
+    test-gles-handler \
+    $(NULL)
+endif
+
+if HAVE_VULKAN
+noinst_PROGRAMS += \
+    test-vk-handler \
+    $(NULL)
+endif
+
+if ENABLE_RENDER
+noinst_PROGRAMS += \
+    test-render-surround-view \
+    $(NULL)
+endif
+
+if ENABLE_DNN
+noinst_PROGRAMS += \
+    test-dnn-inference \
+    $(NULL)
+endif
 
 if HAVE_OPENCV
 noinst_PROGRAMS += \
-	test-image-deblurring \
-	$(NULL)
-
-TEST_BASE_CXXFLAGS += $(OPENCV_CFLAGS)
-TEST_BASE_LA += $(OPENCV_LIBS)
-endif
+    test-image-deblurring \
+    $(NULL)
 endif
 
-TEST_BASE_LA +=  \
+TEST_BASE_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)        \
+    -I$(top_srcdir)/xcore   \
+    -I$(top_srcdir)/modules \
+    $(NULL)
+
+TEST_BASE_LA = \
     $(top_builddir)/xcore/libxcam_core.la \
-	$(NULL)
+    $(NULL)
+
+if HAVE_OPENCV
+XCAM_OCV_CFLAGS = $(OPENCV_CFLAGS)
+XCAM_OCV_LIBS = $(OPENCV_LIBS)
+XCAM_OCV_LA = $(top_builddir)/modules/ocv/libxcam_ocv.la
+endif
+
+if HAVE_LIBDRM
+TEST_DRM_CFLAGS = $(LIBDRM_CFLAGS)
+TEST_DRM_LIBS = \
+    -ldrm_intel    \
+    $(LIBDRM_LIBS) \
+    $(NULL)
+endif
 
 test_device_manager_SOURCES = test-device-manager.cpp
-test_device_manager_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_device_manager_LDADD = $(TEST_BASE_LA)
-
+test_device_manager_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(TEST_DRM_CFLAGS)    \
+    $(NULL)
+test_device_manager_LDADD = \
+    $(TEST_BASE_LA)  \
+    $(TEST_DRM_LIBS) \
+    $(NULL)
+if USE_LOCAL_ATOMISP
+test_device_manager_CXXFLAGS += -I$(top_srcdir)/ext/atomisp
+endif
 if ENABLE_IA_AIQ
-ISP_LA = $(top_builddir)/modules/isp/libxcam_isp.la
-
-test_device_manager_LDADD += $(ISP_LA)
-
-test_poll_thread_SOURCES = test-poll-thread.cpp
-test_poll_thread_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_poll_thread_LDADD = \
-	$(TEST_BASE_LA) $(ISP_LA)  \
-	$(NULL)
+test_device_manager_LDADD += $(top_builddir)/modules/isp/libxcam_isp.la
 endif
 
 if HAVE_LIBCL
+test_device_manager_LDADD += $(top_builddir)/modules/ocl/libxcam_ocl.la
+
+TEST_OCL_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(TEST_DRM_CFLAGS)    \
+    $(NULL)
+
+TEST_OCL_LDADD = \
+    $(TEST_BASE_LA)                            \
+    $(TEST_DRM_LIBS)                           \
+    $(top_builddir)/modules/ocl/libxcam_ocl.la \
+    $(NULL)
+
 test_cl_image_SOURCES = test-cl-image.cpp
-test_cl_image_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_cl_image_LDADD = \
-	$(TEST_BASE_LA)   \
-	$(NULL)
+test_cl_image_CXXFLAGS = $(TEST_OCL_CXXFLAGS)
+test_cl_image_LDADD = $(TEST_OCL_LDADD)
 
 test_binary_kernel_SOURCES = test-binary-kernel.cpp
-test_binary_kernel_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_binary_kernel_LDADD = \
-	$(TEST_BASE_LA)        \
-	$(NULL)
+test_binary_kernel_CXXFLAGS = $(TEST_OCL_CXXFLAGS)
+test_binary_kernel_LDADD = $(TEST_OCL_LDADD)
 
 test_pipe_manager_SOURCES = test-pipe-manager.cpp
-test_pipe_manager_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_pipe_manager_LDADD =      \
-	$(TEST_BASE_LA)            \
-	$(NULL)
+test_pipe_manager_CXXFLAGS = $(TEST_OCL_CXXFLAGS)
+test_pipe_manager_LDADD = $(TEST_OCL_LDADD)
 
 test_image_blend_SOURCES = test-image-blend.cpp
-test_image_blend_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_image_blend_LDADD =       \
-	$(TEST_BASE_LA)            \
-	$(NULL)
+test_image_blend_CXXFLAGS = $(TEST_OCL_CXXFLAGS)
+test_image_blend_LDADD = $(TEST_OCL_LDADD)
 
 test_image_stitching_SOURCES = test-image-stitching.cpp
-test_image_stitching_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
+test_image_stitching_CXXFLAGS = \
+    $(TEST_OCL_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)   \
+    $(NULL)
 test_image_stitching_LDADD = \
-	$(TEST_BASE_LA)          \
-	$(NULL)
+    $(TEST_OCL_LDADD) \
+    $(XCAM_OCV_LIBS)  \
+    $(XCAM_OCV_LA)    \
+    $(NULL)
 
 test_video_stabilization_SOURCES = test-video-stabilization.cpp
-test_video_stabilization_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
+test_video_stabilization_CXXFLAGS = \
+    $(TEST_OCL_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)   \
+    $(NULL)
 test_video_stabilization_LDADD = \
-	$(TEST_BASE_LA)              \
-	$(NULL)
+    $(TEST_OCL_LDADD) \
+    $(XCAM_OCV_LIBS)  \
+    $(XCAM_OCV_LA)    \
+    $(NULL)
+endif
 
 if HAVE_OPENCV
 test_image_deblurring_SOURCES = test-image-deblurring.cpp
-test_image_deblurring_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-	$(NULL)
+test_image_deblurring_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)    \
+    $(NULL)
 test_image_deblurring_LDADD = \
-	$(TEST_BASE_LA)           \
-	$(NULL)
-endif
+    $(TEST_BASE_LA)  \
+    $(XCAM_OCV_LIBS) \
+    $(XCAM_OCV_LA)   \
+    $(NULL)
 endif
 
+TEST_SOFT_LA = $(top_builddir)/modules/soft/libxcam_soft.la
+
 test_soft_image_SOURCES = test-soft-image.cpp
-test_soft_image_CXXFLAGS = $(TEST_BASE_CXXFLAGS)
-test_soft_image_LDADD =                           \
-	$(top_builddir)/modules/soft/libxcam_soft.la  \
-	$(TEST_BASE_LA)          \
-	$(NULL)
+test_soft_image_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)    \
+    $(NULL)
+test_soft_image_LDADD = \
+    $(TEST_BASE_LA)  \
+    $(XCAM_OCV_LIBS) \
+    $(XCAM_OCV_LA)   \
+    $(TEST_SOFT_LA)  \
+    $(NULL)
+
+if HAVE_GLES
+TEST_GLES_LA = $(top_builddir)/modules/gles/libxcam_gles.la
+endif
+if HAVE_VULKAN
+TEST_VK_LA = $(top_builddir)/modules/vulkan/libxcam_vulkan.la
+endif
+
+test_surround_view_SOURCES = test-surround-view.cpp
+test_surround_view_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)    \
+    $(NULL)
+test_surround_view_LDADD = \
+    $(TEST_BASE_LA)  \
+    $(XCAM_OCV_LIBS) \
+    $(XCAM_OCV_LA)   \
+    $(TEST_SOFT_LA)  \
+    $(TEST_GLES_LA)  \
+    $(TEST_VK_LA)    \
+    $(NULL)
+
+if HAVE_VULKAN
+test_vk_handler_SOURCES = test-vk-handler.cpp
+test_vk_handler_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(LIBVULKAN_CFLAGS)   \
+    $(XCAM_OCV_CFLAGS)    \
+    $(NULL)
+test_vk_handler_LDADD = \
+    $(TEST_BASE_LA)   \
+    $(LIBVULKAN_LIBS) \
+    $(XCAM_OCV_LIBS)  \
+    $(XCAM_OCV_LA)    \
+    $(TEST_VK_LA)     \
+    $(NULL)
+endif
+
+if HAVE_GLES
+test_gles_handler_SOURCES = test-gles-handler.cpp
+test_gles_handler_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)    \
+    $(NULL)
+test_gles_handler_LDADD = \
+    $(TEST_BASE_LA)  \
+    $(XCAM_OCV_LIBS) \
+    $(XCAM_OCV_LA)   \
+    $(TEST_GLES_LA)  \
+    $(NULL)
+endif
+
+if ENABLE_RENDER
+TEST_RENDER_LA = $(top_builddir)/modules/render/libxcam_render.la
+
+test_render_surround_view_SOURCES = test-render-surround-view.cpp
+test_render_surround_view_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    $(XCAM_OCV_CFLAGS)    \
+    $(NULL)
+test_render_surround_view_LDADD = \
+    $(TEST_BASE_LA)   \
+    $(XCAM_OCV_LIBS)  \
+    $(XCAM_OCV_LA)    \
+    $(TEST_SOFT_LA)   \
+    $(TEST_GLES_LA)   \
+    $(TEST_VK_LA)     \
+    $(TEST_RENDER_LA) \
+    $(NULL)
+endif
+
+if ENABLE_DNN
+TEST_DNN_INFERENCE_LA = $(top_builddir)/modules/dnn/libxcam_dnn.la
+
+test_dnn_inference_SOURCES = test-dnn-inference.cpp
+test_dnn_inference_CXXFLAGS = \
+    $(TEST_BASE_CXXFLAGS) \
+    -I$(OPENVINO_IE_INC_PATH)/include \
+    -I$(OPENVINO_IE_INC_PATH)/src/extension \
+    $(NULL)
+
+test_dnn_inference_LDADD = \
+    $(TEST_BASE_LA)   \
+    $(TEST_DNN_INFERENCE_LA) \
+    $(NULL)
+endif
+
diff --git a/tests/test-cl-image.cpp b/tests/test-cl-image.cpp
index 19000b5..a986d5d 100644
--- a/tests/test-cl-image.cpp
+++ b/tests/test-cl-image.cpp
@@ -175,7 +175,6 @@
     SmartPtr<CLImageHandler> image_handler;
     VideoBufferInfo input_buf_info;
     SmartPtr<CLContext> context;
-    SmartPtr<BufferPool> buf_pool;
     int opt = 0;
     CLCscType csc_type = CL_CSC_TYPE_RGBATONV12;
     bool enable_bnr = false;
@@ -409,6 +408,7 @@
         SmartPtr<CLNewWaveletDenoiseImageHandler> wavelet = image_handler.dynamic_cast_ptr<CLNewWaveletDenoiseImageHandler> ();
         XCAM_ASSERT (wavelet.ptr ());
         XCam3aResultWaveletNoiseReduction wavelet_config;
+        xcam_mem_clear (wavelet_config);
         wavelet_config.threshold[0] = 0.2;
         wavelet_config.threshold[1] = 0.5;
         wavelet_config.decomposition_levels = 4;
@@ -497,7 +497,8 @@
 
     input_buf_info.init (input_format, width, height);
 
-    buf_pool = new CLVideoBufferPool ();
+    SmartPtr<BufferPool> buf_pool = new CLVideoBufferPool ();
+    XCAM_ASSERT (buf_pool.ptr ());
     image_handler->set_pool_type (CLImageHandler::CLVideoPoolType);
     buf_pool->set_video_info (input_buf_info);
     if (!buf_pool->reserve (6)) {
@@ -541,14 +542,6 @@
     XCAM_LOG_INFO ("processed %d buffers successfully", buf_count);
 
     if (enable_psnr) {
-        buf_pool = new CLVideoBufferPool ();
-        XCAM_ASSERT (buf_pool.ptr ());
-        buf_pool->set_video_info (input_buf_info);
-        if (!buf_pool->reserve (6)) {
-            XCAM_LOG_ERROR ("init buffer pool failed");
-            return -1;
-        }
-
         psnr_ref = buf_pool->get_buffer (buf_pool);
         XCAM_ASSERT (psnr_ref.ptr ());
 
diff --git a/tests/test-device-manager.cpp b/tests/test-device-manager.cpp
index f299d46..1be70f5 100644
--- a/tests/test-device-manager.cpp
+++ b/tests/test-device-manager.cpp
@@ -32,7 +32,7 @@
 #include "isp/isp_image_processor.h"
 #include "isp/isp_poll_thread.h"
 #include "isp/x3a_analyzer_aiq.h"
-#include "x3a_analyze_tuner.h"
+#include "isp/iq/x3a_analyze_tuner.h"
 #include "dynamic_analyzer_loader.h"
 #include "isp/hybrid_analyzer_loader.h"
 #endif
@@ -328,8 +328,6 @@
     bool have_cl_processor = false;
     SmartPtr<SmartAnalyzer> smart_analyzer;
     bool have_cl_post_processor = true;
-    SmartPtr<CL3aImageProcessor> cl_processor;
-    SmartPtr<CLPostImageProcessor> cl_post_processor;
     uint32_t tnr_type = CL_TNR_DISABLE;
     uint32_t denoise_type = 0;
     uint8_t tnr_level = 0;
@@ -817,7 +815,7 @@
 #endif
 #if HAVE_LIBCL
     if (have_cl_processor) {
-        cl_processor = new CL3aImageProcessor ();
+        SmartPtr<CL3aImageProcessor> cl_processor = new CL3aImageProcessor ();
         cl_processor->set_stats_callback(device_manager);
         cl_processor->set_denoise (denoise_type);
         cl_processor->set_capture_stage (capture_stage);
@@ -837,7 +835,7 @@
     }
 
     if (have_cl_post_processor) {
-        cl_post_processor = new CLPostImageProcessor ();
+        SmartPtr<CLPostImageProcessor> cl_post_processor = new CLPostImageProcessor ();
 
         cl_post_processor->set_stats_callback (device_manager);
         cl_post_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode)defog_type);
diff --git a/tests/test-dnn-inference.cpp b/tests/test-dnn-inference.cpp
new file mode 100644
index 0000000..d07e27c
--- /dev/null
+++ b/tests/test-dnn-inference.cpp
@@ -0,0 +1,497 @@
+/*
+ * test-dnn-inference.cpp -  test dnn inference sample
+ *
+ *  Copyright (c) 2019 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ *
+ */
+
+#include <fstream>
+#include <random>
+#include <string>
+#include <vector>
+#include <time.h>
+
+#include <xcam_std.h>
+#include "test_common.h"
+
+#include <dnn/dnn_inference_engine.h>
+#include <dnn/dnn_object_detection.h>
+
+using namespace XCam;
+using namespace InferenceEngine;
+
+class Color {
+
+public:
+    Color (uint8_t r, uint8_t g, uint8_t b) {
+        _red = r;
+        _green = g;
+        _blue = b;
+    }
+
+public:
+    uint8_t _red;
+    uint8_t _green;
+    uint8_t _blue;
+};
+
+static void add_rectangles (
+    uint8_t *data,  uint32_t width, uint32_t height,
+    std::vector<int> rectangles, std::vector<int> classes, int thickness = 1)
+{
+    std::vector<Color> colors = {
+        // colors to be used for bounding boxes
+        Color ( 128, 64,  128 ),
+        Color ( 232, 35,  244 ),
+        Color ( 70,  70,  70 ),
+        Color ( 156, 102, 102 ),
+        Color ( 153, 153, 190 ),
+        Color ( 153, 153, 153 ),
+        Color ( 30,  170, 250 ),
+        Color ( 0,   220, 220 ),
+        Color ( 35,  142, 107 ),
+        Color ( 152, 251, 152 ),
+        Color ( 180, 130, 70 ),
+        Color ( 60,  20,  220 ),
+        Color ( 0,   0,   255 ),
+        Color ( 142, 0,   0 ),
+        Color ( 70,  0,   0 ),
+        Color ( 100, 60,  0 ),
+        Color ( 90,  0,   0 ),
+        Color ( 230, 0,   0 ),
+        Color ( 32,  11,  119 ),
+        Color ( 0,   74,  111 ),
+        Color ( 81,  0,   81 )
+    };
+    if (rectangles.size() % 4 != 0 || rectangles.size() / 4 != classes.size()) {
+        return;
+    }
+
+    for (size_t i = 0; i < classes.size(); i++) {
+        int x = rectangles.at(i * 4);
+        int y = rectangles.at(i * 4 + 1);
+        int w = rectangles.at(i * 4 + 2);
+        int h = rectangles.at(i * 4 + 3);
+
+        int cls = classes.at(i) % colors.size();  // color of a bounding box line
+
+        if (x < 0) x = 0;
+        if (y < 0) y = 0;
+        if (w < 0) w = 0;
+        if (h < 0) h = 0;
+
+        if (static_cast<std::size_t>(x) >= width) {
+            x = width - 1;
+            w = 0;
+            thickness = 1;
+        }
+        if (static_cast<std::size_t>(y) >= height) {
+            y = height - 1;
+            h = 0;
+            thickness = 1;
+        }
+
+        if (static_cast<std::size_t>(x + w) >= width) {
+            w = width - x - 1;
+        }
+        if (static_cast<std::size_t>(y + h) >= height) {
+            h = height - y - 1;
+        }
+
+        thickness = std::min(std::min(thickness, w / 2 + 1), h / 2 + 1);
+
+        size_t shift_first;
+        size_t shift_second;
+        for (int t = 0; t < thickness; t++) {
+            shift_first = (y + t) * width * 3;
+            shift_second = (y + h - t) * width * 3;
+            for (int ii = x; ii < x + w + 1; ii++) {
+                data[shift_first + ii * 3] = colors.at(cls)._red;
+                data[shift_first + ii * 3 + 1] = colors.at(cls)._green;
+                data[shift_first + ii * 3 + 2] = colors.at(cls)._blue;
+                data[shift_second + ii * 3] = colors.at(cls)._red;
+                data[shift_second + ii * 3 + 1] = colors.at(cls)._green;
+                data[shift_second + ii * 3 + 2] = colors.at(cls)._blue;
+            }
+        }
+
+        for (int t = 0; t < thickness; t++) {
+            shift_first = (x + t) * 3;
+            shift_second = (x + w - t) * 3;
+            for (int ii = y; ii < y + h + 1; ii++) {
+                data[shift_first + ii * width * 3] = colors.at(cls)._red;
+                data[shift_first + ii * width * 3 + 1] = colors.at(cls)._green;
+                data[shift_first + ii * width * 3 + 2] = colors.at(cls)._blue;
+                data[shift_second + ii * width * 3] = colors.at(cls)._red;
+                data[shift_second + ii * width * 3 + 1] = colors.at(cls)._green;
+                data[shift_second + ii * width * 3 + 2] = colors.at(cls)._blue;
+            }
+        }
+    }
+}
+
+static bool write_output_bmp (std::string name, unsigned char *data, uint32_t width, uint32_t height)
+{
+    std::ofstream out_file;
+    out_file.open (name, std::ofstream::binary);
+    if (!out_file.is_open ()) {
+        return false;
+    }
+
+    unsigned char file[14] = {
+        'B', 'M',           // magic
+        0, 0, 0, 0,         // size in bytes
+        0, 0,               // app data
+        0, 0,               // app data
+        40 + 14, 0, 0, 0      // start of data offset
+    };
+    unsigned char info[40] = {
+        40, 0, 0, 0,        // info hd size
+        0, 0, 0, 0,         // width
+        0, 0, 0, 0,         // height
+        1, 0,               // number color planes
+        24, 0,              // bits per pixel
+        0, 0, 0, 0,         // compression is none
+        0, 0, 0, 0,         // image bits size
+        0x13, 0x0B, 0, 0,   // horz resolution in pixel / m
+        0x13, 0x0B, 0, 0,   // vert resolution (0x03C3 = 96 dpi, 0x0B13 = 72 dpi)
+        0, 0, 0, 0,         // #colors in palette
+        0, 0, 0, 0,         // #important colors
+    };
+
+    if (height > (size_t)std::numeric_limits<int32_t>::max ||
+            width > (size_t)std::numeric_limits<int32_t>::max) {
+        XCAM_LOG_ERROR ("File size is too big: %dx%d", height, width);
+        return false;
+    }
+
+    int pad_size = static_cast<int>(4 - (width * 3) % 4) % 4;
+    int size_data = static_cast<int>(width * height * 3 + height * pad_size);
+    int size_all = size_data + sizeof(file) + sizeof(info);
+
+    file[2] = (unsigned char)(size_all);
+    file[3] = (unsigned char)(size_all >> 8);
+    file[4] = (unsigned char)(size_all >> 16);
+    file[5] = (unsigned char)(size_all >> 24);
+
+    info[4] = (unsigned char)(width);
+    info[5] = (unsigned char)(width >> 8);
+    info[6] = (unsigned char)(width >> 16);
+    info[7] = (unsigned char)(width >> 24);
+
+    int32_t negative_height = -(int32_t)height;
+    info[8] = (unsigned char)(negative_height);
+    info[9] = (unsigned char)(negative_height >> 8);
+    info[10] = (unsigned char)(negative_height >> 16);
+    info[11] = (unsigned char)(negative_height >> 24);
+
+    info[20] = (unsigned char)(size_data);
+    info[21] = (unsigned char)(size_data >> 8);
+    info[22] = (unsigned char)(size_data >> 16);
+    info[23] = (unsigned char)(size_data >> 24);
+
+    out_file.write(reinterpret_cast<char *>(file), sizeof(file));
+    out_file.write(reinterpret_cast<char *>(info), sizeof(info));
+
+    unsigned char pad[3] = { 0, 0, 0 };
+
+    for (size_t y = 0; y < height; y++) {
+        for (size_t x = 0; x < width; x++) {
+            unsigned char pixel[3];
+            pixel[0] = data[y * width * 3 + x * 3];
+            pixel[1] = data[y * width * 3 + x * 3 + 1];
+            pixel[2] = data[y * width * 3 + x * 3 + 2];
+
+            out_file.write(reinterpret_cast<char *>(pixel), 3);
+        }
+        out_file.write(reinterpret_cast<char *>(pad), pad_size);
+    }
+    return true;
+}
+
+static void usage (const char* arg0)
+{
+    printf ("Usage:\n"
+            "%s --plugin PATH --input filename --model-name xx.xml ...\n"
+            "\t--plugin            plugin path\n"
+            "\t--target-dev        target device, default: DnnInferDeviceCPU\n"
+            "\t--ext-path          extension path\n"
+            "\t--model-file        model file name\n"
+            "\t--input             input image \n"
+            "\t--save              save output image \n"
+            "\t--help              usage\n",
+            arg0);
+}
+
+int main (int argc, char *argv[])
+{
+    const struct option long_opts[] = {
+        {"plugin", required_argument, NULL, 'p'},
+        {"target-dev", required_argument, NULL, 'd'},
+        {"ext-path", required_argument, NULL, 'x'},
+        {"model-file", required_argument, NULL, 'm'},
+        {"input", required_argument, NULL, 'i'},
+        {"save", required_argument, NULL, 's'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0},
+    };
+
+    // --------------------------- 0. Get inference engine configurations -----------------------------------------------------------
+    XCAM_LOG_DEBUG ("0. Get inference engine configurations");
+
+    DnnInferConfig infer_config;
+    infer_config.target_id = DnnInferDeviceCPU;
+
+    char* ext_path = NULL;
+    char* input_image = NULL;
+    bool save_output = true;
+
+    int opt = -1;
+    while ((opt = getopt_long (argc, argv, "", long_opts, NULL)) != -1) {
+        switch (opt) {
+        case 'p':
+            XCAM_ASSERT (optarg);
+            infer_config.plugin_path = optarg;
+            break;
+        case 'd':
+            XCAM_ASSERT (optarg);
+            infer_config.target_id = (DnnInferTargetDeviceType)(atoi (optarg));
+            if (!strcasecmp (optarg, "CPU")) {
+                infer_config.target_id = DnnInferDeviceCPU;
+            } else if (!strcasecmp (optarg, "GPU")) {
+                infer_config.target_id = DnnInferDeviceGPU;
+            } else if (!strcasecmp (optarg, "FPGA")) {
+                infer_config.target_id = DnnInferDeviceFPGA;
+            } else if (!strcasecmp (optarg, "Myriad")) {
+                infer_config.target_id = DnnInferDeviceMyriad;
+            } else {
+                XCAM_LOG_ERROR ("target device unknown type: %s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'x':
+            XCAM_ASSERT (optarg);
+            ext_path = optarg;
+            break;
+        case 'm':
+            XCAM_ASSERT (optarg);
+            infer_config.model_filename = optarg;
+            break;
+        case 'i':
+            XCAM_ASSERT (optarg);
+            input_image = optarg;
+            break;
+        case 's':
+            XCAM_ASSERT (optarg);
+            save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+            break;
+        case 'h':
+            usage (argv[0]);
+            return 0;
+        default:
+            XCAM_LOG_ERROR ("getopt_long return unknown value: %c", opt);
+            usage (argv[0]);
+            return -1;
+        }
+    }
+
+    XCAM_LOG_DEBUG ("targetDevice: %d", infer_config.target_id );
+    if (DnnInferDeviceCPU == infer_config.target_id) {
+        infer_config.cpu_ext_path = ext_path;
+        XCAM_LOG_DEBUG ("CPU Extension loaded: %s", infer_config.cpu_ext_path);
+    } else if (DnnInferDeviceGPU == infer_config.target_id) {
+        infer_config.cldnn_ext_path = ext_path;
+        XCAM_LOG_DEBUG ("GPU Extension loaded: %s", infer_config.cldnn_ext_path);
+    }
+
+    if (optind < argc || argc < 2) {
+        XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
+        usage (argv[0]);
+        return -1;
+    }
+
+    printf ("plugin path:\t\t%s\n", (infer_config.plugin_path != NULL) ? infer_config.plugin_path : "NULL");
+    printf ("target device id:\t\t%d\n", infer_config.target_id);
+    printf ("extention path:\t\t%s\n", (ext_path != NULL) ? ext_path : "NULL");
+    printf ("input image:\t\t%s\n", (input_image != NULL) ? input_image : "NULL");
+    printf ("model file name:\t\t%s\n", (infer_config.model_filename != NULL) ? infer_config.model_filename : "NULL");
+
+    // --------------------------- 1. Set input image file names -----------------------------------------------------------
+    XCAM_LOG_DEBUG ("1. Set input image file names");
+    std::vector<std::string> images;
+    if (NULL != input_image) {
+        images.push_back (input_image);
+    }
+
+    if (images.empty()) {
+        XCAM_LOG_ERROR ("No suitable images were found!");
+        return -1;
+    }
+
+    // --------------------------- 2. create inference engine --------------------------------------------------
+    XCAM_LOG_DEBUG ("2. Create inference engine");
+    infer_config.perf_counter = 0;
+
+    SmartPtr<DnnInferenceEngine> infer_engine = new DnnObjectDetection (infer_config);
+
+    DnnInferenceEngineInfo infer_info;
+    CHECK (
+        infer_engine->get_info (infer_info, DnnInferInfoEngine),
+        "get inference engine info failed!");
+    XCAM_LOG_DEBUG ("Inference Engine version: %d.%d",  infer_info.major, infer_info.minor);
+
+    CHECK (
+        infer_engine->get_info (infer_info, DnnInferInfoPlugin),
+        "get inference engine info failed!");
+    XCAM_LOG_DEBUG ("Inference Engine plugin discription: %s",  infer_info.desc);
+    XCAM_LOG_DEBUG ("Inference Engine plugin version: %d.%d",  infer_info.major, infer_info.minor);
+
+    CHECK (
+        infer_engine->get_info (infer_info, DnnInferInfoNetwork),
+        "get inference engine info failed!");
+    XCAM_LOG_DEBUG ("Inference Engine network name: %s",  infer_info.name);
+    XCAM_LOG_DEBUG ("Inference Engine network discription: %s",  infer_info.desc);
+    XCAM_LOG_DEBUG ("Inference Engine network version: %d.%d",  infer_info.major, infer_info.minor);
+
+    // --------------------------- 3. Get model input infos --------------------------------------------------
+    XCAM_LOG_DEBUG ("3. Get/Set model input infos");
+    CHECK (
+        infer_engine->get_model_input_info (infer_config.input_infos),
+        "get model input info failed!");
+
+    XCAM_LOG_DEBUG ("Input info :");
+    for (uint32_t i = 0; i < infer_config.input_infos.numbers; i++) {
+        infer_config.input_infos.data_type[i] = DnnInferDataTypeImage;
+        CHECK (
+            infer_engine->set_input_presion (i, DnnInferPrecisionU8),
+            "set input presion failed!");
+        XCAM_LOG_DEBUG ("Idx %d : [%d X %d X %d] , [%d %d %d], batch size = %d", i,
+                        infer_config.input_infos.width[i], infer_config.input_infos.height[i], infer_config.input_infos.channels[i],
+                        infer_config.input_infos.precision[i], infer_config.input_infos.layout[i], infer_config.input_infos.data_type[i],
+                        infer_config.input_infos.batch_size);
+    }
+
+    // --------------------------- 4. Get model output infos -------------------------------------------------
+    XCAM_LOG_DEBUG ("4. Get/Set model output infos");
+    CHECK (
+        infer_engine->get_model_output_info (infer_config.output_infos),
+        "get model output info failed!");
+    XCAM_LOG_DEBUG ("Output info (numbers %d) :", infer_config.output_infos.numbers);
+
+    for (uint32_t i = 0; i < infer_config.output_infos.numbers; i++) {
+        CHECK (
+            infer_engine->set_output_presion (i, DnnInferPrecisionFP32),
+            "set output presion failed!");
+        XCAM_LOG_DEBUG ("Idx %d : [%d X %d X %d] , [%d %d %d], batch size = %d", i,
+                        infer_config.output_infos.width[i], infer_config.output_infos.height[i], infer_config.output_infos.channels[i],
+                        infer_config.output_infos.precision[i], infer_config.output_infos.layout[i], infer_config.output_infos.data_type[i],
+                        infer_config.output_infos.batch_size);
+    }
+
+    // --------------------------- 5. load inference model -------------------------------------------------
+    XCAM_LOG_DEBUG ("5. load inference model");
+    CHECK (
+        infer_engine->load_model (infer_config),
+        "load model failed!");
+
+    // --------------------------- 6. Set inference data --------------------------------------------------------
+    XCAM_LOG_DEBUG ("6. Set inference data");
+    CHECK (
+        infer_engine->set_inference_data (images),
+        "set inference data failed!");
+
+    // --------------------------- 7. Do inference ---------------------------------------------------------
+    XCAM_LOG_DEBUG ("7. Start inference iterations");
+    if (infer_engine->ready_to_start ()) {
+        CHECK (
+            infer_engine->start (),
+            "inference failed!");
+    }
+
+    FPS_CALCULATION (inference_engine, XCAM_OBJ_DUR_FRAME_NUM);
+
+    // --------------------------- 8. Process inference results -------------------------------------------------------
+    XCAM_LOG_DEBUG ("Processing inference results");
+
+    size_t batch_size = infer_engine->get_output_size ();
+    if (batch_size != images.size ()) {
+        XCAM_LOG_DEBUG ( "Number of images: %d ", images.size ());
+        batch_size = std::min(batch_size, images.size ());
+        XCAM_LOG_DEBUG ( "Number of images to be processed is: %d ", batch_size);
+    }
+
+    uint32_t blob_size = 0;
+    float* result_ptr = NULL;
+    std::vector<std::vector<int> > boxes(batch_size);
+    std::vector<std::vector<int> > classes(batch_size);
+
+    for (uint32_t batch_idx = 0; batch_idx < batch_size; batch_idx ++) {
+        result_ptr = (float*)infer_engine->get_inference_results (batch_idx, blob_size);
+        if (NULL == result_ptr) {
+            continue;
+        }
+
+        int image_width = infer_engine->get_input_image_width ();
+        int image_height = infer_engine->get_input_image_height ();
+        int max_proposal_count = infer_config.output_infos.channels[batch_idx];
+        int object_size = infer_config.output_infos.object_size[batch_idx];
+
+        for (int32_t cur_proposal = 0; cur_proposal < max_proposal_count; cur_proposal++) {
+            float image_id = result_ptr[cur_proposal * object_size + 0];
+            if (image_id < 0) {
+                break;
+            }
+
+            float label = result_ptr[cur_proposal * object_size + 1];
+            float confidence = result_ptr[cur_proposal * object_size + 2];
+            float xmin = result_ptr[cur_proposal * object_size + 3] * image_width;
+            float ymin = result_ptr[cur_proposal * object_size + 4] * image_height;
+            float xmax = result_ptr[cur_proposal * object_size + 5] * image_width;
+            float ymax = result_ptr[cur_proposal * object_size + 6] * image_height;
+
+            if (confidence > 0.5) {
+                classes[image_id].push_back(static_cast<int>(label));
+                boxes[image_id].push_back(static_cast<int>(xmin));
+                boxes[image_id].push_back(static_cast<int>(ymin));
+                boxes[image_id].push_back(static_cast<int>(xmax - xmin));
+                boxes[image_id].push_back(static_cast<int>(ymax - ymin));
+
+                XCAM_LOG_DEBUG ("Proposal:%d label:%d confidence:%f", cur_proposal, (int)label, confidence);
+                XCAM_LOG_DEBUG ("Boxes[%f] {%d, %d, %d, %d}",
+                                image_id, (int)xmin, (int)ymin, (int)xmax, (int)ymax);
+            }
+        }
+
+        if (save_output) {
+            std::shared_ptr<unsigned char> orig_image = infer_engine->read_inference_image (images[batch_idx]);
+            add_rectangles (orig_image.get (),
+                            image_width, image_height,
+                            boxes[batch_idx], classes[batch_idx]);
+
+            const std::string image_path = images[batch_idx] + "_out_" + std::to_string (batch_idx) + ".bmp";
+            if (write_output_bmp (image_path, orig_image.get (), image_width, image_height)) {
+                XCAM_LOG_DEBUG ("Image %s created!", image_path.c_str ());
+            } else {
+                XCAM_LOG_ERROR ("Can't create image file: %s", image_path.c_str ());
+            }
+        }
+    }
+
+    XCAM_LOG_DEBUG ("Execution successful");
+    return 0;
+}
diff --git a/tests/test-gles-handler.cpp b/tests/test-gles-handler.cpp
new file mode 100644
index 0000000..acafa00
--- /dev/null
+++ b/tests/test-gles-handler.cpp
@@ -0,0 +1,313 @@
+/*
+ * test-gles-handler.cpp - test gles handler
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "test_common.h"
+#include "test_stream.h"
+
+#include <gles/gl_video_buffer.h>
+#include <gles/egl/egl_base.h>
+#include <gles/gl_copy_handler.h>
+#include <gles/gl_geomap_handler.h>
+#include <interface/blender.h>
+
+using namespace XCam;
+
+enum GLType {
+    GLTypeNone    = 0,
+    GLTypeCopy,
+    GLTypeRemap,
+    GLTypeBlender
+};
+
+class GLStream
+    : public Stream
+{
+public:
+    explicit GLStream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+    virtual ~GLStream () {}
+
+    virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
+};
+
+typedef std::vector<SmartPtr<GLStream>> GLStreams;
+
+GLStream::GLStream (const char *file_name, uint32_t width, uint32_t height)
+    : Stream (file_name, width, height)
+{
+}
+
+XCamReturn
+GLStream::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
+{
+    SmartPtr<GLVideoBufferPool> pool = new GLVideoBufferPool (info);
+    XCAM_ASSERT (pool.ptr ());
+
+    if (!pool->reserve (count)) {
+        XCAM_LOG_ERROR ("create buffer pool failed");
+        return XCAM_RETURN_ERROR_MEM;
+    }
+
+    set_buf_pool (pool);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static void
+calc_hor_flip_table (uint32_t width, uint32_t height, PointFloat2 *&map_table)
+{
+    XCAM_ASSERT (map_table);
+
+    float lut_size[2] = {8, 8};
+    for (uint32_t i = 0; i < height; ++i) {
+        PointFloat2 *line = &map_table[i * width];
+        for (uint32_t j = 0; j < width; j++) {
+            line[j].x = (width - j) * lut_size[0];
+            line[j].y = i * lut_size[1];
+        }
+    }
+}
+
+static void usage (const char *arg0)
+{
+    printf ("Usage:\n"
+            "%s --type TYPE --input0 input.nv12 --input1 input1.nv12 --output output.nv12 ...\n"
+            "\t--type              processing type, selected from: copy, remap, blend\n"
+            "\t--input0            input image(NV12)\n"
+            "\t--input1            input image(NV12)\n"
+            "\t--output            output image(NV12/MP4)\n"
+            "\t--in-w              optional, input width, default: 1280\n"
+            "\t--in-h              optional, input height, default: 800\n"
+            "\t--out-w             optional, output width, default: 1280\n"
+            "\t--out-h             optional, output height, default: 800\n"
+            "\t--save              optional, save file or not, select from [true/false], default: true\n"
+            "\t--loop              optional, how many loops need to run, default: 1\n"
+            "\t--help              usage\n",
+            arg0);
+}
+
+int main (int argc, char **argv)
+{
+    uint32_t input_width = 1280;
+    uint32_t input_height = 800;
+    uint32_t output_width = 1280;
+    uint32_t output_height = 800;
+
+    GLStreams ins;
+    GLStreams outs;
+    GLType type = GLTypeNone;
+
+    int loop = 1;
+    bool save_output = true;
+
+    const struct option long_opts[] = {
+        {"type", required_argument, NULL, 't'},
+        {"input0", required_argument, NULL, 'i'},
+        {"input1", required_argument, NULL, 'j'},
+        {"output", required_argument, NULL, 'o'},
+        {"in-w", required_argument, NULL, 'w'},
+        {"in-h", required_argument, NULL, 'h'},
+        {"out-w", required_argument, NULL, 'W'},
+        {"out-h", required_argument, NULL, 'H'},
+        {"save", required_argument, NULL, 's'},
+        {"loop", required_argument, NULL, 'l'},
+        {"help", no_argument, NULL, 'e'},
+        {NULL, 0, NULL, 0},
+    };
+
+    int opt = -1;
+    while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+        switch (opt) {
+        case 't':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "copy"))
+                type = GLTypeCopy;
+            else if (!strcasecmp (optarg, "remap"))
+                type = GLTypeRemap;
+            else if (!strcasecmp (optarg, "blend"))
+                type = GLTypeBlender;
+            else {
+                XCAM_LOG_ERROR ("unknown type:%s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'i':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (GLStream, ins, optarg);
+            break;
+        case 'j':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (GLStream, ins, optarg);
+            break;
+        case 'o':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (GLStream, outs, optarg);
+            break;
+        case 'w':
+            input_width = atoi(optarg);
+            break;
+        case 'h':
+            input_height = atoi(optarg);
+            break;
+        case 'W':
+            output_width = atoi(optarg);
+            break;
+        case 'H':
+            output_height = atoi(optarg);
+            break;
+        case 's':
+            save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+            break;
+        case 'l':
+            loop = atoi(optarg);
+            break;
+        case 'e':
+            usage (argv[0]);
+            return 0;
+        default:
+            XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt);
+            usage (argv[0]);
+            return -1;
+        }
+    }
+
+    if (optind < argc || argc < 2) {
+        XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
+        usage (argv[0]);
+        return -1;
+    }
+
+    if (ins.empty () || outs.empty ()) {
+        XCAM_LOG_ERROR ("input or output stream is empty");
+        usage (argv[0]);
+        return -1;
+    }
+
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ());
+    }
+    printf ("output file:\t\t%s\n", outs[0]->get_file_name ());
+    printf ("input width:\t\t%d\n", input_width);
+    printf ("input height:\t\t%d\n", input_height);
+    printf ("output width:\t\t%d\n", output_width);
+    printf ("output height:\t\t%d\n", output_height);
+    printf ("save output:\t\t%s\n", save_output ? "true" : "false");
+    printf ("loop count:\t\t%d\n", loop);
+
+    SmartPtr<EGLBase> egl = new EGLBase ();
+    XCAM_FAIL_RETURN (ERROR, egl->init (), -1, "init EGL failed");
+
+    VideoBufferInfo in_info;
+    in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        ins[i]->set_buf_size (input_width, input_height);
+        CHECK (ins[i]->create_buf_pool (in_info, XCAM_GL_RESERVED_BUF_COUNT), "create buffer pool failed");
+        CHECK (ins[i]->open_reader ("rb"), "open input file(%s) failed", ins[i]->get_file_name ());
+    }
+
+    VideoBufferInfo out_info;
+    out_info.init (V4L2_PIX_FMT_NV12, output_width, output_height);
+    outs[0]->set_buf_size (output_width, output_height);
+    if (save_output) {
+        CHECK (outs[0]->estimate_file_format (), "%s: estimate file format failed", outs[0]->get_file_name ());
+        CHECK (outs[0]->open_writer ("wb"), "open output file(%s) failed", outs[0]->get_file_name ());
+    }
+
+    switch (type) {
+    case GLTypeCopy: {
+        SmartPtr<GLCopyHandler> copyer = new GLCopyHandler ();
+        XCAM_ASSERT (copyer.ptr ());
+
+        Rect in_area = Rect (0, 0, output_width, output_height);
+        Rect out_area = in_area;
+        copyer->set_copy_area (0, in_area, out_area);
+        copyer->set_out_video_info (out_info);
+
+        CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
+        for (int i = 0; i < loop; ++i) {
+            CHECK (copyer->copy (ins[0]->get_buf (), outs[0]->get_buf ()), "copy buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (gl-copy, XCAM_OBJ_DUR_FRAME_NUM);
+        }
+        break;
+    }
+    case GLTypeRemap: {
+        SmartPtr<GLGeoMapHandler> mapper = new GLGeoMapHandler ();
+        XCAM_ASSERT (mapper.ptr ());
+        mapper->set_output_size (output_width, output_height);
+
+        uint32_t lut_width = XCAM_ALIGN_UP (output_width, 8) / 8;
+        uint32_t lut_height = XCAM_ALIGN_UP (output_height, 8) / 8;
+        PointFloat2 *map_table = new PointFloat2[lut_width * lut_height];
+        calc_hor_flip_table (lut_width, lut_height, map_table);
+        mapper->set_lookup_table (map_table, lut_width, lut_height);
+        delete [] map_table;
+
+        CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
+        for (int i = 0; i < loop; ++i) {
+            CHECK (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), "remap buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (gl-remap, XCAM_OBJ_DUR_FRAME_NUM);
+        }
+        break;
+    }
+    case GLTypeBlender: {
+        CHECK_EXP (ins.size () == 2, "Error: blender needs 2 input files.");
+        SmartPtr<Blender> blender = Blender::create_gl_blender ();
+        XCAM_ASSERT (blender.ptr ());
+        blender->set_output_size (output_width, output_height);
+
+        Rect area;
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = output_width;
+        area.height = output_height;
+        blender->set_merge_window (area);
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = input_width;
+        area.height = input_height;
+        blender->set_input_merge_area (area, 0);
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = input_width;
+        area.height = input_height;
+        blender->set_input_merge_area (area, 1);
+
+        CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
+        CHECK (ins[1]->read_buf(), "read buffer from file(%s) failed.", ins[1]->get_file_name ());
+        for (int i = 0; i < loop; ++i) {
+            CHECK (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), "blend buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (gl-blend, XCAM_OBJ_DUR_FRAME_NUM);
+        }
+        break;
+    }
+    default: {
+        XCAM_LOG_ERROR ("unsupported type:%d", type);
+        usage (argv[0]);
+        return -1;
+    }
+    }
+
+    return 0;
+}
diff --git a/tests/test-image-blend.cpp b/tests/test-image-blend.cpp
index a00236f..c355a49 100644
--- a/tests/test-image-blend.cpp
+++ b/tests/test-image-blend.cpp
@@ -27,6 +27,7 @@
 #include <ocl/cl_blender.h>
 #include <image_file_handle.h>
 #include <ocl/cl_geo_map_handler.h>
+#include <ocl/cl_video_buffer.h>
 #if HAVE_LIBDRM
 #include <drm_display.h>
 #endif
@@ -165,7 +166,6 @@
     SmartPtr<CLBlender> blender;
     VideoBufferInfo input_buf_info0, input_buf_info1, output_buf_info;
     SmartPtr<CLContext> context;
-    SmartPtr<BufferPool> buf_pool0, buf_pool1;
     ImageFileHandle file_in0, file_in1, file_out;
     SmartPtr<VideoBuffer> input0, input1;
     SmartPtr<VideoBuffer> output_buf;
@@ -227,7 +227,7 @@
             break;
         case 'h':
             usage (argv[0]);
-            return -1;
+            return 0;
         default:
             printf ("getopt_long return unknown value:%c\n", opt);
             usage (argv[0]);
@@ -259,13 +259,14 @@
     input_buf_info0.init (input_format, input_width0, input_height);
     input_buf_info1.init (input_format, input_width1, input_height);
     output_buf_info.init (input_format, output_width, output_height);
+
 #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM)
     SmartPtr<DrmDisplay> display = DrmDisplay::instance ();
-    buf_pool0 = new DrmBoBufferPool (display);
-    buf_pool1 = new DrmBoBufferPool (display);
+    SmartPtr<BufferPool> buf_pool0 = new DrmBoBufferPool (display);
+    SmartPtr<BufferPool> buf_pool1 = new DrmBoBufferPool (display);
 #else
-    buf_pool0 = new CLVideoBufferPool ();
-    buf_pool1 = new CLVideoBufferPool ();
+    SmartPtr<BufferPool> buf_pool0 = new CLVideoBufferPool ();
+    SmartPtr<BufferPool> buf_pool1 = new CLVideoBufferPool ();
 #endif
     XCAM_ASSERT (buf_pool0.ptr () && buf_pool1.ptr ());
     buf_pool0->set_video_info (input_buf_info0);
diff --git a/tests/test-image-deblurring.cpp b/tests/test-image-deblurring.cpp
index bc681b2..bfc9d88 100644
--- a/tests/test-image-deblurring.cpp
+++ b/tests/test-image-deblurring.cpp
@@ -25,9 +25,9 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <image_file_handle.h>
-#include <ocl/cv_image_sharp.h>
-#include <ocl/cv_wiener_filter.h>
-#include <ocl/cv_image_deblurring.h>
+#include "ocv/cv_image_sharp.h"
+#include "ocv/cv_wiener_filter.h"
+#include "ocv/cv_image_deblurring.h"
 
 #include <opencv2/opencv.hpp>
 #include <opencv2/core/ocl.hpp>
@@ -58,7 +58,7 @@
 non_blind_deblurring (cv::Mat &input_image, cv::Mat &output_image)
 {
     SmartPtr<CVWienerFilter> wiener_filter = new CVWienerFilter ();
-    cv::cvtColor (input_image, input_image, CV_BGR2GRAY);
+    cv::cvtColor (input_image, input_image, cv::COLOR_BGR2GRAY);
     // use simple motion blur kernel
     int kernel_size = 13;
     cv::Mat kernel = cv::Mat::zeros (kernel_size, kernel_size, CV_32FC1);
@@ -115,7 +115,7 @@
             break;
         case 'H':
             usage (argv[0]);
-            return -1;
+            return 0;
         default:
             printf ("getopt_long return unknown value:%c\n", opt);
             usage (argv[0]);
@@ -144,12 +144,12 @@
     printf ("----------------------\n");
 
     SmartPtr<CVImageSharp> sharp = new CVImageSharp ();
-    cv::Mat input_image = cv::imread (file_in_name, CV_LOAD_IMAGE_COLOR);
+    cv::Mat input_image = cv::imread (file_in_name, cv::IMREAD_COLOR);
     cv::Mat output_image;
     if (input_image.empty ())
     {
         XCAM_LOG_ERROR ("input file read error");
-        return 0;
+        return -1;
     }
     if (blind)
     {
@@ -166,5 +166,7 @@
         cv::imwrite (file_out_name, output_image);
     }
     XCAM_ASSERT (output_sharp > input_sharp);
+
+    return 0;
 }
 
diff --git a/tests/test-image-stitching.cpp b/tests/test-image-stitching.cpp
index ddd765f..0062f90 100644
--- a/tests/test-image-stitching.cpp
+++ b/tests/test-image-stitching.cpp
@@ -31,12 +31,16 @@
 #include <ocl/cl_image_360_stitch.h>
 #include <ocl/cl_utils.h>
 #if HAVE_OPENCV
-#include <ocl/cv_base_class.h>
+#include "ocv/cv_utils.h"
 #endif
 
 #define XCAM_TEST_STITCH_DEBUG 0
 #define XCAM_ALIGNED_WIDTH 16
 
+#if HAVE_OPENCV
+#define FOURCC_X264 cv::VideoWriter::fourcc ('X', '2', '6', '4')
+#endif
+
 #define CHECK_ACCESS(fliename) \
     if (access (fliename, F_OK) != 0) {            \
         XCAM_LOG_ERROR ("%s not found", fliename); \
@@ -59,31 +63,28 @@
     ExtrinsicParameter extrinsic_param[],
     int fisheye_num)
 {
+    static const char *instrinsic_names[] = {
+        "intrinsic_camera_front.txt", "intrinsic_camera_right.txt",
+        "intrinsic_camera_rear.txt", "intrinsic_camera_left.txt"
+    };
+    static const char *exstrinsic_names[] = {
+        "extrinsic_camera_front.txt", "extrinsic_camera_right.txt",
+        "extrinsic_camera_rear.txt", "extrinsic_camera_left.txt"
+    };
+
+    std::string fisheye_config_path = FISHEYE_CONFIG_PATH;
+    const char *env = std::getenv (FISHEYE_CONFIG_ENV_VAR);
+    if (env)
+        fisheye_config_path.assign (env, strlen (env));
+    XCAM_LOG_INFO ("calibration config path:%s", fisheye_config_path.c_str ());
+
     CalibrationParser calib_parser;
+    XCAM_ASSERT (fisheye_num <= 4);
 
     char intrinsic_path[1024], extrinsic_path[1024];
     for(int index = 0; index < fisheye_num; index++) {
-        switch (index) {
-        case 0:
-            strncpy (intrinsic_path, "./calib_params/intrinsic_camera_front.txt", 1023);
-            strncpy (extrinsic_path, "./calib_params/extrinsic_camera_front.txt", 1023);
-            break;
-        case 1:
-            strncpy (intrinsic_path, "./calib_params/intrinsic_camera_right.txt", 1023);
-            strncpy (extrinsic_path, "./calib_params/extrinsic_camera_right.txt", 1023);
-            break;
-        case 2:
-            strncpy (intrinsic_path, "./calib_params/intrinsic_camera_rear.txt", 1023);
-            strncpy (extrinsic_path, "./calib_params/extrinsic_camera_rear.txt", 1023);
-            break;
-        case 3:
-            strncpy (intrinsic_path, "./calib_params/intrinsic_camera_left.txt", 1023);
-            strncpy (extrinsic_path, "./calib_params/extrinsic_camera_left.txt", 1023);
-            break;
-        default:
-            XCAM_LOG_ERROR ("bowl view only support 4-camera mode");
-            return false;
-        }
+        snprintf (intrinsic_path, 1023, "%s/%s", fisheye_config_path.c_str (), instrinsic_names[index]);
+        snprintf (extrinsic_path, 1023, "%s/%s", fisheye_config_path.c_str (), exstrinsic_names[index]);
 
         CHECK_ACCESS (intrinsic_path);
         CHECK_ACCESS (extrinsic_path);
@@ -148,11 +149,13 @@
             "\t--enable-fisheyemap optional, enable fisheye map, default: no\n"
             "\t--enable-lsc        optional, enable lens shading correction, default: no\n"
 #if HAVE_OPENCV
-            "\t--fm-ocl            optional, enable ocl for feature match, select from [true/false], default: false\n"
+            "\t--fm                optional, enable or disable feature match, default: true\n"
 #endif
             "\t--fisheye-num       optional, the number of fisheye lens, default: 2\n"
             "\t--all-in-one        optional, all fisheye in one image, select from [true/false], default: true\n"
             "\t--save              optional, save file or not, select from [true/false], default: true\n"
+            "\t--save-top-view     optional, save top view videos. default: no\n"
+            "\t--save-free-view    optional, save rectified(free) view videos. default: no\n"
             "\t--framerate         optional, framerate of saved video, default: 30.0\n"
             "\t--loop              optional, how many loops need to run for performance test, default: 1\n"
             "\t--help              usage\n",
@@ -186,19 +189,21 @@
     bool enable_seam = false;
     bool enable_fisheye_map = false;
     bool enable_lsc = false;
+#if HAVE_OPENCV
+    bool need_fm = true;
+#endif
     CLBlenderScaleMode scale_mode = CLBlenderScaleLocal;
     StitchResMode res_mode = StitchRes1080P;
-    SurroundMode surround_mode = BowlView;
+    SurroundMode surround_mode = SphereView;
 
     IntrinsicParameter intrinsic_param[XCAM_STITCH_FISHEYE_MAX_NUM];
     ExtrinsicParameter extrinsic_param[XCAM_STITCH_FISHEYE_MAX_NUM];
 
-#if HAVE_OPENCV
-    bool fm_ocl = false;
-#endif
     int fisheye_num = 2;
     bool all_in_one = true;
     bool need_save_output = true;
+    bool save_top_view = false;
+    bool save_free_view = false;
     double framerate = 30.0;
 
     const char *file_in_name[XCAM_STITCH_FISHEYE_MAX_NUM] = {NULL};
@@ -222,11 +227,13 @@
         {"enable-fisheyemap", no_argument, NULL, 'F'},
         {"enable-lsc", no_argument, NULL, 'L'},
 #if HAVE_OPENCV
-        {"fm-ocl", required_argument, NULL, 'O'},
+        {"fm", required_argument, NULL, 'm'},
 #endif
         {"fisheye-num", required_argument, NULL, 'N'},
         {"all-in-one", required_argument, NULL, 'A'},
         {"save", required_argument, NULL, 's'},
+        {"save-top-view", no_argument, NULL, 't'},
+        {"save-free-view", no_argument, NULL, 'v'},
         {"framerate", required_argument, NULL, 'f'},
         {"loop", required_argument, NULL, 'l'},
         {"help", no_argument, NULL, 'e'},
@@ -299,8 +306,8 @@
             enable_lsc = true;
             break;
 #if HAVE_OPENCV
-        case 'O':
-            fm_ocl = (strcasecmp (optarg, "true") == 0 ? true : false);
+        case 'm':
+            need_fm = (strcasecmp (optarg, "false") == 0 ? false : true);
             break;
 #endif
         case 'N':
@@ -316,6 +323,12 @@
         case 's':
             need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
             break;
+        case 't':
+            save_top_view = true;
+            break;
+        case 'v':
+            save_free_view = true;
+            break;
         case 'f':
             framerate = atof(optarg);
             break;
@@ -324,7 +337,7 @@
             break;
         case 'e':
             usage (argv[0]);
-            return -1;
+            return 0;
         default:
             XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt);
             usage (argv[0]);
@@ -351,8 +364,8 @@
         }
     }
 
-    if (!file_out_name) {
-        XCAM_LOG_ERROR ("output path is NULL");
+    if (!file_out_name && need_save_output) {
+        XCAM_LOG_ERROR ("output path is NULL, video can't be saved");
         return -1;
     }
 
@@ -365,7 +378,7 @@
 
 #if !HAVE_OPENCV
     if (need_save_output) {
-        XCAM_LOG_WARNING ("non-OpenCV mode, can't save video");
+        XCAM_LOG_WARNING ("non-OpenCV mode, can't save video to file:%s", XCAM_STR (file_out_name));
         need_save_output = false;
     }
 #endif
@@ -377,7 +390,7 @@
         for (int i = 0; i < input_count; i++)
             printf ("input file %d:\t\t%s\n", i, file_in_name[i]);
     }
-    printf ("output file:\t\t%s\n", file_out_name);
+    printf ("output file:\t\t%s\n", XCAM_STR (file_out_name));
     printf ("input width:\t\t%d\n", input_width);
     printf ("input height:\t\t%d\n", input_height);
     printf ("output width:\t\t%d\n", output_width);
@@ -391,11 +404,13 @@
     printf ("fisheye map:\t\t%s\n", enable_fisheye_map ? "true" : "false");
     printf ("shading correction:\t%s\n", enable_lsc ? "true" : "false");
 #if HAVE_OPENCV
-    printf ("feature match ocl:\t%s\n", fm_ocl ? "true" : "false");
+    printf ("feature match:\t\t%s\n", need_fm ? "true" : "false");
 #endif
     printf ("fisheye number:\t\t%d\n", fisheye_num);
     printf ("all in one:\t\t%s\n", all_in_one ? "true" : "false");
     printf ("save file:\t\t%s\n", need_save_output ? "true" : "false");
+    printf ("save top-view file:\t%s\n", save_top_view ? top_view_filename : "NO");
+    printf ("save free-view file:\t%s\n", save_free_view ? rectified_view_filename : "NO");
     printf ("framerate:\t\t%.3lf\n", framerate);
     printf ("loop count:\t\t%d\n", loop);
     printf ("-----------------------------------\n");
@@ -407,13 +422,16 @@
             res_mode, fisheye_num, all_in_one).dynamic_cast_ptr<CLImage360Stitch> ();
     XCAM_ASSERT (image_360.ptr ());
     image_360->set_output_size (output_width, output_height);
-#if HAVE_OPENCV
-    image_360->set_feature_match_ocl (fm_ocl);
-#endif
     image_360->set_pool_type (CLImageHandler::CLVideoPoolType);
+#if HAVE_OPENCV
+    image_360->set_feature_match (need_fm);
+#endif
 
     if (surround_mode == BowlView) {
-        parse_calibration_params (intrinsic_param, extrinsic_param, fisheye_num);
+        if (!parse_calibration_params (intrinsic_param, extrinsic_param, fisheye_num)) {
+            XCAM_LOG_ERROR ("parse calibration data failed in surround view.");
+            return -1;
+        }
 
         for (int i = 0; i < fisheye_num; i++) {
             image_360->set_fisheye_intrinsic (intrinsic_param[i], i);
@@ -426,13 +444,15 @@
     top_view_buf_info.init (input_format, top_view_width, top_view_height);
     rectified_view_buf_info.init (input_format, rectified_view_width, rectified_view_height);
     for (int i = 0; i < input_count; i++) {
-        buf_pool[i] = new CLVideoBufferPool ();
-        XCAM_ASSERT (buf_pool[i].ptr ());
-        buf_pool[i]->set_video_info (input_buf_info);
-        if (!buf_pool[i]->reserve (6)) {
+        SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+        XCAM_ASSERT (pool.ptr ());
+        pool->set_video_info (input_buf_info);
+        if (!pool->reserve (6)) {
             XCAM_LOG_ERROR ("init buffer pool failed");
             return -1;
         }
+
+        buf_pool[i] = pool;
     }
 
     SmartPtr<BufferPool> top_view_pool = new CLVideoBufferPool ();
@@ -464,19 +484,21 @@
     cv::VideoWriter rectified_view_writer;
     if (need_save_output) {
         cv::Size dst_size = cv::Size (output_width, output_height);
-        if (!writer.open (file_out_name, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) {
+        if (!writer.open (file_out_name, FOURCC_X264, framerate, dst_size)) {
             XCAM_LOG_ERROR ("open file %s failed", file_out_name);
             return -1;
         }
-
-        dst_size = cv::Size (top_view_width, top_view_height);
-        if (!top_view_writer.open (top_view_filename, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) {
+    }
+    if (save_top_view) {
+        cv::Size dst_size = cv::Size (top_view_width, top_view_height);
+        if (!top_view_writer.open (top_view_filename, FOURCC_X264, framerate, dst_size)) {
             XCAM_LOG_ERROR ("open file %s failed", top_view_filename);
             return -1;
         }
-
-        dst_size = cv::Size (rectified_view_width, rectified_view_height);
-        if (!rectified_view_writer.open (rectified_view_filename, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) {
+    }
+    if (save_free_view) {
+        cv::Size dst_size = cv::Size (rectified_view_width, rectified_view_height);
+        if (!rectified_view_writer.open (rectified_view_filename, FOURCC_X264, framerate, dst_size)) {
             XCAM_LOG_ERROR ("open file %s failed", rectified_view_filename);
             return -1;
         }
@@ -484,13 +506,15 @@
 #endif
 
     SmartPtr<VideoBuffer> pre_buf, cur_buf;
-#if (HAVE_OPENCV) && (XCAM_TEST_STITCH_DEBUG)
+    int frame_id = 0;
+#if (HAVE_OPENCV)
+#if XCAM_TEST_STITCH_DEBUG
     SmartPtr<VideoBuffer> input_bufs[XCAM_STITCH_FISHEYE_MAX_NUM];
 #endif
-    int frame_id = 0;
     std::vector<PointFloat2> top_view_map_table;
     std::vector<PointFloat2> rectified_view_map_table;
     float rectified_start_angle = -45.0f, rectified_end_angle = 45.0f;
+#endif
 
     while (loop--) {
         for (int i = 0; i < input_count; i++) {
@@ -532,24 +556,29 @@
                 cv::Mat out_mat;
                 convert_to_mat (output_buf, out_mat);
                 writer.write (out_mat);
+            }
 
-                BowlDataConfig config = image_360->get_fisheye_bowl_config ();
+            BowlDataConfig config = image_360->get_fisheye_bowl_config ();
+            if (save_top_view) {
                 cv::Mat top_view_mat;
                 sample_generate_top_view (output_buf, top_view_buf, config, top_view_map_table);
                 convert_to_mat (top_view_buf, top_view_mat);
                 top_view_writer.write (top_view_mat);
-
+            }
+            if (save_free_view) {
                 cv::Mat rectified_view_mat;
                 sample_generate_rectified_view (output_buf, rectified_view_buf, config, rectified_start_angle,
                                                 rectified_end_angle, rectified_view_map_table);
                 convert_to_mat (rectified_view_buf, rectified_view_mat);
                 rectified_view_writer.write (rectified_view_mat);
+            }
 
 #if XCAM_TEST_STITCH_DEBUG
-                dbg_write_image (context, image_360, input_bufs, output_buf, top_view_buf, rectified_view_buf,
-                                 all_in_one, fisheye_num, input_count);
+            dbg_write_image (context, image_360, input_bufs, output_buf, top_view_buf, rectified_view_buf,
+                             all_in_one, fisheye_num, input_count);
 #endif
-            } else
+
+            if (!(need_save_output || save_top_view || save_free_view))
 #endif
                 ensure_gpu_buffer_done (output_buf);
 
diff --git a/tests/test-pipe-manager.cpp b/tests/test-pipe-manager.cpp
index 280bfdc..1389699 100644
--- a/tests/test-pipe-manager.cpp
+++ b/tests/test-pipe-manager.cpp
@@ -199,8 +199,6 @@
     VideoBufferInfo buf_info;
     SmartPtr<VideoBuffer> video_buf;
     SmartPtr<SmartAnalyzer> smart_analyzer;
-    SmartPtr<CLPostImageProcessor> cl_post_processor;
-    SmartPtr<BufferPool> buf_pool;
 
     uint32_t pixel_format = V4L2_PIX_FMT_NV12;
     uint32_t image_width = 1920;
@@ -400,7 +398,7 @@
         pipe_manager->set_smart_analyzer (smart_analyzer);
     }
 
-    cl_post_processor = new CLPostImageProcessor ();
+    SmartPtr<CLPostImageProcessor> cl_post_processor = new CLPostImageProcessor ();
     cl_post_processor->set_stats_callback (pipe_manager);
     cl_post_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) defog_mode);
     cl_post_processor->set_wavelet (wavelet_mode, wavelet_channel, wavelet_bayes_shrink);
@@ -416,7 +414,7 @@
     pipe_manager->add_image_processor (cl_post_processor);
 
     buf_info.init (pixel_format, image_width, image_height);
-    buf_pool = new CLVideoBufferPool ();
+    SmartPtr<BufferPool> buf_pool = new CLVideoBufferPool ();
     XCAM_ASSERT (buf_pool.ptr ());
     if (!buf_pool->set_video_info (buf_info) || !buf_pool->reserve (DEFAULT_FPT_BUF_COUNT)) {
         XCAM_LOG_ERROR ("init buffer pool failed");
diff --git a/tests/test-render-surround-view.cpp b/tests/test-render-surround-view.cpp
new file mode 100644
index 0000000..9142d4d
--- /dev/null
+++ b/tests/test-render-surround-view.cpp
@@ -0,0 +1,688 @@
+/*
+ * test-render-surround-view.cpp - test render surround view
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include "test_common.h"
+#include "test_stream.h"
+#include <interface/geo_mapper.h>
+#include <interface/stitcher.h>
+#include <calibration_parser.h>
+#include <soft/soft_video_buf_allocator.h>
+#if HAVE_GLES
+#include <gles/gl_video_buffer.h>
+#include <gles/egl/egl_base.h>
+#endif
+#if HAVE_VULKAN
+#include <vulkan/vk_device.h>
+#endif
+
+#include <render/render_osg_viewer.h>
+#include <render/render_osg_model.h>
+#include <render/render_osg_shader.h>
+
+using namespace XCam;
+
+#define CAR_MODEL_NAME  "Suv.osgb"
+
+enum SVModule {
+    SVModuleNone    = 0,
+    SVModuleSoft,
+    SVModuleGLES,
+    SVModuleVulkan
+};
+
+static const char *instrinsic_names[] = {
+    "intrinsic_camera_front.txt",
+    "intrinsic_camera_right.txt",
+    "intrinsic_camera_rear.txt",
+    "intrinsic_camera_left.txt"
+};
+
+static const char *exstrinsic_names[] = {
+    "extrinsic_camera_front.txt",
+    "extrinsic_camera_right.txt",
+    "extrinsic_camera_rear.txt",
+    "extrinsic_camera_left.txt"
+};
+
+static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f};
+
+static const char VtxShaderCar[] = ""
+                                   "precision highp float;                                        \n"
+                                   "uniform mat4 osg_ModelViewProjectionMatrix;                   \n"
+                                   "uniform mat4 osg_ModelViewMatrix;                             \n"
+                                   "uniform mat3 osg_NormalMatrix;                                \n"
+                                   "attribute vec3 osg_Normal;                                    \n"
+                                   "attribute vec4 osg_Color;                                     \n"
+                                   "attribute vec4 osg_Vertex;                                    \n"
+                                   "varying vec4 v_color;                                         \n"
+                                   "varying float diffuseLight;                                   \n"
+                                   "varying float specLight;                                      \n"
+                                   "attribute vec2 osg_MultiTexCoord0;                            \n"
+                                   "varying vec2 texCoord0;                                       \n"
+                                   "void main()                                                   \n"
+                                   "{                                                             \n"
+                                   "    vec4 light = vec4(0.0,100.0, 100.0, 1.0);                 \n"
+                                   "    vec4 lightColorSpec = vec4(1.0, 1.0, 1.0, 1.0);           \n"
+                                   "    vec4 lightColorDiffuse = vec4(1.0, 1.0, 1.0, 1.0);        \n"
+                                   "    vec4 lightColorAmbient = vec4(0.3, 0.3, .3, 1.0);         \n"
+                                   "    vec4 carColorAmbient = vec4(0.0, 0.0, 1.0, 1.0);          \n"
+                                   "    vec4 carColorDiffuse = vec4(0.0, 0.0, 1.0, 1.0);          \n"
+                                   "    vec4 carColorSpec = vec4(1.0, 1.0, 1.0, 1.0);             \n"
+                                   "    vec3 tnorm = normalize(osg_NormalMatrix * osg_Normal);    \n"
+                                   "    vec4 eye = osg_ModelViewMatrix * osg_Vertex;              \n"
+                                   "    vec3 s = normalize(vec3(light - eye));                    \n"
+                                   "    vec3 v = normalize(-eye.xyz);                             \n"
+                                   "    vec3 r = reflect(-s, tnorm);                              \n"
+                                   "    diffuseLight = max(0.0, dot( s, tnorm));                  \n"
+                                   "    specLight = 0.0;                                          \n"
+                                   "    if(diffuseLight > 0.0)                                    \n"
+                                   "    {                                                         \n"
+                                   "        specLight = pow(max(0.0, dot(r,v)), 10.0);            \n"
+                                   "    }                                                         \n"
+                                   "    texCoord0 = osg_MultiTexCoord0;                               \n"
+                                   "    v_color = (specLight *  lightColorSpec * carColorSpec) + (carColorDiffuse * lightColorDiffuse * diffuseLight) + lightColorAmbient * carColorAmbient;   \n"
+                                   "    gl_Position = osg_ModelViewProjectionMatrix * osg_Vertex;     \n"
+                                   "}                                                \n";
+
+static const char FrgShaderCar[] = ""
+                                   "precision highp float;                                                      \n"
+                                   "varying vec4 v_color;                                                       \n"
+                                   "varying float diffuseLight;                                                 \n"
+                                   "varying float specLight;                                                    \n"
+                                   "uniform sampler2D textureWheel;                                             \n"
+                                   "varying vec2 texCoord0;                                                     \n"
+                                   "void main()                                                                 \n"
+                                   "{                                                                           \n"
+                                   "    vec4 lightColorSpec = vec4(1.0, 1.0, 1.0, 1.0);                         \n"
+                                   "    vec4 lightColorDiffuse = vec4(1.0, 1.0, 1.0, 1.0);                      \n"
+                                   "    vec4 lightColorAmbient = vec4(0.3, 0.3, .3, 1.0);                       \n"
+                                   "    vec4 base = texture2D(textureWheel, texCoord0.st);                      \n"
+                                   "    gl_FragColor = (specLight *  lightColorSpec * base) + (base * lightColorDiffuse * diffuseLight) + lightColorAmbient * base ; \n"
+                                   "}                                                                           \n";
+
+class SVStream
+    : public Stream
+{
+public:
+    explicit SVStream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+    virtual ~SVStream () {}
+
+    void set_module (SVModule module) {
+        XCAM_ASSERT (module != SVModuleNone);
+        _module = module;
+    }
+
+#if HAVE_VULKAN
+    void set_vk_device (SmartPtr<VKDevice> &device) {
+        XCAM_ASSERT (device.ptr ());
+        _vk_dev = device;
+    }
+    SmartPtr<VKDevice> &get_vk_device () {
+        return _vk_dev;
+    }
+#endif
+
+    virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
+
+private:
+    XCAM_DEAD_COPY (SVStream);
+
+private:
+    SVModule               _module;
+#if HAVE_VULKAN
+    SmartPtr<VKDevice>     _vk_dev;
+#endif
+};
+typedef std::vector<SmartPtr<SVStream>> SVStreams;
+
+SVStream::SVStream (const char *file_name, uint32_t width, uint32_t height)
+    :  Stream (file_name, width, height)
+    , _module (SVModuleNone)
+{
+}
+
+XCamReturn
+SVStream::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _module != SVModuleNone, XCAM_RETURN_ERROR_PARAM,
+        "invalid module, please set module first");
+
+    SmartPtr<BufferPool> pool;
+    if (_module == SVModuleSoft) {
+        pool = new SoftVideoBufAllocator (info);
+    } else if (_module == SVModuleGLES) {
+#if HAVE_GLES
+        pool = new GLVideoBufferPool (info);
+#endif
+    } else if (_module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        XCAM_ASSERT (_vk_dev.ptr ());
+        pool = create_vk_buffer_pool (_vk_dev);
+        XCAM_ASSERT (pool.ptr ());
+        pool->set_video_info (info);
+#endif
+    }
+    XCAM_ASSERT (pool.ptr ());
+
+    if (!pool->reserve (count)) {
+        XCAM_LOG_ERROR ("create buffer pool failed");
+        pool.release ();
+        return XCAM_RETURN_ERROR_MEM;
+    }
+
+    set_buf_pool (pool);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static SmartPtr<Stitcher>
+create_stitcher (const SmartPtr<SVStream> &stitch, SVModule module)
+{
+    SmartPtr<Stitcher> stitcher;
+
+    if (module == SVModuleSoft) {
+        stitcher = Stitcher::create_soft_stitcher ();
+    } else if (module == SVModuleGLES) {
+#if HAVE_GLES
+        stitcher = Stitcher::create_gl_stitcher ();
+#endif
+    } else if (module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        SmartPtr<VKDevice> dev = stitch->get_vk_device ();
+        XCAM_ASSERT (dev.ptr ());
+        stitcher = Stitcher::create_vk_stitcher (dev);
+#else
+        XCAM_UNUSED (stitch);
+#endif
+    }
+    XCAM_ASSERT (stitcher.ptr ());
+
+    return stitcher;
+}
+
+static int
+parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count)
+{
+    XCAM_ASSERT (path);
+
+    char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]);
+    snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]);
+
+    CalibrationParser parser;
+    CHECK (
+        parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic),
+        "parse intrinsic params(%s) failed.", intrinsic_path);
+
+    CHECK (
+        parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic),
+        "parse extrinsic params(%s) failed.", extrinsic_path);
+    info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X;
+
+    info.angle_range = viewpoints_range[idx];
+    info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f;
+    return 0;
+}
+
+void
+get_bowl_model (
+    const SmartPtr<Stitcher> &stitcher,
+    BowlModel::VertexMap &vertices,
+    BowlModel::PointMap &points,
+    BowlModel::IndexVector &indices,
+    float &a,
+    float &b,
+    float &c,
+    float resRatio,
+    uint32_t image_width,
+    uint32_t image_height)
+{
+    uint32_t res_width = image_width * resRatio;
+    uint32_t res_height = image_height * resRatio;
+
+    BowlDataConfig bowl = stitcher->get_bowl_config();
+    bowl.angle_start = 0.0f;
+    bowl.angle_end = 360.0f;
+
+    a = bowl.a;
+    b = bowl.b;
+    c = bowl.c;
+
+    BowlModel bowl_model(bowl, image_width, image_height);
+
+    bowl_model.get_bowlview_vertex_model(
+        vertices,
+        points,
+        indices,
+        res_width,
+        res_height);
+}
+
+static SmartPtr<RenderOsgModel>
+create_surround_view_model (
+    const SmartPtr<Stitcher> &stitcher,
+    uint32_t texture_width,
+    uint32_t texture_height)
+{
+    SmartPtr<RenderOsgModel> svm_model = new RenderOsgModel ("svm model", texture_width, texture_height);
+
+    svm_model->setup_shader_program ("SVM", osg::Shader::VERTEX, VtxShaderProjectNV12Texture);
+    svm_model->setup_shader_program ("SVM", osg::Shader::FRAGMENT, FrgShaderProjectNV12Texture);
+
+    BowlModel::VertexMap vertices;
+    BowlModel::PointMap points;
+    BowlModel::IndexVector indices;
+
+    float a = 0;
+    float b = 0;
+    float c = 0;
+    float res_ratio = 0.3;
+    float scaling = 1000.0f;
+
+    get_bowl_model (stitcher, vertices, points, indices,
+                    a, b, c, res_ratio, texture_width, texture_height );
+
+    svm_model->setup_vertex_model (vertices, points, indices, a / scaling, b / scaling, c / scaling);
+
+    return svm_model;
+}
+
+static SmartPtr<RenderOsgModel>
+create_car_model (const char *name)
+{
+    std::string car_name;
+    if (NULL != name) {
+        car_name = std::string (name);
+    } else {
+        car_name = std::string (CAR_MODEL_NAME);
+    }
+    std::string car_model_path = FISHEYE_CONFIG_PATH + car_name;
+
+    const char *env_path = std::getenv (FISHEYE_CONFIG_ENV_VAR);
+    if (env_path) {
+        car_model_path.clear ();
+        car_model_path = std::string (env_path) + car_name;
+    }
+
+    SmartPtr<RenderOsgModel> car_model = new RenderOsgModel (car_model_path.c_str(), true);
+
+    car_model->setup_shader_program ("Car", osg::Shader::VERTEX, VtxShaderCar);
+    car_model->setup_shader_program ("Car", osg::Shader::FRAGMENT, FrgShaderCar);
+
+    float translation_x = -0.3f;
+    float translation_y = 0.0f;
+    float translation_z = 0.0f;
+    float rotation_x = 0.0f;
+    float rotation_y = 0.0f;
+    float rotation_z = 1.0f;
+    float rotation_degrees = -180.0;
+
+    car_model->setup_model_matrix (
+        translation_x,
+        translation_y,
+        translation_z,
+        rotation_x,
+        rotation_y,
+        rotation_z,
+        rotation_degrees);
+
+    return car_model;
+}
+
+static int
+run_stitcher (
+    const SmartPtr<Stitcher> &stitcher,
+    const SmartPtr<RenderOsgModel> &model,
+    const SVStreams &ins,
+    const SVStreams &outs)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    Mutex mutex;
+
+    VideoBufferList in_buffers;
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        CHECK (ins[i]->rewind (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ());
+    }
+
+    do {
+        in_buffers.clear ();
+
+        for (uint32_t i = 0; i < ins.size (); ++i) {
+            ret = ins[i]->read_buf();
+            if (ret == XCAM_RETURN_BYPASS)
+                break;
+            CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ());
+            in_buffers.push_back (ins[i]->get_buf ());
+        }
+        if (ret == XCAM_RETURN_BYPASS) {
+            XCAM_LOG_DEBUG ("XCAM_RETURN_BYPASS \n");
+            break;
+        }
+
+        {
+            SmartLock locker (mutex);
+            CHECK (
+                stitcher->stitch_buffers (in_buffers, outs[0]->get_buf ()),
+                "stitch buffer failed.");
+        }
+
+        model->update_texture (outs[0]->get_buf ());
+
+        FPS_CALCULATION (render surround view, XCAM_OBJ_DUR_FRAME_NUM);
+    } while (true);
+
+    return 0;
+}
+
+static void usage(const char* arg0)
+{
+    printf ("Usage:\n"
+            "%s --module MODULE --input0 input.nv12 --input1 input1.nv12 --input2 input2.nv12 ...\n"
+            "\t--module            processing module, selected from: soft, gles, vulkan\n"
+            "\t--                  read calibration files from exported path $FISHEYE_CONFIG_PATH\n"
+            "\t--input0            input image(NV12)\n"
+            "\t--input1            input image(NV12)\n"
+            "\t--input2            input image(NV12)\n"
+            "\t--input3            input image(NV12)\n"
+            "\t--in-w              optional, input width, default: 1280\n"
+            "\t--in-h              optional, input height, default: 800\n"
+            "\t--out-w             optional, output width, default: 1920\n"
+            "\t--out-h             optional, output height, default: 640\n"
+            "\t--scale-mode        optional, scaling mode for geometric mapping,\n"
+            "\t                    select from [singleconst/dualconst/dualcurve], default: singleconst\n"
+            "\t--fm-mode           optional, feature match mode,\n"
+#if HAVE_OPENCV
+            "\t                    select from [none/default/cluster/capi], default: none\n"
+#else
+            "\t                    select from [none], default: none\n"
+#endif
+            "\t--car               optional, car model name\n"
+            "\t--loop              optional, how many loops need to run, default: 1\n"
+            "\t--help              usage\n",
+            arg0);
+}
+
+int main (int argc, char *argv[])
+{
+    uint32_t input_width = 1280;
+    uint32_t input_height = 800;
+    uint32_t output_width = 1920;
+    uint32_t output_height = 640;
+
+    SVStreams ins;
+    SVStreams outs;
+    PUSH_STREAM (SVStream, outs, NULL);
+
+    const char *car_name = NULL;
+
+    SVModule module = SVModuleGLES;
+    GeoMapScaleMode scale_mode = ScaleSingleConst;
+    FeatureMatchMode fm_mode = FMNone;
+
+    int loop = 1;
+
+    const struct option long_opts[] = {
+        {"module", required_argument, NULL, 'm'},
+        {"input0", required_argument, NULL, 'i'},
+        {"input1", required_argument, NULL, 'j'},
+        {"input2", required_argument, NULL, 'k'},
+        {"input3", required_argument, NULL, 'l'},
+        {"in-w", required_argument, NULL, 'w'},
+        {"in-h", required_argument, NULL, 'h'},
+        {"out-w", required_argument, NULL, 'W'},
+        {"out-h", required_argument, NULL, 'H'},
+        {"scale-mode", required_argument, NULL, 'S'},
+        {"fm-mode", required_argument, NULL, 'F'},
+        {"car", required_argument, NULL, 'c'},
+        {"loop", required_argument, NULL, 'L'},
+        {"help", no_argument, NULL, 'e'},
+        {NULL, 0, NULL, 0},
+    };
+
+    int opt = -1;
+    while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+        switch (opt) {
+        case 'm':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "soft")) {
+                module = SVModuleSoft;
+            } else if (!strcasecmp (optarg, "gles")) {
+                module = SVModuleGLES;
+            } else if (!strcasecmp (optarg, "vulkan")) {
+                module = SVModuleVulkan;
+            }
+            break;
+        case 'i':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'j':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'k':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'l':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'w':
+            XCAM_ASSERT (optarg);
+            input_width = (uint32_t)atoi(optarg);
+            break;
+        case 'h':
+            XCAM_ASSERT (optarg);
+            input_height = (uint32_t)atoi(optarg);
+            break;
+        case 'W':
+            XCAM_ASSERT (optarg);
+            output_width = (uint32_t)atoi(optarg);
+            break;
+        case 'H':
+            XCAM_ASSERT (optarg);
+            output_height = (uint32_t)atoi(optarg);
+            break;
+        case 'S':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "singleconst"))
+                scale_mode = ScaleSingleConst;
+            else if (!strcasecmp (optarg, "dualconst"))
+                scale_mode = ScaleDualConst;
+            else if (!strcasecmp (optarg, "dualcurve"))
+                scale_mode = ScaleDualCurve;
+            else {
+                XCAM_LOG_ERROR ("GeoMapScaleMode unknown mode: %s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'F':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "none"))
+                fm_mode = FMNone;
+#if HAVE_OPENCV
+            else if (!strcasecmp (optarg, "default"))
+                fm_mode = FMDefault;
+            else if (!strcasecmp (optarg, "cluster"))
+                fm_mode = FMCluster;
+            else if (!strcasecmp (optarg, "capi"))
+                fm_mode = FMCapi;
+#endif
+            else {
+                XCAM_LOG_ERROR ("unsupported feature match mode: %s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'c':
+            XCAM_ASSERT (optarg);
+            car_name = optarg;
+            break;
+        case 'L':
+            loop = atoi(optarg);
+            break;
+        case 'e':
+            usage (argv[0]);
+            return 0;
+        default:
+            XCAM_LOG_ERROR ("getopt_long return unknown value: %c", opt);
+            usage (argv[0]);
+            return -1;
+        }
+    }
+
+    if (optind < argc || argc < 2) {
+        XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
+        usage (argv[0]);
+        return -1;
+    }
+
+    CHECK_EXP (ins.size () == 4, "surrond view needs 4 input streams");
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        CHECK_EXP (ins[i].ptr (), "input stream is NULL, index:%d", i);
+        CHECK_EXP (strlen (ins[i]->get_file_name ()), "input file name was not set, index:%d", i);
+    }
+
+    CHECK_EXP (outs.size () == 1 && outs[0].ptr (), "surrond view needs 1 output stream");
+
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ());
+    }
+    printf ("input width:\t\t%d\n", input_width);
+    printf ("input height:\t\t%d\n", input_height);
+    printf ("output width:\t\t%d\n", output_width);
+    printf ("output height:\t\t%d\n", output_height);
+    printf ("scaling mode:\t\t%s\n", (scale_mode == ScaleSingleConst) ? "singleconst" :
+            ((scale_mode == ScaleDualConst) ? "dualconst" : "dualcurve"));
+    printf ("feature match:\t\t%s\n", (fm_mode == FMNone) ? "none" :
+            ((fm_mode == FMDefault ) ? "default" : ((fm_mode == FMCluster) ? "cluster" : "capi")));
+    printf ("car model name:\t\t%s\n", car_name != NULL ? car_name : "Not specified, use default model");
+    printf ("loop count:\t\t%d\n", loop);
+
+#if HAVE_GLES
+    SmartPtr<EGLBase> egl;
+    if (module == SVModuleGLES) {
+        egl = new EGLBase ();
+        XCAM_ASSERT (egl.ptr ());
+        XCAM_FAIL_RETURN (ERROR, egl->init (), -1, "init EGL failed");
+    }
+#else
+    if (module == SVModuleGLES) {
+        XCAM_LOG_ERROR ("GLES module is unsupported");
+        return -1;
+    }
+#endif
+
+    if (module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        scale_mode = ScaleSingleConst;
+        if (scale_mode != ScaleSingleConst) {
+            XCAM_LOG_ERROR ("vulkan module only support singleconst scale mode currently");
+            return -1;
+        }
+
+        SmartPtr<VKDevice> vk_dev = VKDevice::default_device ();
+        for (uint32_t i = 0; i < ins.size (); ++i) {
+            ins[i]->set_vk_device (vk_dev);
+        }
+        XCAM_ASSERT (outs[0].ptr ());
+        outs[0]->set_vk_device (vk_dev);
+#else
+        XCAM_LOG_ERROR ("vulkan module is unsupported");
+        return -1;
+#endif
+    }
+
+    VideoBufferInfo in_info;
+    in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        ins[i]->set_module (module);
+        ins[i]->set_buf_size (input_width, input_height);
+        CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed");
+        CHECK (ins[i]->open_reader ("rb"), "open input file(%s) failed", ins[i]->get_file_name ());
+    }
+
+    outs[0]->set_buf_size (output_width, output_height);
+
+    SmartPtr<Stitcher> stitcher = create_stitcher (outs[0], module);
+    XCAM_ASSERT (stitcher.ptr ());
+
+    CameraInfo cam_info[4];
+    std::string fisheye_config_path = FISHEYE_CONFIG_PATH;
+    const char *env = std::getenv (FISHEYE_CONFIG_ENV_VAR);
+    if (env)
+        fisheye_config_path.assign (env, strlen (env));
+    XCAM_LOG_INFO ("calibration config path:%s", fisheye_config_path.c_str ());
+
+    uint32_t camera_count = ins.size ();
+    for (uint32_t i = 0; i < camera_count; ++i) {
+        if (parse_camera_info (fisheye_config_path.c_str (), i, cam_info[i], camera_count) != 0) {
+            XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i);
+            return -1;
+        }
+    }
+
+    PointFloat3 bowl_coord_offset;
+    centralize_bowl_coord_from_cameras (
+        cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic,
+        cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic,
+        bowl_coord_offset);
+
+    stitcher->set_camera_num (camera_count);
+    for (uint32_t i = 0; i < camera_count; ++i) {
+        stitcher->set_camera_info (i, cam_info[i]);
+    }
+
+    BowlDataConfig bowl;
+    bowl.wall_height = 1800.0f;
+    bowl.ground_length = 3000.0f;
+    bowl.angle_start = 0.0f;
+    bowl.angle_end = 360.0f;
+    stitcher->set_bowl_config (bowl);
+    stitcher->set_output_size (output_width, output_height);
+    stitcher->set_scale_mode (scale_mode);
+    stitcher->set_fm_mode (fm_mode);
+
+    SmartPtr<RenderOsgViewer> render = new RenderOsgViewer ();
+
+    SmartPtr<RenderOsgModel> sv_model = create_surround_view_model (stitcher, output_width, output_height);
+    render->add_model (sv_model);
+
+    SmartPtr<RenderOsgModel> car_model = create_car_model (car_name);
+    render->add_model (car_model);
+
+    render->validate_model_groups ();
+
+    render->start_render ();
+
+    while (loop--) {
+        CHECK_EXP (
+            run_stitcher (stitcher, sv_model, ins, outs) == 0,
+            "run stitcher failed");
+    }
+
+    render->stop_render ();
+
+    return 0;
+}
diff --git a/tests/test-soft-image.cpp b/tests/test-soft-image.cpp
index 578de8e..d9d9493 100644
--- a/tests/test-soft-image.cpp
+++ b/tests/test-soft-image.cpp
@@ -20,31 +20,10 @@
 
 #include "test_common.h"
 #include "test_inline.h"
-#include <buffer_pool.h>
-#include <image_handler.h>
-#include <image_file_handle.h>
+#include "test_stream.h"
 #include <soft/soft_video_buf_allocator.h>
 #include <interface/blender.h>
 #include <interface/geo_mapper.h>
-#include <interface/stitcher.h>
-#include <calibration_parser.h>
-#include <string>
-
-#if (!defined(ANDROID) && (HAVE_OPENCV))
-#include <ocl/cv_base_class.h>
-#endif
-
-#define XCAM_TEST_SOFT_IMAGE_DEBUG 0
-
-#if (!defined(ANDROID) && (HAVE_OPENCV))
-#define XCAM_TEST_OPENCV 1
-#else
-#define XCAM_TEST_OPENCV 0
-#endif
-
-#define XCAM_TEST_MAX_STR_SIZE 1024
-
-#define FISHEYE_CONFIG_PATH "./"
 
 #define MAP_WIDTH 3
 #define MAP_HEIGHT 4
@@ -59,484 +38,58 @@
 using namespace XCam;
 
 enum SoftType {
-    SoftTypeNone     = 0,
+    SoftTypeNone    = 0,
     SoftTypeBlender,
-    SoftTypeRemap,
-    SoftTypeStitch,
+    SoftTypeRemap
 };
 
-#define RUN_N(statement, loop, msg, ...) \
-    for (int i = 0; i < loop; ++i) {                          \
-        CHECK (statement, msg, ## __VA_ARGS__);               \
-        FPS_CALCULATION (soft-image, XCAM_OBJ_DUR_FRAME_NUM); \
-    }
-
-#define ADD_ENELEMT(elements, file_name) \
-    {                                                                \
-        SmartPtr<SoftElement> element = new SoftElement (file_name); \
-        elements.push_back (element);                                \
-    }
-
-#if XCAM_TEST_OPENCV
-const static cv::Scalar color = cv::Scalar (0, 0, 255);
-const static int fontFace = cv::FONT_HERSHEY_COMPLEX;
-#endif
-
-class SoftElement {
+class SoftStream
+    : public Stream
+{
 public:
-    explicit SoftElement (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
-    ~SoftElement ();
+    explicit SoftStream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+    virtual ~SoftStream () {}
 
-    void set_buf_size (uint32_t width, uint32_t height);
-    uint32_t get_width () const {
-        return _width;
-    }
-    uint32_t get_height () const {
-        return _height;
-    }
-
-    const char *get_file_name () const {
-        return _file_name;
-    }
-
-    SmartPtr<VideoBuffer> &get_buf () {
-        return _buf;
-    }
-
-    XCamReturn open_file (const char *option);
-    XCamReturn close_file ();
-    XCamReturn rewind_file ();
-
-    XCamReturn read_buf ();
-    XCamReturn write_buf ();
-
-    XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
-
-#if XCAM_TEST_OPENCV
-    XCamReturn cv_open_writer ();
-    void cv_write_image (char *img_name, char *frame_str, char *idx_str = NULL);
-#endif
+    virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
 
 private:
-    char                 *_file_name;
-    uint32_t              _width;
-    uint32_t              _height;
-    SmartPtr<VideoBuffer> _buf;
-
-    ImageFileHandle       _file;
-    SmartPtr<BufferPool>  _pool;
-#if XCAM_TEST_OPENCV
-    cv::VideoWriter       _writer;
-#endif
+    XCAM_DEAD_COPY (SoftStream);
 };
+typedef std::vector<SmartPtr<SoftStream>> SoftStreams;
 
-typedef std::vector<SmartPtr<SoftElement>> SoftElements;
-
-SoftElement::SoftElement (const char *file_name, uint32_t width, uint32_t height)
-    : _file_name (NULL)
-    , _width (width)
-    , _height (height)
+SoftStream::SoftStream (const char *file_name, uint32_t width, uint32_t height)
+    :  Stream (file_name, width, height)
 {
-    if (file_name)
-        _file_name = strndup (file_name, XCAM_TEST_MAX_STR_SIZE);
-}
-
-SoftElement::~SoftElement ()
-{
-    _file.close ();
-
-    if (_file_name)
-        xcam_free (_file_name);
-}
-
-void
-SoftElement::set_buf_size (uint32_t width, uint32_t height)
-{
-    _width = width;
-    _height = height;
 }
 
 XCamReturn
-SoftElement::open_file (const char *option)
+SoftStream::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
 {
-    if (_file.open (_file_name, option) != XCAM_RETURN_NO_ERROR) {
-        XCAM_LOG_ERROR ("open %s failed.", _file_name);
-        return XCAM_RETURN_ERROR_FILE;
-    }
+    SmartPtr<BufferPool> pool = new SoftVideoBufAllocator ();
+    XCAM_ASSERT (pool.ptr ());
 
-    return XCAM_RETURN_NO_ERROR;
-}
-
-XCamReturn
-SoftElement::close_file ()
-{
-    return _file.close ();
-}
-
-XCamReturn
-SoftElement::rewind_file ()
-{
-    return _file.rewind ();
-}
-
-XCamReturn
-SoftElement::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
-{
-    _pool = new SoftVideoBufAllocator ();
-    _pool->set_video_info (info);
-    if (!_pool->reserve (count)) {
+    pool->set_video_info (info);
+    if (!pool->reserve (count)) {
         XCAM_LOG_ERROR ("create buffer pool failed");
         return XCAM_RETURN_ERROR_MEM;
     }
 
+    set_buf_pool (pool);
     return XCAM_RETURN_NO_ERROR;
 }
 
-XCamReturn
-SoftElement::read_buf ()
-{
-    _buf = _pool->get_buffer (_pool);
-    XCAM_ASSERT (_buf.ptr ());
-
-    return _file.read_buf (_buf);
-}
-
-XCamReturn
-SoftElement::write_buf () {
-    return _file.write_buf (_buf);
-}
-
-#if XCAM_TEST_OPENCV
-XCamReturn
-SoftElement::cv_open_writer ()
-{
-    XCAM_FAIL_RETURN (
-        ERROR,
-        _width && _height,
-        XCAM_RETURN_ERROR_PARAM,
-        "invalid size width:%d height:%d", _width, _height);
-
-    cv::Size frame_size = cv::Size (_width, _height);
-    if (!_writer.open (_file_name, CV_FOURCC('X', '2', '6', '4'), 30, frame_size)) {
-        XCAM_LOG_ERROR ("open file %s failed", _file_name);
-        return XCAM_RETURN_ERROR_FILE;
-    }
-
-    return XCAM_RETURN_NO_ERROR;
-}
-
-void
-SoftElement::cv_write_image (char *img_name, char *frame_str, char *idx_str)
-{
-    cv::Mat mat;
-
-#if XCAM_TEST_SOFT_IMAGE_DEBUG
-    convert_to_mat (_buf, mat);
-
-    cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false);
-    if(idx_str)
-        cv::putText (mat, idx_str, cv::Point(20, 110), fontFace, 2.0, color, 2, 8, false);
-
-    cv::imwrite (img_name, mat);
-#else
-    XCAM_UNUSED (img_name);
-    XCAM_UNUSED (frame_str);
-    XCAM_UNUSED (idx_str);
-#endif
-
-    if (_writer.isOpened ()) {
-        if (mat.empty())
-            convert_to_mat (_buf, mat);
-
-        _writer.write (mat);
-    }
-}
-#endif
-
-static int
-parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count)
-{
-    static const char *instrinsic_names[] = {
-        "intrinsic_camera_front.txt", "intrinsic_camera_right.txt",
-        "intrinsic_camera_rear.txt", "intrinsic_camera_left.txt"
-    };
-    static const char *exstrinsic_names[] = {
-        "extrinsic_camera_front.txt", "extrinsic_camera_right.txt",
-        "extrinsic_camera_rear.txt", "extrinsic_camera_left.txt"
-    };
-    static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f};
-
-    char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-    char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-    snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]);
-    snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]);
-
-    CalibrationParser parser;
-    CHECK (
-        parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic),
-        "parse intrinsic params (%s)failed.", intrinsic_path);
-
-    CHECK (
-        parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic),
-        "parse extrinsic params (%s)failed.", extrinsic_path);
-    info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X;
-
-    info.angle_range = viewpoints_range[idx];
-    info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f;
-    return 0;
-}
-
-static void
-combine_name (const char *orig_name, const char *embedded_str, char *new_name)
-{
-    const char *dir_delimiter = std::strrchr (orig_name, '/');
-
-    if (dir_delimiter) {
-        std::string path (orig_name, dir_delimiter - orig_name + 1);
-        XCAM_ASSERT (path.c_str ());
-        snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s%s_%s", path.c_str (), embedded_str, dir_delimiter + 1);
-    } else {
-        snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s_%s", embedded_str, orig_name);
-    }
-}
-
-static void
-add_element (SoftElements &elements, const char *element_name, uint32_t width, uint32_t height)
-{
-    char file_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-    combine_name (elements[0]->get_file_name (), element_name, file_name);
-
-    SmartPtr<SoftElement> element = new SoftElement (file_name, width, height);
-    elements.push_back (element);
-}
-
-static XCamReturn
-elements_open_file (const SoftElements &elements, const char *option, const bool &nv12_output)
-{
-    XCamReturn ret = XCAM_RETURN_NO_ERROR;
-
-    for (uint32_t i = 0; i < elements.size (); ++i) {
-        if (nv12_output)
-            ret = elements[i]->open_file (option);
-#if XCAM_TEST_OPENCV
-        else
-            ret = elements[i]->cv_open_writer ();
-#endif
-
-        if (ret != XCAM_RETURN_NO_ERROR) {
-            XCAM_LOG_ERROR ("open file(%s) failed", elements[i]->get_file_name ());
-            break;
-        }
-    }
-
-    return ret;
-}
-
-static XCamReturn
-remap_topview_buf (
-    BowlModel &model,
-    const SmartPtr<VideoBuffer> &buf,
-    SmartPtr<VideoBuffer> &topview_buf,
-    uint32_t topview_width, uint32_t topview_height)
-{
-    BowlModel::PointMap points;
-
-    uint32_t lut_w = topview_width / 4, lut_h = topview_height / 4;
-    float length_mm = 0.0f, width_mm = 0.0f;
-
-    model.get_max_topview_area_mm (length_mm, width_mm);
-    XCAM_LOG_INFO ("Max Topview Area (L%.2fmm, W%.2fmm)", length_mm, width_mm);
-
-    model.get_topview_rect_map (points, lut_w, lut_h);
-    SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper ();
-    XCAM_ASSERT (mapper.ptr ());
-    mapper->set_output_size (topview_width, topview_height);
-    mapper->set_lookup_table (points.data (), lut_w, lut_h);
-
-    XCamReturn ret = mapper->remap (buf, topview_buf);
-    if (ret != XCAM_RETURN_NO_ERROR) {
-        XCAM_LOG_ERROR ("remap stitched image to topview failed.");
-        return ret;
-    }
-
-#if 0
-    BowlModel::VertexMap bowl_vertices;
-    BowlModel::PointMap bowl_points;
-    uint32_t bowl_lut_w = 15, bowl_lut_h = 10;
-    model.get_bowlview_vertex_map (bowl_vertices, bowl_points, bowl_lut_w, bowl_lut_h);
-    for (uint32_t i = 0; i < bowl_lut_h; ++i) {
-        for (uint32_t j = 0; j < bowl_lut_w; ++j)
-        {
-            PointFloat3 &vetex = bowl_vertices[i * bowl_lut_w + j];
-            printf ("(%4.0f, %4.0f, %4.0f), ", vetex.x, vetex.y, vetex.z );
-        }
-        printf ("\n");
-    }
-#endif
-
-    return XCAM_RETURN_NO_ERROR;
-}
-
-static void
-write_image (const SoftElements &ins, const SoftElements &outs, const bool &nv12_output) {
-    if (nv12_output) {
-        for (uint32_t i = 0; i < outs.size (); ++i)
-            outs[i]->write_buf ();
-    }
-#if XCAM_TEST_OPENCV
-    else {
-        static uint32_t frame_num = 0;
-        char img_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-        char frame_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-        std::snprintf (frame_str, XCAM_TEST_MAX_STR_SIZE, "frame:%d", frame_num);
-
-        char idx_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-        for (uint32_t i = 0; i < ins.size (); ++i) {
-            std::snprintf (idx_str, XCAM_TEST_MAX_STR_SIZE, "idx:%d", i);
-            std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "orig_fisheye_%d_%d.jpg", frame_num, i);
-            ins[i]->cv_write_image (img_name, frame_str, idx_str);
-        }
-
-        for (uint32_t i = 0; i < outs.size (); ++i) {
-            std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "%s_%d.jpg", outs[i]->get_file_name (), frame_num);
-            outs[i]->cv_write_image (img_name, frame_str);
-        }
-        frame_num++;
-    }
-#endif
-}
-
-static XCamReturn
-ensure_output_format (const char *file_name, const SoftType &type, bool &nv12_output)
-{
-    char suffix[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
-    const char *ptr = std::strrchr (file_name, '.');
-    std::snprintf (suffix, XCAM_TEST_MAX_STR_SIZE, "%s", ptr + 1);
-    if (!strcasecmp (suffix, "mp4")) {
-#if XCAM_TEST_OPENCV
-        if (type != SoftTypeStitch) {
-            XCAM_LOG_ERROR ("only stitch type supports MP4 output format");
-            return XCAM_RETURN_ERROR_PARAM;
-        }
-        nv12_output = false;
-#else
-        XCAM_LOG_ERROR ("only supports NV12 output format");
-        return XCAM_RETURN_ERROR_PARAM;
-#endif
-    }
-
-    return XCAM_RETURN_NO_ERROR;
-}
-
-static bool
-check_element (const SoftElements &elements, const uint32_t &idx)
-{
-    if (idx >= elements.size ())
-        return false;
-
-    if (!elements[idx].ptr()) {
-        XCAM_LOG_ERROR ("SoftElement(idx:%d) ptr is NULL", idx);
-        return false;
-    }
-
-    XCAM_FAIL_RETURN (
-        ERROR,
-        elements[idx]->get_width () && elements[idx]->get_height (),
-        false,
-        "SoftElement(idx:%d): invalid parameters width:%d height:%d",
-        idx, elements[idx]->get_width (), elements[idx]->get_height ());
-
-    return true;
-}
-
-static XCamReturn
-check_elements (const SoftElements &elements)
-{
-    for (uint32_t i = 0; i < elements.size (); ++i) {
-        XCAM_FAIL_RETURN (
-            ERROR,
-            check_element (elements, i),
-            XCAM_RETURN_ERROR_PARAM,
-            "invalid SoftElement index:%d\n", i);
-    }
-
-    return XCAM_RETURN_NO_ERROR;
-}
-
-static XCamReturn
-run_topview (const SmartPtr<Stitcher> &stitcher, const SoftElements &outs)
-{
-    BowlModel bowl_model (stitcher->get_bowl_config (), outs[0]->get_width (), outs[0]->get_height ());
-    return remap_topview_buf (bowl_model, outs[0]->get_buf (), outs[1]->get_buf (),
-                              outs[1]->get_width (), outs[1]->get_height ());
-}
-
-static int
-run_stitcher (
-    const SmartPtr<Stitcher> &stitcher,
-    const SoftElements &ins, const SoftElements &outs,
-    bool nv12_output, bool save_output, int loop)
-{
-    XCamReturn ret = XCAM_RETURN_NO_ERROR;
-    CHECK (check_elements (ins), "invalid input elements");
-    CHECK (check_elements (outs), "invalid output elements");
-
-    VideoBufferList in_buffers;
-    while (loop--) {
-        for (uint32_t i = 0; i < ins.size (); ++i) {
-            CHECK (ins[i]->rewind_file (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ());
-        }
-
-        do {
-            in_buffers.clear ();
-
-            for (uint32_t i = 0; i < ins.size (); ++i) {
-                ret = ins[i]->read_buf();
-                if (ret == XCAM_RETURN_BYPASS)
-                    break;
-                CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ());
-
-                in_buffers.push_back (ins[i]->get_buf ());
-            }
-            if (ret == XCAM_RETURN_BYPASS)
-                break;
-
-            CHECK (
-                stitcher->stitch_buffers (in_buffers, outs[0]->get_buf ()),
-                "stitch buffer failed.");
-
-            if (save_output) {
-                if (check_element (outs, 1)) {
-                    CHECK (run_topview (stitcher, outs), "run topview failed");
-                }
-
-                write_image (ins, outs, nv12_output);
-            }
-
-            FPS_CALCULATION (soft - stitcher, XCAM_OBJ_DUR_FRAME_NUM);
-        } while (true);
-    }
-
-    return 0;
-}
-
 static void usage(const char* arg0)
 {
     printf ("Usage:\n"
-            "%s --type TYPE--input0 file0 --input1 file1 --output file\n"
-            "\t--type              processing type, selected from: blend, remap, stitch, ...\n"
-            "\t--                  [stitch]: read calibration files from exported path $FISHEYE_CONFIG_PATH\n"
+            "%s --type TYPE --input0 input.nv12 --input1 input1.nv12 --output output.nv12 ...\n"
+            "\t--type              processing type, selected from: blend, remap\n"
             "\t--input0            input image(NV12)\n"
             "\t--input1            input image(NV12)\n"
-            "\t--input2            input image(NV12)\n"
-            "\t--input3            input image(NV12)\n"
-            "\t--output            output image(NV12)\n"
-            "\t--in-w              optional, input width, default: 1920\n"
-            "\t--in-h              optional, input height, default: 1080\n"
-            "\t--out-w             optional, output width, default: 1920\n"
-            "\t--out-h             optional, output height, default: 960\n"
-            "\t--topview-w         optional, output width, default: 1280\n"
-            "\t--topview-h         optional, output height, default: 720\n"
+            "\t--output            output image(NV12/MP4)\n"
+            "\t--in-w              optional, input width, default: 1280\n"
+            "\t--in-h              optional, input height, default: 800\n"
+            "\t--out-w             optional, output width, default: 1280\n"
+            "\t--out-h             optional, output height, default: 800\n"
             "\t--save              optional, save file or not, select from [true/false], default: true\n"
             "\t--loop              optional, how many loops need to run, default: 1\n"
             "\t--help              usage\n",
@@ -545,36 +98,29 @@
 
 int main (int argc, char *argv[])
 {
-    uint32_t input_width = 1920;
-    uint32_t input_height = 1080;
-    uint32_t output_width = 1920; //output_height * 2;
-    uint32_t output_height = 960; //960;
-    uint32_t topview_width = 1280;
-    uint32_t topview_height = 720;
-    SoftType type = SoftTypeNone;
+    uint32_t input_width = 1280;
+    uint32_t input_height = 800;
+    uint32_t output_width = 1280;
+    uint32_t output_height = 800;
 
-    SoftElements ins;
-    SoftElements outs;
+    SoftStreams ins;
+    SoftStreams outs;
+    SoftType type = SoftTypeNone;
 
     int loop = 1;
     bool save_output = true;
-    bool nv12_output = true;
 
     const struct option long_opts[] = {
         {"type", required_argument, NULL, 't'},
         {"input0", required_argument, NULL, 'i'},
         {"input1", required_argument, NULL, 'j'},
-        {"input2", required_argument, NULL, 'k'},
-        {"input3", required_argument, NULL, 'l'},
         {"output", required_argument, NULL, 'o'},
         {"in-w", required_argument, NULL, 'w'},
         {"in-h", required_argument, NULL, 'h'},
         {"out-w", required_argument, NULL, 'W'},
         {"out-h", required_argument, NULL, 'H'},
-        {"topview-w", required_argument, NULL, 'P'},
-        {"topview-h", required_argument, NULL, 'V'},
         {"save", required_argument, NULL, 's'},
-        {"loop", required_argument, NULL, 'L'},
+        {"loop", required_argument, NULL, 'l'},
         {"help", no_argument, NULL, 'e'},
         {NULL, 0, NULL, 0},
     };
@@ -588,34 +134,23 @@
                 type = SoftTypeBlender;
             else if (!strcasecmp (optarg, "remap"))
                 type = SoftTypeRemap;
-            else if (!strcasecmp (optarg, "stitch"))
-                type = SoftTypeStitch;
             else {
                 XCAM_LOG_ERROR ("unknown type:%s", optarg);
                 usage (argv[0]);
                 return -1;
             }
             break;
-
         case 'i':
             XCAM_ASSERT (optarg);
-            ADD_ENELEMT(ins, optarg);
+            PUSH_STREAM (SoftStream, ins, optarg);
             break;
         case 'j':
             XCAM_ASSERT (optarg);
-            ADD_ENELEMT(ins, optarg);
-            break;
-        case 'k':
-            XCAM_ASSERT (optarg);
-            ADD_ENELEMT(ins, optarg);
-            break;
-        case 'l':
-            XCAM_ASSERT (optarg);
-            ADD_ENELEMT(ins, optarg);
+            PUSH_STREAM (SoftStream, ins, optarg);
             break;
         case 'o':
             XCAM_ASSERT (optarg);
-            ADD_ENELEMT(outs, optarg);
+            PUSH_STREAM (SoftStream, outs, optarg);
             break;
         case 'w':
             input_width = atoi(optarg);
@@ -629,18 +164,15 @@
         case 'H':
             output_height = atoi(optarg);
             break;
-        case 'P':
-            topview_width = atoi(optarg);
-            break;
-        case 'V':
-            topview_height = atoi(optarg);
-            break;
         case 's':
             save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
             break;
-        case 'L':
+        case 'l':
             loop = atoi(optarg);
             break;
+        case 'e':
+            usage (argv[0]);
+            return 0;
         default:
             XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt);
             usage (argv[0]);
@@ -654,12 +186,6 @@
         return -1;
     }
 
-    if (SoftTypeNone == type) {
-        XCAM_LOG_ERROR ("Type was not set");
-        usage (argv[0]);
-        return -1;
-    }
-
     if (ins.empty () || outs.empty () ||
             !strlen (ins[0]->get_file_name ()) || !strlen (outs[0]->get_file_name ())) {
         XCAM_LOG_ERROR ("input or output file name was not set");
@@ -675,47 +201,55 @@
     printf ("input height:\t\t%d\n", input_height);
     printf ("output width:\t\t%d\n", output_width);
     printf ("output height:\t\t%d\n", output_height);
-    printf ("topview width:\t\t%d\n", topview_width);
-    printf ("topview height:\t\t%d\n", topview_height);
     printf ("save output:\t\t%s\n", save_output ? "true" : "false");
     printf ("loop count:\t\t%d\n", loop);
 
-    VideoBufferInfo in_info, out_info;
+    VideoBufferInfo in_info;
     in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
-    out_info.init (V4L2_PIX_FMT_NV12, output_width, output_height);
-
     for (uint32_t i = 0; i < ins.size (); ++i) {
         ins[i]->set_buf_size (input_width, input_height);
         CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed");
-        CHECK (ins[i]->open_file ("rb"), "open file(%s) failed", ins[i]->get_file_name ());
+        CHECK (ins[i]->open_reader ("rb"), "open input file(%s) failed", ins[i]->get_file_name ());
     }
 
     outs[0]->set_buf_size (output_width, output_height);
     if (save_output) {
-        CHECK (ensure_output_format (outs[0]->get_file_name (), type, nv12_output), "unsupported output format");
-        if (nv12_output) {
-            CHECK (outs[0]->open_file ("wb"), "open file(%s) failed", outs[0]->get_file_name ());
-        }
+        CHECK (outs[0]->estimate_file_format (), "%s: estimate file format failed", outs[0]->get_file_name ());
+        CHECK (outs[0]->open_writer ("wb"), "open output file(%s) failed", outs[0]->get_file_name ());
     }
 
     switch (type) {
     case SoftTypeBlender: {
-        CHECK_EXP (ins.size () >= 2, "blender need 2 input files.");
+        CHECK_EXP (ins.size () == 2, "blender needs 2 input files.");
         SmartPtr<Blender> blender = Blender::create_soft_blender ();
         XCAM_ASSERT (blender.ptr ());
         blender->set_output_size (output_width, output_height);
-        Rect merge_window;
-        merge_window.pos_x = 0;
-        merge_window.pos_y = 0;
-        merge_window.width = out_info.width;
-        merge_window.height = out_info.height;
-        blender->set_merge_window (merge_window);
+
+        Rect area;
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = output_width;
+        area.height = output_height;
+        blender->set_merge_window (area);
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = input_width;
+        area.height = input_height;
+        blender->set_input_merge_area (area, 0);
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = input_width;
+        area.height = input_height;
+        blender->set_input_merge_area (area, 1);
 
         CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
         CHECK (ins[1]->read_buf(), "read buffer from file(%s) failed.", ins[1]->get_file_name ());
-        RUN_N (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), loop, "blend buffer failed.");
-        if (save_output)
-            outs[0]->write_buf ();
+        for (int i = 0; i < loop; ++i) {
+            CHECK (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), "blend buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (soft-blend, XCAM_OBJ_DUR_FRAME_NUM);
+        }
         break;
     }
     case SoftTypeRemap: {
@@ -726,64 +260,14 @@
         //mapper->set_factors ((output_width - 1.0f) / (MAP_WIDTH - 1.0f), (output_height - 1.0f) / (MAP_HEIGHT - 1.0f));
 
         CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
-        RUN_N (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), loop, "remap buffer failed.");
-        if (save_output)
-            outs[0]->write_buf ();
+        for (int i = 0; i < loop; ++i) {
+            CHECK (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), "remap buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (soft-remap, XCAM_OBJ_DUR_FRAME_NUM);
+        }
         break;
     }
-    case SoftTypeStitch: {
-        CHECK_EXP (ins.size () >= 2 && ins.size () <= 4, "stitcher need at 2~4 input files.");
-
-        uint32_t camera_count = ins.size ();
-        SmartPtr<Stitcher> stitcher = Stitcher::create_soft_stitcher ();
-        XCAM_ASSERT (stitcher.ptr ());
-
-        CameraInfo cam_info[4];
-        const char *fisheye_config_path = getenv ("FISHEYE_CONFIG_PATH");
-        if (!fisheye_config_path)
-            fisheye_config_path = FISHEYE_CONFIG_PATH;
-
-        for (uint32_t i = 0; i < camera_count; ++i) {
-            if (parse_camera_info (fisheye_config_path, i, cam_info[i], camera_count) != 0) {
-                XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i);
-                return -1;
-            }
-        }
-
-        PointFloat3 bowl_coord_offset;
-        if (camera_count == 4) {
-            centralize_bowl_coord_from_cameras (
-                cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic,
-                cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic,
-                bowl_coord_offset);
-        }
-
-        stitcher->set_camera_num (camera_count);
-        for (uint32_t i = 0; i < camera_count; ++i) {
-            stitcher->set_camera_info (i, cam_info[i]);
-        }
-
-        BowlDataConfig bowl;
-        bowl.wall_height = 3000.0f;
-        bowl.ground_length = 2000.0f;
-        //bowl.a = 5000.0f;
-        //bowl.b = 3600.0f;
-        //bowl.c = 3000.0f;
-        bowl.angle_start = 0.0f;
-        bowl.angle_end = 360.0f;
-        stitcher->set_bowl_config (bowl);
-        stitcher->set_output_size (output_width, output_height);
-
-        if (save_output) {
-            add_element (outs, "topview", topview_width, topview_height);
-            elements_open_file (outs, "wb", nv12_output);
-        }
-        CHECK_EXP (
-            run_stitcher (stitcher, ins, outs, nv12_output, save_output, loop) == 0,
-            "run stitcher failed.");
-        break;
-    }
-
     default: {
         XCAM_LOG_ERROR ("unsupported type:%d", type);
         usage (argv[0]);
diff --git a/tests/test-surround-view.cpp b/tests/test-surround-view.cpp
new file mode 100644
index 0000000..6d627c3
--- /dev/null
+++ b/tests/test-surround-view.cpp
@@ -0,0 +1,769 @@
+/*
+ * test-surround-view.cpp - test surround view
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#include "test_common.h"
+#include "test_stream.h"
+#include <interface/geo_mapper.h>
+#include <interface/stitcher.h>
+#include <calibration_parser.h>
+#include <soft/soft_video_buf_allocator.h>
+#if HAVE_GLES
+#include <gles/gl_video_buffer.h>
+#include <gles/egl/egl_base.h>
+#endif
+#if HAVE_VULKAN
+#include <vulkan/vk_device.h>
+#endif
+
+using namespace XCam;
+
+enum FrameMode {
+    FrameSingle = 0,
+    FrameMulti
+};
+
+enum SVModule {
+    SVModuleNone    = 0,
+    SVModuleSoft,
+    SVModuleGLES,
+    SVModuleVulkan
+};
+
+enum SVOutIdx {
+    IdxStitch    = 0,
+    IdxTopView,
+    IdxCount
+};
+
+static const char *instrinsic_names[] = {
+    "intrinsic_camera_front.txt",
+    "intrinsic_camera_right.txt",
+    "intrinsic_camera_rear.txt",
+    "intrinsic_camera_left.txt"
+};
+
+static const char *exstrinsic_names[] = {
+    "extrinsic_camera_front.txt",
+    "extrinsic_camera_right.txt",
+    "extrinsic_camera_rear.txt",
+    "extrinsic_camera_left.txt"
+};
+
+static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f};
+
+class SVStream
+    : public Stream
+{
+public:
+    explicit SVStream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+    virtual ~SVStream () {}
+
+    void set_module (SVModule module) {
+        XCAM_ASSERT (module != SVModuleNone);
+        _module = module;
+    }
+
+    void set_mapper (const SmartPtr<GeoMapper> &mapper) {
+        XCAM_ASSERT (mapper.ptr ());
+        _mapper = mapper;
+    }
+    const SmartPtr<GeoMapper> &get_mapper () {
+        return _mapper;
+    }
+
+#if HAVE_VULKAN
+    void set_vk_device (SmartPtr<VKDevice> &device) {
+        XCAM_ASSERT (device.ptr ());
+        _vk_dev = device;
+    }
+    SmartPtr<VKDevice> &get_vk_device () {
+        return _vk_dev;
+    }
+#endif
+
+    virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
+
+private:
+    XCAM_DEAD_COPY (SVStream);
+
+private:
+    SVModule               _module;
+    SmartPtr<GeoMapper>    _mapper;
+#if HAVE_VULKAN
+    SmartPtr<VKDevice>     _vk_dev;
+#endif
+};
+typedef std::vector<SmartPtr<SVStream>> SVStreams;
+
+SVStream::SVStream (const char *file_name, uint32_t width, uint32_t height)
+    :  Stream (file_name, width, height)
+    , _module (SVModuleNone)
+{
+}
+
+XCamReturn
+SVStream::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _module != SVModuleNone, XCAM_RETURN_ERROR_PARAM,
+        "invalid module, please set module first");
+
+    SmartPtr<BufferPool> pool;
+    if (_module == SVModuleSoft) {
+        pool = new SoftVideoBufAllocator (info);
+    } else if (_module == SVModuleGLES) {
+#if HAVE_GLES
+        pool = new GLVideoBufferPool (info);
+#endif
+    } else if (_module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        XCAM_ASSERT (_vk_dev.ptr ());
+        pool = create_vk_buffer_pool (_vk_dev);
+        XCAM_ASSERT (pool.ptr ());
+        pool->set_video_info (info);
+#endif
+    }
+    XCAM_ASSERT (pool.ptr ());
+
+    if (!pool->reserve (count)) {
+        XCAM_LOG_ERROR ("create buffer pool failed");
+        return XCAM_RETURN_ERROR_MEM;
+    }
+
+    set_buf_pool (pool);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static SmartPtr<Stitcher>
+create_stitcher (const SmartPtr<SVStream> &stitch, SVModule module)
+{
+    SmartPtr<Stitcher> stitcher;
+
+    if (module == SVModuleSoft) {
+        stitcher = Stitcher::create_soft_stitcher ();
+    } else if (module == SVModuleGLES) {
+#if HAVE_GLES
+        stitcher = Stitcher::create_gl_stitcher ();
+#endif
+    } else if (module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        SmartPtr<VKDevice> dev = stitch->get_vk_device ();
+        XCAM_ASSERT (dev.ptr ());
+        stitcher = Stitcher::create_vk_stitcher (dev);
+#else
+        XCAM_UNUSED (stitch);
+#endif
+    }
+    XCAM_ASSERT (stitcher.ptr ());
+
+    return stitcher;
+}
+
+static int
+parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count)
+{
+    XCAM_ASSERT (path);
+
+    char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]);
+    snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]);
+
+    CalibrationParser parser;
+    CHECK (
+        parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic),
+        "parse intrinsic params(%s) failed.", intrinsic_path);
+
+    CHECK (
+        parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic),
+        "parse extrinsic params(%s) failed.", extrinsic_path);
+    info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X;
+
+    info.angle_range = viewpoints_range[idx];
+    info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f;
+    return 0;
+}
+
+static void
+combine_name (const char *orig_name, const char *embedded_str, char *new_name)
+{
+    const char *dir_delimiter = strrchr (orig_name, '/');
+
+    if (dir_delimiter) {
+        std::string path (orig_name, dir_delimiter - orig_name + 1);
+        XCAM_ASSERT (path.c_str ());
+        snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s%s_%s", path.c_str (), embedded_str, dir_delimiter + 1);
+    } else {
+        snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s_%s", embedded_str, orig_name);
+    }
+}
+
+static void
+add_stream (SVStreams &streams, const char *stream_name, uint32_t width, uint32_t height)
+{
+    char file_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    combine_name (streams[0]->get_file_name (), stream_name, file_name);
+
+    SmartPtr<SVStream> stream = new SVStream (file_name, width, height);
+    XCAM_ASSERT (stream.ptr ());
+    streams.push_back (stream);
+}
+
+static void
+write_in_image (const SVStreams &ins, uint32_t frame_num)
+{
+#if (XCAM_TEST_STREAM_DEBUG) && (XCAM_TEST_OPENCV)
+    char frame_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    std::snprintf (frame_str, XCAM_TEST_MAX_STR_SIZE, "frame:%d", frame_num);
+
+    char img_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    char idx_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        std::snprintf (idx_str, XCAM_TEST_MAX_STR_SIZE, "idx:%d", i);
+        std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "orig_fisheye_%d_%d.jpg", frame_num, i);
+        ins[i]->debug_write_image (img_name, frame_str, idx_str);
+    }
+#else
+    XCAM_UNUSED (ins);
+    XCAM_UNUSED (frame_num);
+#endif
+}
+
+static void
+write_out_image (const SmartPtr<SVStream> &out, uint32_t frame_num)
+{
+#if !XCAM_TEST_STREAM_DEBUG
+    XCAM_UNUSED (frame_num);
+    out->write_buf ();
+#else
+    char frame_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    std::snprintf (frame_str, XCAM_TEST_MAX_STR_SIZE, "frame:%d", frame_num);
+    out->write_buf (frame_str);
+
+#if XCAM_TEST_OPENCV
+    char img_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "%s_%d.jpg", out->get_file_name (), frame_num);
+    out->debug_write_image (img_name, frame_str);
+#endif
+#endif
+}
+
+static XCamReturn
+create_topview_mapper (
+    const SmartPtr<Stitcher> &stitcher, const SmartPtr<SVStream> &stitch,
+    const SmartPtr<SVStream> &topview, SVModule module)
+{
+    BowlModel bowl_model (stitcher->get_bowl_config (), stitch->get_width (), stitch->get_height ());
+    BowlModel::PointMap points;
+
+    float length_mm = 0.0f, width_mm = 0.0f;
+    bowl_model.get_max_topview_area_mm (length_mm, width_mm);
+    XCAM_LOG_INFO ("Max Topview Area (L%.2fmm, W%.2fmm)", length_mm, width_mm);
+
+    bowl_model.get_topview_rect_map (points, topview->get_width (), topview->get_height (), length_mm, width_mm);
+    SmartPtr<GeoMapper> mapper;
+    if (module == SVModuleSoft) {
+        mapper = GeoMapper::create_soft_geo_mapper ();
+    } else if (module == SVModuleGLES) {
+#if HAVE_GLES
+        mapper = GeoMapper::create_gl_geo_mapper ();
+#endif
+    } else if (module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        SmartPtr<VKDevice> dev = stitch->get_vk_device ();
+        XCAM_ASSERT (dev.ptr ());
+        mapper = GeoMapper::create_vk_geo_mapper (dev, "topview-map");
+#endif
+    }
+    XCAM_ASSERT (mapper.ptr ());
+
+    mapper->set_output_size (topview->get_width (), topview->get_height ());
+    mapper->set_lookup_table (points.data (), topview->get_width (), topview->get_height ());
+    topview->set_mapper (mapper);
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static XCamReturn
+remap_topview_buf (const SmartPtr<SVStream> &stitch, const SmartPtr<SVStream> &topview)
+{
+    const SmartPtr<GeoMapper> mapper = topview->get_mapper();
+    XCAM_ASSERT (mapper.ptr ());
+
+    XCamReturn ret = mapper->remap (stitch->get_buf (), topview->get_buf ());
+    if (ret != XCAM_RETURN_NO_ERROR) {
+        XCAM_LOG_ERROR ("remap stitched image to topview failed.");
+        return ret;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static void
+write_image (
+    const SVStreams &ins, const SVStreams &outs, bool save_output, bool save_topview)
+{
+    static uint32_t frame_num = 0;
+
+    write_in_image (ins, frame_num);
+
+    if (save_output)
+        write_out_image (outs[IdxStitch], frame_num);
+
+    if (save_topview) {
+        remap_topview_buf (outs[IdxStitch], outs[IdxTopView]);
+        write_out_image (outs[IdxTopView], frame_num);
+    }
+
+    frame_num++;
+}
+
+static int
+single_frame (
+    const SmartPtr<Stitcher> &stitcher,
+    const SVStreams &ins, const SVStreams &outs,
+    bool save_output, bool save_topview, int loop)
+{
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        CHECK (ins[i]->rewind (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ());
+    }
+
+    VideoBufferList in_buffers;
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        XCamReturn ret = ins[i]->read_buf ();
+        CHECK_EXP (ret == XCAM_RETURN_NO_ERROR, "read buffer from file(%s) failed.", ins[i]->get_file_name ());
+
+        XCAM_ASSERT (ins[i]->get_buf ().ptr ());
+        in_buffers.push_back (ins[i]->get_buf ());
+    }
+
+    while (loop--) {
+        CHECK (stitcher->stitch_buffers (in_buffers, outs[IdxStitch]->get_buf ()), "stitch buffer failed.");
+
+        if (save_output || save_topview)
+            write_image (ins, outs, save_output, save_topview);
+
+        FPS_CALCULATION (surround-view, XCAM_OBJ_DUR_FRAME_NUM);
+    }
+
+    return 0;
+}
+
+static int
+multi_frame (
+    const SmartPtr<Stitcher> &stitcher,
+    const SVStreams &ins, const SVStreams &outs,
+    bool save_output, bool save_topview, int loop)
+{
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    VideoBufferList in_buffers;
+    while (loop--) {
+        for (uint32_t i = 0; i < ins.size (); ++i) {
+            CHECK (ins[i]->rewind (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ());
+        }
+
+        do {
+            in_buffers.clear ();
+
+            for (uint32_t i = 0; i < ins.size (); ++i) {
+                ret = ins[i]->read_buf();
+                if (ret == XCAM_RETURN_BYPASS)
+                    break;
+                CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ());
+
+                in_buffers.push_back (ins[i]->get_buf ());
+            }
+            if (ret == XCAM_RETURN_BYPASS)
+                break;
+
+            CHECK (
+                stitcher->stitch_buffers (in_buffers, outs[IdxStitch]->get_buf ()),
+                "stitch buffer failed.");
+
+            if (save_output || save_topview)
+                write_image (ins, outs, save_output, save_topview);
+
+            FPS_CALCULATION (surround-view, XCAM_OBJ_DUR_FRAME_NUM);
+        } while (true);
+    }
+
+    return 0;
+}
+
+static int
+run_stitcher (
+    const SmartPtr<Stitcher> &stitcher,
+    const SVStreams &ins, const SVStreams &outs,
+    FrameMode frame_mode, bool save_output, bool save_topview, int loop)
+{
+    CHECK (check_streams<SVStreams> (ins), "invalid input streams");
+    CHECK (check_streams<SVStreams> (outs), "invalid output streams");
+
+    int ret = -1;
+    if (frame_mode == FrameSingle)
+        ret = single_frame (stitcher, ins, outs, save_output, save_topview, loop);
+    else if (frame_mode == FrameMulti)
+        ret = multi_frame (stitcher, ins, outs, save_output, save_topview, loop);
+    else
+        XCAM_LOG_ERROR ("invalid frame mode: %d", frame_mode);
+
+    return ret;
+}
+
+static void usage(const char* arg0)
+{
+    printf ("Usage:\n"
+            "%s --module MODULE --input0 input.nv12 --input1 input1.nv12 --input2 input2.nv12 ...\n"
+            "\t--module            processing module, selected from: soft, gles, vulkan\n"
+            "\t--                  read calibration files from exported path $FISHEYE_CONFIG_PATH\n"
+            "\t--input0            input image(NV12)\n"
+            "\t--input1            input image(NV12)\n"
+            "\t--input2            input image(NV12)\n"
+            "\t--input3            input image(NV12)\n"
+            "\t--output            output image(NV12/MP4)\n"
+            "\t--in-w              optional, input width, default: 1280\n"
+            "\t--in-h              optional, input height, default: 800\n"
+            "\t--out-w             optional, output width, default: 1920\n"
+            "\t--out-h             optional, output height, default: 640\n"
+            "\t--topview-w         optional, output width, default: 1280\n"
+            "\t--topview-h         optional, output height, default: 720\n"
+            "\t--scale-mode        optional, scaling mode for geometric mapping,\n"
+            "\t                    select from [singleconst/dualconst/dualcurve], default: singleconst\n"
+            "\t--fm-mode           optional, feature match mode,\n"
+#if HAVE_OPENCV
+            "\t                    select from [none/default/cluster/capi], default: none\n"
+#else
+            "\t                    select from [none], default: none\n"
+#endif
+            "\t--frame-mode        optional, times of buffer reading, select from [single/multi], default: multi\n"
+            "\t--save              optional, save file or not, select from [true/false], default: true\n"
+            "\t--save-topview      optional, save top view video, select from [true/false], default: false\n"
+            "\t--loop              optional, how many loops need to run, default: 1\n"
+            "\t--help              usage\n",
+            arg0);
+}
+
+int main (int argc, char *argv[])
+{
+    uint32_t input_width = 1280;
+    uint32_t input_height = 800;
+    uint32_t output_width = 1920;
+    uint32_t output_height = 640;
+    uint32_t topview_width = 1280;
+    uint32_t topview_height = 720;
+
+    SVStreams ins;
+    SVStreams outs;
+
+    FrameMode frame_mode = FrameMulti;
+    SVModule module = SVModuleNone;
+    GeoMapScaleMode scale_mode = ScaleSingleConst;
+    FeatureMatchMode fm_mode = FMNone;
+
+    int loop = 1;
+    bool save_output = true;
+    bool save_topview = false;
+
+    const struct option long_opts[] = {
+        {"module", required_argument, NULL, 'm'},
+        {"input0", required_argument, NULL, 'i'},
+        {"input1", required_argument, NULL, 'j'},
+        {"input2", required_argument, NULL, 'k'},
+        {"input3", required_argument, NULL, 'l'},
+        {"output", required_argument, NULL, 'o'},
+        {"in-w", required_argument, NULL, 'w'},
+        {"in-h", required_argument, NULL, 'h'},
+        {"out-w", required_argument, NULL, 'W'},
+        {"out-h", required_argument, NULL, 'H'},
+        {"topview-w", required_argument, NULL, 'P'},
+        {"topview-h", required_argument, NULL, 'V'},
+        {"scale-mode", required_argument, NULL, 'S'},
+        {"fm-mode", required_argument, NULL, 'F'},
+        {"frame-mode", required_argument, NULL, 'f'},
+        {"save", required_argument, NULL, 's'},
+        {"save-topview", required_argument, NULL, 't'},
+        {"loop", required_argument, NULL, 'L'},
+        {"help", no_argument, NULL, 'e'},
+        {NULL, 0, NULL, 0},
+    };
+
+    int opt = -1;
+    while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+        switch (opt) {
+        case 'm':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "soft"))
+                module = SVModuleSoft;
+            else if (!strcasecmp (optarg, "gles")) {
+                module = SVModuleGLES;
+            } else if (!strcasecmp (optarg, "vulkan")) {
+                module = SVModuleVulkan;
+            } else {
+                XCAM_LOG_ERROR ("unknown module:%s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'i':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'j':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'k':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'l':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, ins, optarg);
+            break;
+        case 'o':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (SVStream, outs, optarg);
+            break;
+        case 'w':
+            input_width = atoi(optarg);
+            break;
+        case 'h':
+            input_height = atoi(optarg);
+            break;
+        case 'W':
+            output_width = atoi(optarg);
+            break;
+        case 'H':
+            output_height = atoi(optarg);
+            break;
+        case 'P':
+            topview_width = atoi(optarg);
+            break;
+        case 'V':
+            topview_height = atoi(optarg);
+            break;
+        case 'S':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "singleconst"))
+                scale_mode = ScaleSingleConst;
+            else if (!strcasecmp (optarg, "dualconst"))
+                scale_mode = ScaleDualConst;
+            else if (!strcasecmp (optarg, "dualcurve"))
+                scale_mode = ScaleDualCurve;
+            else {
+                XCAM_LOG_ERROR ("GeoMapScaleMode unknown mode: %s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'F':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "none"))
+                fm_mode = FMNone;
+#if HAVE_OPENCV
+            else if (!strcasecmp (optarg, "default"))
+                fm_mode = FMDefault;
+            else if (!strcasecmp (optarg, "cluster"))
+                fm_mode = FMCluster;
+            else if (!strcasecmp (optarg, "capi"))
+                fm_mode = FMCapi;
+#endif
+            else {
+                XCAM_LOG_ERROR ("surround view unsupported feature match mode: %s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 'f':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "single"))
+                frame_mode = FrameSingle;
+            else if (!strcasecmp (optarg, "multi"))
+                frame_mode = FrameMulti;
+            else {
+                XCAM_LOG_ERROR ("FrameMode unknown mode: %s", optarg);
+                usage (argv[0]);
+                return -1;
+            }
+            break;
+        case 's':
+            save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+            break;
+        case 't':
+            save_topview = (strcasecmp (optarg, "false") == 0 ? false : true);
+            break;
+        case 'L':
+            loop = atoi(optarg);
+            break;
+        case 'e':
+            usage (argv[0]);
+            return 0;
+        default:
+            XCAM_LOG_ERROR ("getopt_long return unknown value: %c", opt);
+            usage (argv[0]);
+            return -1;
+        }
+    }
+
+    if (optind < argc || argc < 2) {
+        XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
+        usage (argv[0]);
+        return -1;
+    }
+
+    CHECK_EXP (ins.size () == 4, "surrond view needs 4 input streams");
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        CHECK_EXP (ins[i].ptr (), "input stream is NULL, index:%d", i);
+        CHECK_EXP (strlen (ins[i]->get_file_name ()), "input file name was not set, index:%d", i);
+    }
+
+    CHECK_EXP (outs.size () == 1 && outs[IdxStitch].ptr (), "surrond view needs 1 output stream");
+    CHECK_EXP (strlen (outs[IdxStitch]->get_file_name ()), "output file name was not set");
+
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ());
+    }
+    printf ("output file:\t\t%s\n", outs[IdxStitch]->get_file_name ());
+    printf ("input width:\t\t%d\n", input_width);
+    printf ("input height:\t\t%d\n", input_height);
+    printf ("output width:\t\t%d\n", output_width);
+    printf ("output height:\t\t%d\n", output_height);
+    printf ("topview width:\t\t%d\n", topview_width);
+    printf ("topview height:\t\t%d\n", topview_height);
+    printf ("scaling mode:\t\t%s\n", (scale_mode == ScaleSingleConst) ? "singleconst" :
+            ((scale_mode == ScaleDualConst) ? "dualconst" : "dualcurve"));
+    printf ("feature match:\t\t%s\n", (fm_mode == FMNone) ? "none" :
+            ((fm_mode == FMDefault ) ? "default" : ((fm_mode == FMCluster) ? "cluster" : "capi")));
+    printf ("frame mode:\t\t%s\n", (frame_mode == FrameSingle) ? "singleframe" : "multiframe");
+    printf ("save output:\t\t%s\n", save_output ? "true" : "false");
+    printf ("save topview:\t\t%s\n", save_topview ? "true" : "false");
+    printf ("loop count:\t\t%d\n", loop);
+
+#if HAVE_GLES
+    SmartPtr<EGLBase> egl;
+    if (module == SVModuleGLES) {
+        if (scale_mode == ScaleDualCurve) {
+            XCAM_LOG_ERROR ("GLES module does not support dualcurve scale mode currently");
+            return -1;
+        }
+
+        egl = new EGLBase ();
+        XCAM_ASSERT (egl.ptr ());
+        XCAM_FAIL_RETURN (ERROR, egl->init (), -1, "init EGL failed");
+    }
+#else
+    if (module == SVModuleGLES) {
+        XCAM_LOG_ERROR ("GLES module is unsupported");
+        return -1;
+    }
+#endif
+
+    if (module == SVModuleVulkan) {
+#if HAVE_VULKAN
+        if (scale_mode != ScaleSingleConst) {
+            XCAM_LOG_ERROR ("vulkan module only support singleconst scale mode currently");
+            return -1;
+        }
+
+        SmartPtr<VKDevice> vk_dev = VKDevice::default_device ();
+        for (uint32_t i = 0; i < ins.size (); ++i) {
+            ins[i]->set_vk_device (vk_dev);
+        }
+        XCAM_ASSERT (outs[IdxStitch].ptr ());
+        outs[IdxStitch]->set_vk_device (vk_dev);
+#else
+        XCAM_LOG_ERROR ("vulkan module is unsupported");
+        return -1;
+#endif
+    }
+
+    VideoBufferInfo in_info;
+    in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        ins[i]->set_module (module);
+        ins[i]->set_buf_size (input_width, input_height);
+        CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed");
+        CHECK (ins[i]->open_reader ("rb"), "open input file(%s) failed", ins[i]->get_file_name ());
+    }
+
+    outs[IdxStitch]->set_buf_size (output_width, output_height);
+    if (save_output) {
+        CHECK (outs[IdxStitch]->estimate_file_format (),
+            "%s: estimate file format failed", outs[IdxStitch]->get_file_name ());
+        CHECK (outs[IdxStitch]->open_writer ("wb"), "open output file(%s) failed", outs[IdxStitch]->get_file_name ());
+    }
+
+    SmartPtr<Stitcher> stitcher = create_stitcher (outs[IdxStitch], module);
+    XCAM_ASSERT (stitcher.ptr ());
+
+    CameraInfo cam_info[4];
+    std::string fisheye_config_path = FISHEYE_CONFIG_PATH;
+    const char *env = std::getenv (FISHEYE_CONFIG_ENV_VAR);
+    if (env)
+        fisheye_config_path.assign (env, strlen (env));
+    XCAM_LOG_INFO ("calibration config path:%s", fisheye_config_path.c_str ());
+
+    uint32_t camera_count = ins.size ();
+    for (uint32_t i = 0; i < camera_count; ++i) {
+        if (parse_camera_info (fisheye_config_path.c_str (), i, cam_info[i], camera_count) != 0) {
+            XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i);
+            return -1;
+        }
+    }
+
+    PointFloat3 bowl_coord_offset;
+    centralize_bowl_coord_from_cameras (
+        cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic,
+        cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic,
+        bowl_coord_offset);
+
+    stitcher->set_camera_num (camera_count);
+    for (uint32_t i = 0; i < camera_count; ++i) {
+        stitcher->set_camera_info (i, cam_info[i]);
+    }
+
+    BowlDataConfig bowl;
+    bowl.wall_height = 1800.0f;
+    bowl.ground_length = 3000.0f;
+    bowl.angle_start = 0.0f;
+    bowl.angle_end = 360.0f;
+    stitcher->set_bowl_config (bowl);
+    stitcher->set_output_size (output_width, output_height);
+    stitcher->set_scale_mode (scale_mode);
+    stitcher->set_fm_mode (fm_mode);
+
+    if (save_topview) {
+        add_stream (outs, "topview", topview_width, topview_height);
+        XCAM_ASSERT (outs.size () >= IdxCount);
+
+        CHECK (outs[IdxTopView]->estimate_file_format (),
+            "%s: estimate file format failed", outs[IdxTopView]->get_file_name ());
+        CHECK (outs[IdxTopView]->open_writer ("wb"), "open output file(%s) failed", outs[IdxTopView]->get_file_name ());
+
+        create_topview_mapper (stitcher, outs[IdxStitch], outs[IdxTopView], module);
+    }
+
+    CHECK_EXP (
+        run_stitcher (stitcher, ins, outs, frame_mode, save_output, save_topview, loop) == 0,
+        "run stitcher failed");
+
+    return 0;
+}
diff --git a/tests/test-video-stabilization.cpp b/tests/test-video-stabilization.cpp
index 5280467..7885462 100644
--- a/tests/test-video-stabilization.cpp
+++ b/tests/test-video-stabilization.cpp
@@ -33,7 +33,7 @@
 #if HAVE_OPENCV
 #include <opencv2/opencv.hpp>
 #include <opencv2/core/ocl.hpp>
-#include <ocl/cv_base_class.h>
+#include "ocv/cv_utils.h"
 #endif
 
 using namespace XCam;
@@ -62,10 +62,7 @@
     XCamReturn ret = XCAM_RETURN_NO_ERROR;
 
     SmartPtr<CLVideoStabilizer> video_stab;
-
     SmartPtr<CLContext> context;
-    SmartPtr<BufferPool> buf_pool;
-
     VideoBufferInfo input_buf_info;
     VideoBufferInfo output_buf_info;
     SmartPtr<VideoBuffer> input_buf;
@@ -84,7 +81,6 @@
     const char *gyro_data = "gyro_data.csv";
 
     bool need_save_output = true;
-    double framerate = 30.0;
     int loop = 1;
 
     const struct option long_opts[] = {
@@ -127,7 +123,7 @@
             break;
         case 'H':
             usage (argv[0]);
-            return -1;
+            return 0;
         default:
             printf ("getopt_long return unknown value:%c\n", opt);
             usage (argv[0]);
@@ -201,7 +197,7 @@
 
     input_buf_info.init (input_format, input_width, input_height);
     output_buf_info.init (input_format, output_width, output_height);
-    buf_pool = new CLVideoBufferPool ();
+    SmartPtr<BufferPool> buf_pool = new CLVideoBufferPool ();
     XCAM_ASSERT (buf_pool.ptr ());
     buf_pool->set_video_info (input_buf_info);
     if (!buf_pool->reserve (36)) {
@@ -216,7 +212,7 @@
     cv::VideoWriter writer;
     if (need_save_output) {
         cv::Size dst_size = cv::Size (output_width, output_height);
-        if (!writer.open (file_out_name, CV_FOURCC('X', '2', '6', '4'), framerate, dst_size)) {
+        if (!writer.open (file_out_name, cv::VideoWriter::fourcc ('X', '2', '6', '4'), 30, dst_size)) {
             XCAM_LOG_ERROR ("open file %s failed", file_out_name);
             return -1;
         }
diff --git a/tests/test-vk-handler.cpp b/tests/test-vk-handler.cpp
new file mode 100644
index 0000000..30941fc
--- /dev/null
+++ b/tests/test-vk-handler.cpp
@@ -0,0 +1,340 @@
+/*
+ * test_vk_handler.cpp - test vulkan handler
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Wind Yuan <feng.yuan@intel.com>
+ */
+
+#include "test_common.h"
+#include "test_stream.h"
+
+#include <vulkan/vk_device.h>
+#include <vulkan/vk_copy_handler.h>
+#include <vulkan/vk_geomap_handler.h>
+#include <interface/blender.h>
+
+using namespace XCam;
+
+enum VKType {
+    VKTypeNone    = 0,
+    VKTypeCopy,
+    VKTypeRemap,
+    VKTypeBlender
+};
+
+class VKStream
+    : public Stream
+{
+public:
+    explicit VKStream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+    virtual ~VKStream () {}
+
+    void set_vk_device (SmartPtr<VKDevice> &device) {
+        XCAM_ASSERT (device.ptr ());
+        _device = device;
+    }
+
+    virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
+
+private:
+    SmartPtr<VKDevice>    _device;
+};
+
+typedef std::vector<SmartPtr<VKStream>> VKStreams;
+
+VKStream::VKStream (const char *file_name, uint32_t width, uint32_t height)
+    : Stream (file_name, width, height)
+{
+}
+
+XCamReturn
+VKStream::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _device.ptr(), XCAM_RETURN_ERROR_PARAM,
+        "vulkan device id NULL, please set device first");
+
+    SmartPtr<BufferPool> pool = create_vk_buffer_pool (_device);
+    XCAM_ASSERT (pool.ptr ());
+
+    if (!pool->set_video_info (info)) {
+        XCAM_LOG_ERROR ("set video info failed");
+        return XCAM_RETURN_ERROR_UNKNOWN;
+    }
+
+    if (!pool->reserve (count)) {
+        XCAM_LOG_ERROR ("create buffer pool failed");
+        return XCAM_RETURN_ERROR_MEM;
+    }
+
+    set_buf_pool (pool);
+    return XCAM_RETURN_NO_ERROR;
+}
+
+static void
+calc_hor_flip_table (uint32_t width, uint32_t height, PointFloat2 *&map_table)
+{
+    XCAM_ASSERT (map_table);
+
+    float lut_size[2] = {8, 8};
+    for (uint32_t i = 0; i < height; ++i) {
+        PointFloat2 *line = &map_table[i * width];
+        for (uint32_t j = 0; j < width; j++) {
+            line[j].x = (width - j) * lut_size[0];
+            line[j].y = i * lut_size[1];
+        }
+    }
+}
+
+static void
+print_help (const char *arg0)
+{
+    printf ("Usage:\n"
+            "%s --type TYPE --input0 input.nv12 --input1 input1.nv12 --output output.nv12 ...\n"
+            "\t--type              processing type, selected from: copy, remap, blend\n"
+            "\t--input0            input image(NV12)\n"
+            "\t--input1            input image(NV12)\n"
+            "\t--output            output image(NV12/MP4)\n"
+            "\t--in-w              optional, input width, default: 1280\n"
+            "\t--in-h              optional, input height, default: 800\n"
+            "\t--out-w             optional, output width, default: 1280\n"
+            "\t--out-h             optional, output height, default: 800\n"
+            "\t--save              optional, save file or not, select from [true/false], default: true\n"
+            "\t--loop              optional, how many loops need to run, default: 1\n"
+            "\t--help              usage\n",
+            arg0);
+
+    printf ("Note:\n"
+            "Spirv path Setup Env: $" XCAM_VK_SHADER_PATH "\n"
+            "Generate spirv kernel:\n"
+            "glslangValidator -V -x -o sample.comp.spv sample.comp.sl\n"
+           );
+}
+
+int main (int argc, char **argv)
+{
+    uint32_t input_width = 1280;
+    uint32_t input_height = 800;
+    uint32_t output_width = 1280;
+    uint32_t output_height = 800;
+
+    VKStreams ins;
+    VKStreams outs;
+    VKType type = VKTypeNone;
+
+    int loop = 1;
+    bool save_output = true;
+
+    const struct option long_opts[] = {
+        {"type", required_argument, NULL, 't'},
+        {"input0", required_argument, NULL, 'i'},
+        {"input1", required_argument, NULL, 'j'},
+        {"output", required_argument, NULL, 'o'},
+        {"in-w", required_argument, NULL, 'w'},
+        {"in-h", required_argument, NULL, 'h'},
+        {"out-w", required_argument, NULL, 'W'},
+        {"out-h", required_argument, NULL, 'H'},
+        {"save", required_argument, NULL, 's'},
+        {"loop", required_argument, NULL, 'l'},
+        {"help", no_argument, NULL, 'e'},
+        {NULL, 0, NULL, 0},
+    };
+
+    int opt = -1;
+    while ((opt = getopt_long (argc, argv, "", long_opts, NULL)) != -1) {
+        switch (opt) {
+        case 't':
+            XCAM_ASSERT (optarg);
+            if (!strcasecmp (optarg, "copy"))
+                type = VKTypeCopy;
+            else if (!strcasecmp (optarg, "remap"))
+                type = VKTypeRemap;
+            else if (!strcasecmp (optarg, "blend"))
+                type = VKTypeBlender;
+            else {
+                XCAM_LOG_ERROR ("unknown type:%s", optarg);
+                print_help (argv[0]);
+                return -1;
+            }
+            break;
+        case 'i':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (VKStream, ins, optarg);
+            break;
+        case 'j':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (VKStream, ins, optarg);
+            break;
+        case 'o':
+            XCAM_ASSERT (optarg);
+            PUSH_STREAM (VKStream, outs, optarg);
+            break;
+        case 'w':
+            input_width = atoi(optarg);
+            break;
+        case 'h':
+            input_height = atoi(optarg);
+            break;
+        case 'W':
+            output_width = atoi(optarg);
+            break;
+        case 'H':
+            output_height = atoi(optarg);
+            break;
+        case 's':
+            save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
+            break;
+        case 'l':
+            loop = atoi(optarg);
+            break;
+        case 'e':
+            print_help (argv[0]);
+            return 0;
+        default:
+            XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt);
+            print_help (argv[0]);
+            return -1;
+        }
+    }
+
+    if (optind < argc || argc < 2) {
+        XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
+        print_help (argv[0]);
+        return -1;
+    }
+
+    if (ins.empty () || outs.empty ()) {
+        XCAM_LOG_ERROR ("input or output stream is empty");
+        print_help (argv[0]);
+        return -1;
+    }
+
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ());
+    }
+    printf ("output file:\t\t%s\n", outs[0]->get_file_name ());
+    printf ("input width:\t\t%d\n", input_width);
+    printf ("input height:\t\t%d\n", input_height);
+    printf ("output width:\t\t%d\n", output_width);
+    printf ("output height:\t\t%d\n", output_height);
+    printf ("save output:\t\t%s\n", save_output ? "true" : "false");
+    printf ("loop count:\t\t%d\n", loop);
+
+    SmartPtr<VKDevice> vk_device = VKDevice::default_device ();
+    XCAM_FAIL_RETURN (
+        ERROR, vk_device.ptr(), -1,
+        "Get default VKDevice failed, please check vulkan environment");
+
+    VideoBufferInfo in_info;
+    in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
+    for (uint32_t i = 0; i < ins.size (); ++i) {
+        ins[i]->set_buf_size (input_width, input_height);
+        ins[i]->set_vk_device (vk_device);
+        CHECK (ins[i]->create_buf_pool (in_info, 4), "create buffer pool failed");
+        CHECK (ins[i]->open_reader ("rb"), "open input file(%s) failed", ins[i]->get_file_name ());
+    }
+
+    VideoBufferInfo out_info;
+    out_info.init (V4L2_PIX_FMT_NV12, output_width, output_height);
+    outs[0]->set_buf_size (output_width, output_height);
+    if (save_output) {
+        CHECK (outs[0]->estimate_file_format (), "%s: estimate file format failed", outs[0]->get_file_name ());
+        CHECK (outs[0]->open_writer ("wb"), "open output file(%s) failed", outs[0]->get_file_name ());
+    }
+
+    switch (type) {
+    case VKTypeCopy: {
+        SmartPtr<VKCopyHandler> copyer = new VKCopyHandler (vk_device, "vk-copy");
+        XCAM_ASSERT (copyer.ptr ());
+
+        Rect in_area = Rect (0, 0, input_width, input_height);
+        Rect out_area = Rect (0, 0, output_width, output_height);
+        XCAM_ASSERT (in_area.width == out_area.width && in_area.height == out_area.height);
+        copyer->set_copy_area (0, in_area, out_area);
+        copyer->set_out_video_info (out_info);
+
+        CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed", ins[0]->get_file_name ());
+        for (int i = 0; i < loop; ++i) {
+            CHECK (copyer->copy (ins[0]->get_buf (), outs[0]->get_buf ()), "copy buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (vk-copy, XCAM_OBJ_DUR_FRAME_NUM);
+        }
+        break;
+    }
+    case VKTypeRemap: {
+        SmartPtr<VKGeoMapHandler> mapper = new VKGeoMapHandler (vk_device, "vk-remap");
+        XCAM_ASSERT (mapper.ptr ());
+        mapper->set_output_size (output_width, output_height);
+
+        uint32_t lut_width = XCAM_ALIGN_UP (output_width, 8) / 8;
+        uint32_t lut_height = XCAM_ALIGN_UP (output_height, 8) / 8;
+        PointFloat2 *map_table = new PointFloat2[lut_width * lut_height];
+        calc_hor_flip_table (lut_width, lut_height, map_table);
+        mapper->set_lookup_table (map_table, lut_width, lut_height);
+        delete [] map_table;
+
+        CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed", ins[0]->get_file_name ());
+        for (int i = 0; i < loop; ++i) {
+            CHECK (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), "remap buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (vk-remap, XCAM_OBJ_DUR_FRAME_NUM);
+        }
+        break;
+    }
+    case VKTypeBlender: {
+        CHECK_EXP (ins.size () == 2, "Error: blender needs 2 input files.");
+        SmartPtr<Blender> blender = Blender::create_vk_blender (vk_device);
+        XCAM_ASSERT (blender.ptr ());
+        blender->set_output_size (output_width, output_height);
+
+        Rect area;
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = output_width;
+        area.height = output_height;
+        blender->set_merge_window (area);
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = input_width;
+        area.height = input_height;
+        blender->set_input_merge_area (area, 0);
+        area.pos_x = 0;
+        area.pos_y = 0;
+        area.width = input_width;
+        area.height = input_height;
+        blender->set_input_merge_area (area, 1);
+
+        CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
+        CHECK (ins[1]->read_buf(), "read buffer from file(%s) failed.", ins[1]->get_file_name ());
+        for (int i = 0; i < loop; ++i) {
+            CHECK (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), "blend buffer failed");
+            if (save_output)
+                outs[0]->write_buf ();
+            FPS_CALCULATION (vk-blend, XCAM_OBJ_DUR_FRAME_NUM);
+        }
+        break;
+    }
+    default: {
+        XCAM_LOG_ERROR ("unsupported type:%d", type);
+        print_help (argv[0]);
+        return -1;
+    }
+    }
+
+    return 0;
+}
diff --git a/tests/test_common.h b/tests/test_common.h
index 9ca75e3..3052a60 100644
--- a/tests/test_common.h
+++ b/tests/test_common.h
@@ -24,6 +24,7 @@
 
 #include <unistd.h>
 #include <getopt.h>
+#include <string>
 
 #define TEST_CAMERA_POSITION_OFFSET_X 2000
 
@@ -60,6 +61,8 @@
 #define DEFAULT_HYBRID_3A_LIB "/usr/lib/xcam/plugins/3a/libxcam_3a_hybrid.so"
 #define DEFAULT_SMART_ANALYSIS_LIB_DIR "/usr/lib/xcam/plugins/smart"
 
+#define FISHEYE_CONFIG_PATH "./calib_params/"
+#define FISHEYE_CONFIG_ENV_VAR "FISHEYE_CONFIG_PATH"
 
 #define FPS_CALCULATION(objname, count) XCAM_STATIC_FPS_CALCULATION(objname, count)
 
diff --git a/tests/test_stream.h b/tests/test_stream.h
new file mode 100644
index 0000000..6bbaf8a
--- /dev/null
+++ b/tests/test_stream.h
@@ -0,0 +1,333 @@
+/*
+ * test_stream.h - test stream class
+ *
+ *  Copyright (c) 2018 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Yinhang Liu <yinhangx.liu@intel.com>
+ */
+
+#ifndef XCAM_TEST_STREAM_H
+#define XCAM_TEST_STREAM_H
+
+#include <buffer_pool.h>
+#include <image_file_handle.h>
+#if (!defined(ANDROID) && (HAVE_OPENCV))
+#include "ocv/cv_utils.h"
+#endif
+
+#define XCAM_TEST_STREAM_DEBUG 0
+
+#define XCAM_TEST_MAX_STR_SIZE 256
+
+#if (!defined(ANDROID) && (HAVE_OPENCV))
+#define XCAM_TEST_OPENCV 1
+#else
+#define XCAM_TEST_OPENCV 0
+#endif
+
+#if XCAM_TEST_OPENCV
+const static cv::Scalar color = cv::Scalar (0, 0, 255);
+const static int fontFace = cv::FONT_HERSHEY_COMPLEX;
+#endif
+
+namespace XCam {
+
+enum TestFileFormat {
+    FileNone,
+    FileNV12,
+    FileMP4
+};
+
+#define PUSH_STREAM(Type, streams, file_name) \
+    {                                                  \
+        SmartPtr<Type> stream = new Type (file_name);  \
+        XCAM_ASSERT (stream.ptr ());                   \
+        streams.push_back (stream);                    \
+    }
+
+template <typename TType>
+XCamReturn check_streams (const TType &streams)
+{
+    for (uint32_t i = 0; i < streams.size (); ++i) {
+        if (!streams[i].ptr()) {
+            XCAM_LOG_ERROR ("streams[%d] ptr is NULL", i);
+            return XCAM_RETURN_ERROR_PARAM;
+        }
+
+        XCAM_FAIL_RETURN (
+            ERROR, streams[i]->get_width () && streams[i]->get_height (), XCAM_RETURN_ERROR_PARAM,
+            "streams[%d]: invalid parameters width:%d height:%d, please set buffer size first",
+            i, streams[i]->get_width (), streams[i]->get_height ());
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+class Stream {
+public:
+    explicit Stream (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
+    virtual ~Stream ();
+
+    void set_buf_size (uint32_t width, uint32_t height);
+    uint32_t get_width () const {
+        return _width;
+    }
+    uint32_t get_height () const {
+        return _height;
+    }
+    SmartPtr<VideoBuffer> &get_buf () {
+        return _buf;
+    }
+    const char *get_file_name () const {
+        return _file_name;
+    }
+    XCamReturn estimate_file_format ();
+
+    XCamReturn open_reader (const char *option);
+    XCamReturn open_writer (const char *option);
+    XCamReturn close ();
+    XCamReturn rewind ();
+
+    XCamReturn read_buf ();
+    XCamReturn write_buf (char *frame_str = NULL);
+    virtual XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count) = 0;
+
+#if XCAM_TEST_OPENCV
+    void debug_write_image (char *img_name, char *frame_str = NULL, char *idx_str = NULL);
+#endif
+
+protected:
+    void set_buf_pool (const SmartPtr<BufferPool> &pool) {
+        _pool = pool;
+    }
+
+private:
+#if XCAM_TEST_OPENCV
+    XCamReturn cv_open_writer ();
+    void cv_write_buf (char *frame_str = NULL);
+#endif
+
+private:
+    XCAM_DEAD_COPY (Stream);
+
+private:
+    char                    *_file_name;
+    uint32_t                 _width;
+    uint32_t                 _height;
+
+    SmartPtr<VideoBuffer>    _buf;
+    SmartPtr<BufferPool>     _pool;
+
+    ImageFileHandle          _file;
+#if XCAM_TEST_OPENCV
+    cv::VideoWriter          _writer;
+#endif
+    TestFileFormat           _format;
+};
+
+Stream::Stream (const char *file_name, uint32_t width, uint32_t height)
+    : _file_name (NULL)
+    , _width (width)
+    , _height (height)
+    , _format (FileNV12)
+{
+    if (file_name)
+        _file_name = strndup (file_name, XCAM_TEST_MAX_STR_SIZE);
+}
+
+Stream::~Stream ()
+{
+    _file.close ();
+
+    if (_file_name) {
+        xcam_free (_file_name);
+        _file_name = NULL;
+    }
+}
+
+void
+Stream::set_buf_size (uint32_t width, uint32_t height)
+{
+    _width = width;
+    _height = height;
+}
+
+XCamReturn
+Stream::open_reader (const char *option)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _format == FileNV12, XCAM_RETURN_ERROR_PARAM,
+        "stream(%s) only support NV12 input format", _file_name);
+
+    if (_file.open (_file_name, option) != XCAM_RETURN_NO_ERROR) {
+        XCAM_LOG_ERROR ("stream(%s) open failed", _file_name);
+        return XCAM_RETURN_ERROR_FILE;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+Stream::open_writer (const char *option)
+{
+    XCAM_ASSERT (_format != FileNone);
+
+    if (_format == FileNV12) {
+        if (_file.open (_file_name, option) != XCAM_RETURN_NO_ERROR) {
+            XCAM_LOG_ERROR ("stream(%s) open failed", _file_name);
+            return XCAM_RETURN_ERROR_FILE;
+        }
+    } else if (_format == FileMP4) {
+#if XCAM_TEST_OPENCV
+        XCamReturn ret = cv_open_writer ();
+        XCAM_FAIL_RETURN (
+            ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "stream(%s) cv open writer failed", _file_name);
+#else
+        XCAM_LOG_ERROR ("stream(%s) unsupported MP4 format without opencv", _file_name);
+        return XCAM_RETURN_ERROR_PARAM;
+#endif
+    } else {
+        XCAM_LOG_ERROR ("stream(%s) invalid file format: %d", _file_name, (int)_format);
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+Stream::close ()
+{
+    return _file.close ();
+}
+
+XCamReturn
+Stream::rewind ()
+{
+    return _file.rewind ();
+}
+
+XCamReturn
+Stream::read_buf ()
+{
+    XCAM_ASSERT (_pool.ptr ());
+
+    _buf = _pool->get_buffer (_pool);
+    XCAM_ASSERT (_buf.ptr ());
+
+    return _file.read_buf (_buf);
+}
+
+XCamReturn
+Stream::write_buf (char *frame_str) {
+    if (_format == FileNV12) {
+        _file.write_buf (_buf);
+    } else if (_format == FileMP4) {
+#if XCAM_TEST_OPENCV
+        cv_write_buf (frame_str);
+#else
+        XCAM_UNUSED (frame_str);
+        XCAM_LOG_ERROR ("stream(%s) unsupported MP4 format without opencv", _file_name);
+        return XCAM_RETURN_ERROR_PARAM;
+#endif
+    } else {
+        XCAM_LOG_ERROR ("stream(%s) invalid file format: %d", _file_name, (int)_format);
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+Stream::estimate_file_format ()
+{
+    XCAM_ASSERT (get_file_name ());
+
+    char suffix[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
+    const char *ptr = strrchr (get_file_name (), '.');
+    snprintf (suffix, XCAM_TEST_MAX_STR_SIZE, "%s", ptr + 1);
+
+    if (!strcasecmp (suffix, "nv12")) {
+        _format = FileNV12;
+    } else if (!strcasecmp (suffix, "mp4")) {
+#if XCAM_TEST_OPENCV
+        _format = FileMP4;
+#else
+        XCAM_LOG_ERROR ("stream(%s) unsupported MP4 format without opencv", _file_name);
+        return XCAM_RETURN_ERROR_PARAM;
+#endif
+    } else {
+        XCAM_LOG_ERROR ("stream(%s) invalid file format: %s", _file_name, suffix);
+        return XCAM_RETURN_ERROR_PARAM;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+#if XCAM_TEST_OPENCV
+XCamReturn
+Stream::cv_open_writer ()
+{
+    XCAM_FAIL_RETURN (
+        ERROR, _width && _height, XCAM_RETURN_ERROR_PARAM,
+        "stream(%s) invalid size width:%d height:%d", _file_name, _width, _height);
+
+    cv::Size frame_size = cv::Size (_width, _height);
+    if (!_writer.open (_file_name, cv::VideoWriter::fourcc ('X', '2', '6', '4'), 30, frame_size)) {
+        XCAM_LOG_ERROR ("stream(%s) open file failed", _file_name);
+        return XCAM_RETURN_ERROR_FILE;
+    }
+
+    return XCAM_RETURN_NO_ERROR;
+}
+
+void
+Stream::cv_write_buf (char *frame_str)
+{
+    cv::Mat mat;
+
+#if XCAM_TEST_STREAM_DEBUG
+    convert_to_mat (_buf, mat);
+    cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false);
+#else
+    XCAM_UNUSED (frame_str);
+#endif
+
+    if (_writer.isOpened ()) {
+        if (mat.empty())
+            convert_to_mat (_buf, mat);
+
+        _writer.write (mat);
+    }
+}
+
+void
+Stream::debug_write_image (char *img_name, char *frame_str, char *idx_str)
+{
+    XCAM_ASSERT (img_name);
+
+    cv::Mat mat;
+    convert_to_mat (_buf, mat);
+
+    if(frame_str)
+        cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false);
+    if(idx_str)
+        cv::putText (mat, idx_str, cv::Point(20, 110), fontFace, 2.0, color, 2, 8, false);
+
+    cv::imwrite (img_name, mat);
+}
+#endif
+
+}
+#endif // XCAM_TEST_STREAM_H
diff --git a/tools/cl-double-quotation.sh b/tools/add-quotation-marks.sh
similarity index 65%
rename from tools/cl-double-quotation.sh
rename to tools/add-quotation-marks.sh
index 5a77a67..3c669f5 100755
--- a/tools/cl-double-quotation.sh
+++ b/tools/add-quotation-marks.sh
@@ -1,12 +1,12 @@
 #! /bin/sh
-# Add double quotation marks on cl file, this script will
-# be called in top_srcdir/clx_kernel/Makefile.am
+# Add double quotation marks on source file
+# Usage: add-quotation-marks.sh <src_file> <dst_file>
 
-CL_FILE=$1
-CLX_FILE=$2
+SRC_FILE=$1
+DST_FILE=$2
 
 if [ $# -ne 2 ]; then
-    echo "Usage: $0 <cl_file> <clx_file>"
+    echo "Usage: $0 <src_file> <dst_file>"
     exit 1
 fi
 
@@ -32,15 +32,15 @@
             }
         }
     }
-    ' $CL_FILE > $CLX_FILE.tmp
+    ' $SRC_FILE > $DST_FILE.tmp
 
 ret=$?
 if [ $ret != 0 ]; then
-    rm -rf $CLX_FILE.tmp
-    echo "Add double quotation marks on $CL_FILE failed"
+    rm -rf $DST_FILE.tmp
+    echo "Add double quotation marks on $SRC_FILE failed"
     exit 1
 fi
 
-mv $CLX_FILE.tmp $CLX_FILE
+mv $DST_FILE.tmp $DST_FILE
 
-echo "Add double quotation marks on $CL_FILE done"
+echo "Add double quotation marks on $SRC_FILE done"
diff --git a/wrapper/Makefile.am b/wrapper/Makefile.am
index 63dbffd..cac6ded 100644
--- a/wrapper/Makefile.am
+++ b/wrapper/Makefile.am
@@ -1,8 +1,5 @@
-
 if ENABLE_GST
 GST_DIR = gstreamer
-else
-GST_DIR =
 endif
 
 SUBDIRS = $(GST_DIR)
diff --git a/wrapper/gstreamer/Makefile.am b/wrapper/gstreamer/Makefile.am
index 8a47a6f..cc0f7d8 100644
--- a/wrapper/gstreamer/Makefile.am
+++ b/wrapper/gstreamer/Makefile.am
@@ -2,135 +2,117 @@
 SUBDIRS = interface
 endif
 
-plugin_LTLIBRARIES = \
-    libgstxcamsrc.la \
+plugin_LTLIBRARIES = libgstxcamsrc.la
+
+if HAVE_LIBCL
+plugin_LTLIBRARIES += libgstxcamfilter.la
+endif
+
+XCAM_GST_CXXFLAGS = \
+    $(XCAM_CXXFLAGS)                  \
+    $(GST_CFLAGS)                     \
+    -I$(top_srcdir)/xcore             \
+    -I$(top_srcdir)/modules           \
+    -I$(top_srcdir)/wrapper/gstreamer \
+    $(NULL)
+
+XCAM_GST_LIBS = \
+    $(GST_LIBS)                           \
+    $(GST_VIDEO_LIBS)                     \
+    $(GST_ALLOCATOR_LIBS)                 \
+    $(top_builddir)/xcore/libxcam_core.la \
     $(NULL)
 
 if HAVE_LIBCL
-plugin_LTLIBRARIES += \
-    libgstxcamfilter.la \
-    $(NULL)
+XCAM_GST_LIBS += $(top_builddir)/modules/ocl/libxcam_ocl.la
 endif
 
-XCORE_DIR = $(top_srcdir)/xcore
-MODULES_DIR = $(top_srcdir)/modules
-
-XCORE_LA = $(top_builddir)/xcore/libxcam_core.la
-
-if ENABLE_IA_AIQ
-XCAM_INTERFACE_DIR = -I$(top_srcdir)/wrapper/gstreamer/interface
-XCAM_INTERFACE_LA = $(top_builddir)/wrapper/gstreamer/interface/libgstxcaminterface.la
-else
-XCAM_INTERFACE_DIR =
-XCAM_INTERFACE_LA =
-endif
-
-XCAMGST_CXXFLAGS = $(XCAM_CXXFLAGS)
-XCAMGST_LIBS = \
-    $(NULL)
-
 if HAVE_LIBDRM
-XCAMGST_CXXFLAGS += $(LIBDRM_CFLAGS)
-XCAMGST_LIBS += $(LIBDRM_LIBS)
+XCAM_GST_CXXFLAGS += $(LIBDRM_CFLAGS)
+XCAM_GST_LIBS += $(LIBDRM_LIBS)
 endif
 
-if USE_LOCAL_ATOMISP
-XCAMGST_CXXFLAGS += -I$(top_srcdir)/ext/atomisp
-endif
-
-XCAMGST_CXXFLAGS += \
-    -I$(XCORE_DIR)   \
-    -I$(MODULES_DIR) \
-    $(NULL)
-
 # Note: plugindir is set in configure
 plugindir="$(libdir)/gstreamer-1.0"
 
 # sources used to compile this plug-in
 libgstxcamsrc_la_SOURCES = \
-    gstxcambuffermeta.cpp  \
-    gstxcambufferpool.cpp  \
-    main_dev_manager.cpp   \
-    gstxcamsrc.cpp         \
+    gstxcambuffermeta.cpp \
+    gstxcambufferpool.cpp \
+    main_dev_manager.cpp  \
+    gstxcamsrc.cpp        \
     $(NULL)
 
 # compiler and linker flags used to compile this plugin, set in configure.ac
-libgstxcamsrc_la_CXXFLAGS = \
-    $(GST_CFLAGS) $(XCAMGST_CXXFLAGS)  \
-    -I$(top_srcdir)/wrapper/gstreamer  \
-    $(XCAM_INTERFACE_DIR)              \
+XCAM_SRC_CXXFLAGS = \
+    $(XCAM_GST_CXXFLAGS) \
     $(NULL)
 
-libgstxcamsrc_la_LIBADD = $(XCAMGST_LIBS) \
-    $(XCAM_INTERFACE_LA)              \
-    $(XCORE_LA) $(GST_ALLOCATOR_LIBS) \
-    $(GST_VIDEO_LIBS) $(GST_LIBS)     \
+XCAM_SRC_LIBS = \
+    $(XCAM_GST_LIBS) \
+    $(NULL)
+
+if USE_LOCAL_ATOMISP
+XCAM_SRC_CXXFLAGS += -I$(top_srcdir)/ext/atomisp
+endif
+
+if ENABLE_IA_AIQ
+XCAM_SRC_CXXFLAGS += -I$(top_srcdir)/wrapper/gstreamer/interface
+XCAM_SRC_LIBS += \
+    $(top_builddir)/modules/isp/libxcam_isp.la                          \
+    $(top_builddir)/wrapper/gstreamer/interface/libgstxcaminterface.la \
+    $(NULL)
+endif
+
+libgstxcamsrc_la_CXXFLAGS = \
+    $(XCAM_SRC_CXXFLAGS) \
+    $(NULL)
+
+libgstxcamsrc_la_LIBADD = \
+    $(XCAM_SRC_LIBS) \
     $(NULL)
 
 libgstxcamsrc_la_LDFLAGS = \
-    -module -avoid-version         \
-    $(PTHREAD_LDFLAGS) $(XCORE_LA) \
+    -module -avoid-version \
     $(NULL)
 
 libgstxcamsrc_la_LIBTOOLFLAGS = --tag=disable-static
 
-if ENABLE_IA_AIQ
-ISP_LA = $(top_builddir)/modules/isp/libxcam_isp.la
-libgstxcamsrc_la_LIBADD += $(ISP_LA)
-libgstxcamsrc_la_LDFLAGS += $(ISP_LA)
-endif
-
 if HAVE_LIBCL
-OCL_LA = $(top_builddir)/modules/ocl/libxcam_ocl.la
-
-libgstxcamsrc_la_LIBADD += $(OCL_LA)
-libgstxcamsrc_la_LDFLAGS += $(OCL_LA)
-
 libgstxcamfilter_la_SOURCES = \
-    gstxcambuffermeta.cpp  \
-    main_pipe_manager.cpp  \
-    gstxcamfilter.cpp      \
+    gstxcambuffermeta.cpp \
+    main_pipe_manager.cpp \
+    gstxcamfilter.cpp     \
     $(NULL)
 
 libgstxcamfilter_la_CXXFLAGS = \
-    $(GST_CFLAGS) $(XCAMGST_CXXFLAGS) \
-    -I$(top_srcdir)/wrapper/gstreamer \
+    $(XCAM_GST_CXXFLAGS) \
     $(NULL)
 
 libgstxcamfilter_la_LIBADD = \
-    $(XCAMGST_LIBS)        \
-    $(XCORE_LA) $(OCL_LA)  \
-    $(GST_ALLOCATOR_LIBS)  \
-    $(GST_VIDEO_LIBS)      \
-    $(GST_LIBS)            \
+    $(XCAM_GST_LIBS) \
     $(NULL)
 
 libgstxcamfilter_la_LDFLAGS = \
-    -module -avoid-version    \
-    $(XCORE_LA) $(OCL_LA)     \
+    -module -avoid-version \
     $(NULL)
 
 libgstxcamfilter_la_LIBTOOLFLAGS = --tag=disable-static
 endif
 
-# headers we need but don't want installed
+# headers we need but do not want installed
 noinst_HEADERS = \
-    gst_xcam_utils.h  \
+    gst_xcam_utils.h    \
+    gstxcambufferpool.h \
+    gstxcambuffermeta.h \
+    main_dev_manager.h  \
+    gstxcamsrc.h        \
     $(NULL)
 
-if ENABLE_IA_AIQ
-noinst_HEADERS += \
-    gstxcambufferpool.h  \
-    gstxcambuffermeta.h  \
-    main_dev_manager.h   \
-    gstxcamsrc.h         \
-    $(NULL)
-endif
-
 if HAVE_LIBCL
 noinst_HEADERS += \
-    gstxcambuffermeta.h  \
-    main_pipe_manager.h  \
-    gstxcamfilter.h      \
+    gstxcambuffermeta.h \
+    main_pipe_manager.h \
+    gstxcamfilter.h     \
     $(NULL)
 endif
diff --git a/wrapper/gstreamer/gstxcamfilter.cpp b/wrapper/gstreamer/gstxcamfilter.cpp
index 21b38d8..a8cd595 100644
--- a/wrapper/gstreamer/gstxcamfilter.cpp
+++ b/wrapper/gstreamer/gstxcamfilter.cpp
@@ -42,7 +42,6 @@
 #define DEFAULT_PROP_STITCH_SCALE_MODE      CLBlenderScaleLocal
 #define DEFAULT_PROP_STITCH_FISHEYE_MAP     FALSE
 #define DEFAULT_PROP_STITCH_LSC             FALSE
-#define DEFAULT_PROP_STITCH_FM_OCL          FALSE
 #define DEFAULT_PROP_STITCH_RES_MODE        StitchRes1080P
 
 XCAM_BEGIN_DECLARE
@@ -61,7 +60,6 @@
     PROP_STITCH_SCALE_MODE,
     PROP_STITCH_FISHEYE_MAP,
     PROP_STITCH_LSC,
-    PROP_STITCH_FM_OCL,
     PROP_STITCH_RES_MODE
 };
 
@@ -307,13 +305,6 @@
         g_param_spec_boolean ("stitch-lsc", "stitch enable lens shading correction", "Enable Lens Shading Correction",
                               DEFAULT_PROP_STITCH_LSC, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
 
-#if HAVE_OPENCV
-    g_object_class_install_property (
-        gobject_class, PROP_STITCH_FM_OCL,
-        g_param_spec_boolean ("stitch-fm-ocl", "stitch enable ocl for feature match", "Enable ocl for feature match",
-                              DEFAULT_PROP_STITCH_FM_OCL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
-#endif
-
     g_object_class_install_property (
         gobject_class, PROP_STITCH_RES_MODE,
         g_param_spec_enum ("stitch-res-mode", "stitch resolution mode", "Stitch Resolution Mode",
@@ -355,7 +346,6 @@
     xcamfilter->stitch_enable_seam = DEFAULT_PROP_STITCH_ENABLE_SEAM;
     xcamfilter->stitch_fisheye_map = DEFAULT_PROP_STITCH_FISHEYE_MAP;
     xcamfilter->stitch_lsc = DEFAULT_PROP_STITCH_LSC;
-    xcamfilter->stitch_fm_ocl = DEFAULT_PROP_STITCH_FM_OCL;
     xcamfilter->stitch_scale_mode = DEFAULT_PROP_STITCH_SCALE_MODE;
     xcamfilter->stitch_res_mode = DEFAULT_PROP_STITCH_RES_MODE;
 
@@ -363,8 +353,9 @@
     xcamfilter->cached_buf_num = 0;
 
     XCAM_CONSTRUCTOR (xcamfilter->pipe_manager, SmartPtr<MainPipeManager>);
-    xcamfilter->pipe_manager = new MainPipeManager;
-    XCAM_ASSERT (xcamfilter->pipe_manager.ptr ());
+    SmartPtr<MainPipeManager> pipe_manager = new MainPipeManager;
+    XCAM_ASSERT (pipe_manager.ptr ());
+    xcamfilter->pipe_manager = pipe_manager;
 }
 
 static void
@@ -423,11 +414,6 @@
     case PROP_STITCH_LSC:
         xcamfilter->stitch_lsc = g_value_get_boolean (value);
         break;
-#if HAVE_OPENCV
-    case PROP_STITCH_FM_OCL:
-        xcamfilter->stitch_fm_ocl = g_value_get_boolean (value);
-        break;
-#endif
     case PROP_STITCH_RES_MODE:
         xcamfilter->stitch_res_mode = (StitchResMode) g_value_get_enum (value);
         break;
@@ -479,11 +465,6 @@
     case PROP_STITCH_LSC:
         g_value_set_boolean (value, xcamfilter->stitch_lsc);
         break;
-#if HAVE_OPENCV
-    case PROP_STITCH_FM_OCL:
-        g_value_set_boolean (value, xcamfilter->stitch_fm_ocl);
-        break;
-#endif
     case PROP_STITCH_RES_MODE:
         g_value_set_enum (value, xcamfilter->stitch_res_mode);
         break;
@@ -508,7 +489,6 @@
 
     SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager;
     SmartPtr<SmartAnalyzer> smart_analyzer;
-    SmartPtr<CLPostImageProcessor> image_processor;
 
     SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR);
     if (!smart_handlers.empty ()) {
@@ -530,7 +510,7 @@
         }
     }
 
-    image_processor = new CLPostImageProcessor ();
+    SmartPtr<CLPostImageProcessor> image_processor = new CLPostImageProcessor ();
     XCAM_ASSERT (image_processor.ptr ());
     image_processor->set_stats_callback (pipe_manager);
     image_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) xcamfilter->defog_mode);
@@ -571,8 +551,10 @@
     pipe_manager->add_image_processor (image_processor);
     pipe_manager->set_image_processor (image_processor);
 
-    xcamfilter->buf_pool = new CLVideoBufferPool ();
-    XCAM_ASSERT (xcamfilter->buf_pool.ptr ());
+    SmartPtr<BufferPool> pool = new CLVideoBufferPool ();
+    XCAM_ASSERT (pool.ptr ());
+    xcamfilter->buf_pool = pool;
+
     if (xcamfilter->copy_mode == COPY_MODE_DMA) {
         XCAM_LOG_WARNING ("CLVideoBuffer doesn't support DMA copy mode, switch to CPU copy mode");
         xcamfilter->copy_mode = COPY_MODE_CPU;
@@ -735,8 +717,8 @@
     if (xcamfilter->enable_stitch) {
         processor->set_image_stitch (
             xcamfilter->enable_stitch, xcamfilter->stitch_enable_seam, xcamfilter->stitch_scale_mode,
-            xcamfilter->stitch_fisheye_map, xcamfilter->stitch_lsc, xcamfilter->stitch_fm_ocl,
-            GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info), (uint32_t) xcamfilter->stitch_res_mode);
+            xcamfilter->stitch_fisheye_map, xcamfilter->stitch_lsc, GST_VIDEO_INFO_WIDTH (&out_info),
+            GST_VIDEO_INFO_HEIGHT (&out_info), (uint32_t) xcamfilter->stitch_res_mode);
         XCAM_LOG_INFO ("xcamfilter stitch output size width:%d height:%d",
                        GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info));
     }
@@ -1001,5 +983,5 @@
     VERSION,
     GST_LICENSE_UNKNOWN,
     "libxcamfilter",
-    "https://github.com/01org/libxcam"
+    "https://github.com/intel/libxcam"
 )
diff --git a/wrapper/gstreamer/gstxcamfilter.h b/wrapper/gstreamer/gstxcamfilter.h
index fddfed2..bd26aa9 100644
--- a/wrapper/gstreamer/gstxcamfilter.h
+++ b/wrapper/gstreamer/gstxcamfilter.h
@@ -84,7 +84,6 @@
     gboolean                                 enable_stitch;
     gboolean                                 stitch_enable_seam;
     gboolean                                 stitch_fisheye_map;
-    gboolean                                 stitch_fm_ocl;
     gboolean                                 stitch_lsc;
     XCam::CLBlenderScaleMode                 stitch_scale_mode;
     StitchResMode                            stitch_res_mode;
diff --git a/wrapper/gstreamer/gstxcamsrc.cpp b/wrapper/gstreamer/gstxcamsrc.cpp
index cb3a6f4..0292c26 100644
--- a/wrapper/gstreamer/gstxcamsrc.cpp
+++ b/wrapper/gstreamer/gstxcamsrc.cpp
@@ -41,7 +41,7 @@
 #include "gstxcaminterface.h"
 #include "dynamic_analyzer_loader.h"
 #include "isp/hybrid_analyzer_loader.h"
-#include "x3a_analyze_tuner.h"
+#include "isp/iq/x3a_analyze_tuner.h"
 #include "isp/isp_poll_thread.h"
 #endif
 #if HAVE_LIBCL
@@ -83,6 +83,8 @@
 #define DEFAULT_PROP_IMAGE_PROCESSOR    ISP_IMAGE_PROCESSOR
 #elif HAVE_LIBCL
 #define DEFAULT_PROP_IMAGE_PROCESSOR    CL_IMAGE_PROCESSOR
+#else
+#define DEFAULT_PROP_IMAGE_PROCESSOR    NONE_IMAGE_PROCESSOR
 #endif
 #if HAVE_LIBCL
 #define DEFAULT_PROP_WDR_MODE           NONE_WDR
@@ -633,8 +635,11 @@
     xcamsrc->xcam_video_info.init (DEFAULT_PROP_PIXELFORMAT, DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT);
     xcamsrc->image_processor_type = DEFAULT_PROP_IMAGE_PROCESSOR;
     xcamsrc->analyzer_type = DEFAULT_PROP_ANALYZER;
+
     XCAM_CONSTRUCTOR (xcamsrc->device_manager, SmartPtr<MainDeviceManager>);
-    xcamsrc->device_manager = new MainDeviceManager;
+    SmartPtr<MainDeviceManager> device_manager = new MainDeviceManager;
+    XCAM_ASSERT (device_manager.ptr ());
+    xcamsrc->device_manager = device_manager;
 }
 
 static void
@@ -913,11 +918,6 @@
     SmartPtr<ImageProcessor> isp_processor;
     SmartPtr<IspController> isp_controller;
 #endif
-#if HAVE_LIBCL
-    SmartPtr<SmartAnalyzer> smart_analyzer;
-    SmartPtr<CL3aImageProcessor> cl_processor;
-    SmartPtr<CLPostImageProcessor> cl_post_processor;
-#endif
     SmartPtr<V4l2Device> capture_device;
     SmartPtr<V4l2SubDevice> event_device;
     SmartPtr<PollThread> poll_thread;
@@ -980,13 +980,15 @@
         XCAM_ASSERT (isp_processor.ptr ());
         device_manager->add_image_processor (isp_processor);
 #endif
-        cl_processor = new CL3aImageProcessor ();
+
+        SmartPtr<CL3aImageProcessor> cl_processor = new CL3aImageProcessor ();
+        XCAM_ASSERT (cl_processor.ptr ());
         cl_processor->set_stats_callback (device_manager);
         if(xcamsrc->wdr_mode_type != NONE_WDR)
         {
             cl_processor->set_gamma (false);
             xcamsrc->in_format = V4L2_PIX_FMT_SGRBG12;
-            cl_processor->set_3a_stats_bits(12);
+            cl_processor->set_3a_stats_bits (12);
             setenv ("AIQ_CPF_PATH", "/etc/atomisp/imx185_wdr.cpf", 1);
 
             if(xcamsrc->wdr_mode_type == GAUSSIAN_WDR)
@@ -1018,7 +1020,8 @@
     }
 
 #if HAVE_LIBCL
-    cl_post_processor = new CLPostImageProcessor ();
+    SmartPtr<CLPostImageProcessor> cl_post_processor = new CLPostImageProcessor ();
+    XCAM_ASSERT (cl_post_processor.ptr ());
 
     cl_post_processor->set_stats_callback (device_manager);
     cl_post_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) xcamsrc->defog_mode);
@@ -1110,6 +1113,7 @@
     device_manager->set_3a_analyzer (analyzer);
 
 #if HAVE_LIBCL
+    SmartPtr<SmartAnalyzer> smart_analyzer;
     SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR);
     if (!smart_handlers.empty ()) {
         smart_analyzer = new SmartAnalyzer ();
@@ -1219,7 +1223,7 @@
     case GST_VIDEO_FORMAT_Y42B:
         return V4L2_PIX_FMT_YUV422P;
 
-        //RGB
+    //RGB
     case GST_VIDEO_FORMAT_RGBx:
         return V4L2_PIX_FMT_RGB32;
     case GST_VIDEO_FORMAT_BGRx:
@@ -1733,5 +1737,5 @@
     VERSION,
     GST_LICENSE_UNKNOWN,
     "libxcamsrc",
-    "https://github.com/01org/libxcam"
+    "https://github.com/intel/libxcam"
 )
diff --git a/wrapper/gstreamer/gstxcamsrc.h b/wrapper/gstreamer/gstxcamsrc.h
index 8e87e88..4af1926 100644
--- a/wrapper/gstreamer/gstxcamsrc.h
+++ b/wrapper/gstreamer/gstxcamsrc.h
@@ -42,6 +42,7 @@
 typedef enum {
     ISP_IMAGE_PROCESSOR = 0,
     CL_IMAGE_PROCESSOR,
+    NONE_IMAGE_PROCESSOR,
 } ImageProcessorType;
 
 typedef enum {
diff --git a/wrapper/gstreamer/interface/Makefile.am b/wrapper/gstreamer/interface/Makefile.am
index 5170426..3b056e0 100644
--- a/wrapper/gstreamer/interface/Makefile.am
+++ b/wrapper/gstreamer/interface/Makefile.am
@@ -2,20 +2,22 @@
 
 libgstxcaminterface_la_SOURCES = gstxcaminterface.c
 
-libgstxcaminterface_la_CFLAGS =              \
-				 $(GST_CFLAGS)               \
-				 -I$(top_srcdir)/xcore       \
-				 -I$(top_srcdir)/xcore/base  \
-				 $(XCAM_CFLAGS)              \
-				 $(NULL)
+libgstxcaminterface_la_CFLAGS = \
+    $(XCAM_CFLAGS)             \
+    $(GST_CFLAGS)              \
+    -I$(top_srcdir)/xcore      \
+    -I$(top_srcdir)/xcore/base \
+    $(NULL)
 
 libgstxcaminterface_la_LIBADD = \
-				 $(GST_LIBS) \
-				 $(NULL)
+    $(GST_LIBS)                           \
+    $(top_builddir)/xcore/libxcam_core.la \
+    $(NULL)
 
 libgstxcaminterfaceincludedir = \
-	$(includedir)/gstreamer-1.0/gst
+    $(includedir)/gstreamer-1.0/gst \
+    $(NULL)
 
 libgstxcaminterfaceinclude_HEADERS = \
-	gstxcaminterface.h
-
+    gstxcaminterface.h \
+    $(NULL)
diff --git a/xcore/Makefile.am b/xcore/Makefile.am
index bcadd7c..f901e75 100644
--- a/xcore/Makefile.am
+++ b/xcore/Makefile.am
@@ -1,146 +1,150 @@
 lib_LTLIBRARIES = libxcam_core.la
 
-XCAM_CORE_CXXFLAGS = $(XCAM_CXXFLAGS)
+XCAM_CORE_CXXFLAGS = \
+    $(XCAM_CXXFLAGS) \
+    -pthread         \
+    $(NULL)
+
 XCAM_CORE_LIBS = \
-    -ldl      \
-    -lpthread \
+    -ldl \
     $(NULL)
 
 xcam_sources = \
-    analyzer_loader.cpp                 \
-    smart_analyzer_loader.cpp           \
-    buffer_pool.cpp                     \
-    calibration_parser.cpp              \
-    device_manager.cpp                  \
-    pipe_manager.cpp                    \
-    dma_video_buffer.cpp                \
-    dynamic_analyzer.cpp                \
-    dynamic_analyzer_loader.cpp         \
-    smart_analyzer.cpp                  \
-    smart_analysis_handler.cpp          \
-    smart_buffer_priv.cpp               \
-    fake_poll_thread.cpp                \
-    file_handle.cpp                     \
-    handler_interface.cpp               \
-    image_handler.cpp                   \
-    image_processor.cpp                 \
-    image_projector.cpp                 \
-    image_file_handle.cpp               \
-    poll_thread.cpp                     \
-    surview_fisheye_dewarp.cpp          \
-    swapped_buffer.cpp                  \
-    thread_pool.cpp                     \
-    uvc_device.cpp                      \
-    v4l2_buffer_proxy.cpp               \
-    v4l2_device.cpp                     \
-    video_buffer.cpp                    \
-    worker.cpp                          \
-    xcam_analyzer.cpp                   \
-    x3a_analyzer.cpp                    \
-    x3a_analyzer_manager.cpp            \
-    x3a_analyzer_simple.cpp             \
-    x3a_image_process_center.cpp        \
-    x3a_stats_pool.cpp                  \
-    x3a_result.cpp                      \
-    x3a_result_factory.cpp              \
-    xcam_common.cpp                     \
-    xcam_buffer.cpp                     \
-    xcam_thread.cpp                     \
-    xcam_utils.cpp                      \
-    interface/feature_match.cpp         \
-    interface/blender.cpp               \
-    interface/geo_mapper.cpp            \
-    interface/stitcher.cpp              \
+    analyzer_loader.cpp            \
+    smart_analyzer_loader.cpp      \
+    buffer_pool.cpp                \
+    calibration_parser.cpp         \
+    device_manager.cpp             \
+    pipe_manager.cpp               \
+    dma_video_buffer.cpp           \
+    dynamic_analyzer.cpp           \
+    dynamic_analyzer_loader.cpp    \
+    smart_analyzer.cpp             \
+    smart_analysis_handler.cpp     \
+    smart_buffer_priv.cpp          \
+    fake_poll_thread.cpp           \
+    file_handle.cpp                \
+    handler_interface.cpp          \
+    image_handler.cpp              \
+    image_processor.cpp            \
+    image_projector.cpp            \
+    image_file_handle.cpp          \
+    poll_thread.cpp                \
+    surview_fisheye_dewarp.cpp     \
+    swapped_buffer.cpp             \
+    thread_pool.cpp                \
+    uvc_device.cpp                 \
+    v4l2_buffer_proxy.cpp          \
+    v4l2_device.cpp                \
+    video_buffer.cpp               \
+    once_map_video_buffer_priv.cpp \
+    worker.cpp                     \
+    xcam_analyzer.cpp              \
+    x3a_analyzer.cpp               \
+    x3a_analyzer_manager.cpp       \
+    x3a_analyzer_simple.cpp        \
+    x3a_image_process_center.cpp   \
+    x3a_stats_pool.cpp             \
+    x3a_result.cpp                 \
+    x3a_result_factory.cpp         \
+    xcam_common.cpp                \
+    xcam_buffer.cpp                \
+    xcam_thread.cpp                \
+    xcam_utils.cpp                 \
+    interface/feature_match.cpp    \
+    interface/blender.cpp          \
+    interface/geo_mapper.cpp       \
+    interface/stitcher.cpp         \
     $(NULL)
 
 if HAVE_LIBDRM
 XCAM_CORE_CXXFLAGS += $(LIBDRM_CFLAGS)
 XCAM_CORE_LIBS += \
-    -ldrm_intel          \
-    $(LIBDRM_LIBS)       \
+    -ldrm_intel    \
+    $(LIBDRM_LIBS) \
     $(NULL)
 
 xcam_sources += \
-    drm_bo_buffer.cpp    \
-    drm_display.cpp      \
-    drm_v4l2_buffer.cpp  \
+    drm_bo_buffer.cpp   \
+    drm_display.cpp     \
+    drm_v4l2_buffer.cpp \
     $(NULL)
 endif
 
 libxcam_core_la_CXXFLAGS = \
-    $(XCAM_CORE_CXXFLAGS)  \
+    $(XCAM_CORE_CXXFLAGS) \
     $(NULL)
 
 libxcam_core_la_SOURCES = \
-    $(xcam_sources)  \
-    $(NULL)
-
-libxcam_core_la_LDFLAGS = \
-    -no-undefined       \
-    $(XCAM_LT_LDFLAGS)  \
-    $(PTHREAD_LDFLAGS)  \
+    $(xcam_sources) \
     $(NULL)
 
 libxcam_core_la_LIBADD = \
-    $(XCAM_CORE_LIBS)  \
+    $(XCAM_CORE_LIBS) \
+    $(NULL)
+
+libxcam_core_la_LDFLAGS = \
+    -no-undefined      \
+    -pthread           \
+    $(XCAM_LT_LDFLAGS) \
     $(NULL)
 
 libxcam_coreincludedir = $(includedir)/xcam
 
 nobase_libxcam_coreinclude_HEADERS = \
-    base/xcam_3a_result.h          \
-    base/xcam_3a_types.h           \
-    base/xcam_3a_description.h     \
-    base/xcam_buffer.h             \
-    base/xcam_params.h             \
-    base/xcam_common.h             \
-    base/xcam_defs.h               \
-    base/xcam_smart_description.h  \
-    base/xcam_smart_result.h       \
-    calibration_parser.h           \
-    device_manager.h               \
-    dma_video_buffer.h             \
-    file_handle.h                  \
-    pipe_manager.h                 \
-    handler_interface.h            \
-    image_handler.h                \
-    image_processor.h              \
-    image_projector.h              \
-    image_file_handle.h            \
-    safe_list.h                    \
-    smartptr.h                     \
-    surview_fisheye_dewarp.h       \
-    swapped_buffer.h               \
-    thread_pool.h                  \
-    v4l2_buffer_proxy.h            \
-    v4l2_device.h                  \
-    video_buffer.h                 \
-    worker.h                       \
-    xcam_analyzer.h                \
-    x3a_analyzer.h                 \
-    x3a_analyzer_manager.h         \
-    x3a_event.h                    \
-    x3a_image_process_center.h     \
-    x3a_result.h                   \
-    xcam_mutex.h                   \
-    xcam_thread.h                  \
-    xcam_std.h                     \
-    xcam_utils.h                   \
-    xcam_obj_debug.h               \
-    buffer_pool.h                  \
-    meta_data.h                    \
-    vec_mat.h                      \
-    interface/data_types.h         \
-    interface/feature_match.h      \
-    interface/blender.h            \
-    interface/geo_mapper.h         \
-    interface/stitcher.h           \
+    base/xcam_3a_result.h         \
+    base/xcam_3a_types.h          \
+    base/xcam_3a_description.h    \
+    base/xcam_buffer.h            \
+    base/xcam_params.h            \
+    base/xcam_common.h            \
+    base/xcam_defs.h              \
+    base/xcam_smart_description.h \
+    base/xcam_smart_result.h      \
+    calibration_parser.h          \
+    device_manager.h              \
+    dma_video_buffer.h            \
+    file_handle.h                 \
+    pipe_manager.h                \
+    handler_interface.h           \
+    image_handler.h               \
+    image_processor.h             \
+    image_projector.h             \
+    image_file_handle.h           \
+    safe_list.h                   \
+    smartptr.h                    \
+    surview_fisheye_dewarp.h      \
+    swapped_buffer.h              \
+    thread_pool.h                 \
+    v4l2_buffer_proxy.h           \
+    v4l2_device.h                 \
+    video_buffer.h                \
+    worker.h                      \
+    xcam_analyzer.h               \
+    x3a_analyzer.h                \
+    x3a_analyzer_manager.h        \
+    x3a_event.h                   \
+    x3a_image_process_center.h    \
+    x3a_result.h                  \
+    xcam_mutex.h                  \
+    xcam_thread.h                 \
+    xcam_std.h                    \
+    xcam_utils.h                  \
+    xcam_obj_debug.h              \
+    buffer_pool.h                 \
+    meta_data.h                   \
+    vec_mat.h                     \
+    interface/data_types.h        \
+    interface/feature_match.h     \
+    interface/blender.h           \
+    interface/geo_mapper.h        \
+    interface/stitcher.h          \
     $(NULL)
 
 if HAVE_LIBDRM
 nobase_libxcam_coreinclude_HEADERS += \
-    drm_bo_buffer.h    \
-    drm_display.h      \
-    drm_v4l2_buffer.h  \
+    drm_bo_buffer.h   \
+    drm_display.h     \
+    drm_v4l2_buffer.h \
     $(NULL)
 endif
diff --git a/xcore/base/xcam_common.h b/xcore/base/xcam_common.h
index 46cc6fd..1f16e1e 100644
--- a/xcore/base/xcam_common.h
+++ b/xcore/base/xcam_common.h
@@ -49,6 +49,8 @@
     XCAM_RETURN_ERROR_IOCTL     = -8,
     XCAM_RETURN_ERROR_CL        = -9,
     XCAM_RETURN_ERROR_ORDER     = -10,
+    XCAM_RETURN_ERROR_GLES      = -11,
+    XCAM_RETURN_ERROR_VULKAN    = -12,
 
     XCAM_RETURN_ERROR_TIMEOUT   = -20,
 
diff --git a/xcore/base/xcam_defs.h b/xcore/base/xcam_defs.h
index 276644f..77b74a5 100644
--- a/xcore/base/xcam_defs.h
+++ b/xcore/base/xcam_defs.h
@@ -72,9 +72,17 @@
 #define XCAM_FAIL_RETURN(LEVEL, exp, ret, msg, ...)         \
     if (!(exp)) {                                           \
         XCAM_LOG_##LEVEL (msg, ## __VA_ARGS__);             \
-        return (ret);                                       \
+        return ret;                                         \
     }
 
+#define XCAM_RETURN_CHECK(LEVEL, exp, msg, ...)             \
+    do {                                                    \
+    XCamReturn err_ret = (exp);                             \
+    XCAM_FAIL_RETURN(LEVEL, xcam_ret_is_ok(err_ret),        \
+        err_ret, msg, ## __VA_ARGS__);                      \
+    } while (0)
+
+
 #define XCAM_DEAD_COPY(ClassObj)                \
         ClassObj (const ClassObj&);             \
         ClassObj & operator= (const ClassObj&)  \
@@ -119,7 +127,10 @@
 #define PRIuS "u"
 #endif
 
-#define PI 3.1415926f
-#define degree2radian(degree) ((degree) * PI / 180.0f)
+#ifndef XCAM_PI
+#define XCAM_PI 3.1415926f
+#endif
+
+#define degree2radian(degree) ((degree) * XCAM_PI / 180.0f)
 
 #endif //XCAM_DEFS_H
diff --git a/xcore/buffer_pool.h b/xcore/buffer_pool.h
index 899cbf0..09bb1da 100644
--- a/xcore/buffer_pool.h
+++ b/xcore/buffer_pool.h
@@ -67,6 +67,9 @@
     SmartPtr<BufferData> &get_buffer_data () {
         return _data;
     }
+    const SmartPtr<BufferData> &get_buffer_data () const {
+        return _data;
+    }
 
 private:
     XCAM_DEAD_COPY (BufferProxy);
@@ -126,6 +129,9 @@
     bool                     _started;
 };
 
+class VKDevice;
+SmartPtr<BufferPool> create_vk_buffer_pool (const SmartPtr<VKDevice> &dev);
+
 };
 
 #endif //XCAM_BUFFER_POOL_H
diff --git a/xcore/drm_bo_buffer.h b/xcore/drm_bo_buffer.h
index fa661d3..2a76a43 100644
--- a/xcore/drm_bo_buffer.h
+++ b/xcore/drm_bo_buffer.h
@@ -94,7 +94,7 @@
 
 public:
     explicit DrmBoBufferPool (SmartPtr<DrmDisplay> &display);
-    ~DrmBoBufferPool ();
+    virtual ~DrmBoBufferPool ();
 
     // **** MUST be set before set_video_info ****
     void set_swap_flags (uint32_t flags, uint32_t init_order) {
diff --git a/xcore/drm_display.cpp b/xcore/drm_display.cpp
index a5c89db..7e41efa 100644
--- a/xcore/drm_display.cpp
+++ b/xcore/drm_display.cpp
@@ -54,7 +54,11 @@
     SmartLock lock(_mutex);
     if (_instance.ptr())
         return _instance;
-    _instance = new DrmDisplay ();
+
+    SmartPtr<DrmDisplay> instance = new DrmDisplay ();
+    XCAM_ASSERT (instance.ptr ());
+    _instance = instance;
+
     return _instance;
 }
 
diff --git a/xcore/dynamic_analyzer.cpp b/xcore/dynamic_analyzer.cpp
index 4ca553a..b0932d1 100644
--- a/xcore/dynamic_analyzer.cpp
+++ b/xcore/dynamic_analyzer.cpp
@@ -104,7 +104,10 @@
     if (_common_handler.ptr())
         return _common_handler;
 
-    _common_handler = new DynamicCommonHandler (this);
+    SmartPtr<DynamicCommonHandler> handler = new DynamicCommonHandler (this);
+    XCAM_ASSERT (handler.ptr ());
+    _common_handler = handler;
+
     return _common_handler;
 }
 
diff --git a/xcore/fake_poll_thread.cpp b/xcore/fake_poll_thread.cpp
index 612a697..c15df13 100644
--- a/xcore/fake_poll_thread.cpp
+++ b/xcore/fake_poll_thread.cpp
@@ -146,8 +146,9 @@
               format.fmt.pix.height, 0, 0, 0);
 #if HAVE_LIBDRM
     SmartPtr<DrmDisplay> drm_disp = DrmDisplay::instance ();
-    _buf_pool = new DrmBoBufferPool (drm_disp);
-    XCAM_ASSERT (_buf_pool.ptr ());
+    SmartPtr<BufferPool> pool = new DrmBoBufferPool (drm_disp);
+    XCAM_ASSERT (pool.ptr ());
+    _buf_pool = pool;
 
     if (_buf_pool->set_video_info (info) && _buf_pool->reserve (DEFAULT_FPT_BUF_COUNT))
         return XCAM_RETURN_NO_ERROR;
diff --git a/xcore/image_file_handle.cpp b/xcore/image_file_handle.cpp
index a901b1f..6a9ce68 100644
--- a/xcore/image_file_handle.cpp
+++ b/xcore/image_file_handle.cpp
@@ -48,6 +48,12 @@
     XCAM_ASSERT (is_valid ());
 
     memory = buf->map ();
+
+    if (NULL == memory) {
+        XCAM_LOG_ERROR ("ImageFileHandle::read_buf map buffer memory(%p) \n", memory);
+        buf->unmap ();
+        return ret;
+    }
     for (uint32_t index = 0; index < info.components; index++) {
         info.get_planar_info (planar, index);
         uint32_t line_bytes = planar.width * planar.pixel_bytes;
diff --git a/xcore/image_handler.cpp b/xcore/image_handler.cpp
index 6e47a62..2dabc97 100644
--- a/xcore/image_handler.cpp
+++ b/xcore/image_handler.cpp
@@ -23,7 +23,10 @@
 namespace XCam {
 
 ImageHandler::ImageHandler (const char* name)
-    : _name (NULL)
+    : _need_configure (true)
+    , _enable_allocator (true)
+    , _buf_capacity (XCAM_DEFAULT_HANDLER_BUF_CAP)
+    , _name (NULL)
 {
     if (name)
         _name = strndup (name, XCAM_MAX_STR_SIZE);
@@ -35,22 +38,128 @@
 }
 
 bool
+ImageHandler::set_out_video_info (const VideoBufferInfo &info)
+{
+    XCAM_ASSERT (info.width && info.height && info.format);
+    _out_video_info = info;
+    return true;
+}
+
+bool
+ImageHandler::enable_allocator (bool enable, uint32_t buf_count)
+{
+
+    if (enable && !buf_count) {
+        XCAM_LOG_ERROR (
+            "ImageHandler(%s) enable allocator must with buf_count>0", XCAM_STR(get_name ()));
+        return false;
+    }
+
+    _enable_allocator = enable;
+    if (enable)
+        _buf_capacity = buf_count;
+
+    return true;
+}
+
+bool
 ImageHandler::set_allocator (const SmartPtr<BufferPool> &allocator)
 {
     XCAM_FAIL_RETURN (
         ERROR, allocator.ptr (), false,
-        "softhandler(%s) set allocator(is NULL)", XCAM_STR(get_name ()));
+        "ImageHandler(%s) set allocator(is NULL)", XCAM_STR(get_name ()));
     _allocator = allocator;
     return true;
 }
 
 XCamReturn
+ImageHandler::configure_rest ()
+{
+    if (_enable_allocator) {
+        XCAM_FAIL_RETURN (
+            ERROR, _out_video_info.is_valid (), XCAM_RETURN_ERROR_PARAM,
+            "image_hander(%s) configure reset failed before reserver buffer since out_video_info was not set",
+            XCAM_STR (get_name ()));
+
+        SmartPtr<BufferPool> allocator = create_allocator ();
+        XCAM_FAIL_RETURN (
+            ERROR, allocator.ptr (), XCAM_RETURN_ERROR_PARAM,
+            "image_hander(%s) configure reset failed since allocator not created", XCAM_STR (get_name ()));
+        _allocator = allocator;
+        XCamReturn ret = reserve_buffers (_out_video_info, _buf_capacity);
+        XCAM_FAIL_RETURN (
+            ERROR, xcam_ret_is_ok (ret), ret,
+            "soft_hander(%s) configure resource failed in reserving buffers", XCAM_STR (get_name ()));
+    }
+    return XCAM_RETURN_NO_ERROR;
+}
+
+XCamReturn
+ImageHandler::execute_buffer (const SmartPtr<ImageHandler::Parameters> &param, bool sync)
+{
+    XCAM_UNUSED (sync);
+
+    XCamReturn ret = XCAM_RETURN_NO_ERROR;
+
+    XCAM_FAIL_RETURN (
+        ERROR, param.ptr (), XCAM_RETURN_ERROR_PARAM,
+        "image_handler(%s) execute buffer failed, params is null",
+        XCAM_STR (get_name ()));
+
+    if (_need_configure) {
+        ret = configure_resource (param);
+        XCAM_FAIL_RETURN (
+            WARNING, xcam_ret_is_ok (ret), ret,
+            "image_handler(%s) configure resource failed", XCAM_STR (get_name ()));
+
+        ret = configure_rest ();
+        XCAM_FAIL_RETURN (
+            WARNING, xcam_ret_is_ok (ret), ret,
+            "image_handler(%s) configure rest failed", XCAM_STR (get_name ()));
+        _need_configure = false;
+    }
+
+    if (!param->out_buf.ptr () && _enable_allocator) {
+        param->out_buf = get_free_buf ();
+        XCAM_FAIL_RETURN (
+            ERROR, param->out_buf.ptr (), XCAM_RETURN_ERROR_PARAM,
+            "image_handler:%s execute buffer failed, output buffer failed in allocation.",
+            XCAM_STR (get_name ()));
+    }
+
+    ret = start_work (param);
+    XCAM_FAIL_RETURN (
+        ERROR, xcam_ret_is_ok (ret), ret,
+        "image_handler(%s) execute buffer failed in starting workers", XCAM_STR (get_name ()));
+
+    return ret;
+}
+
+void
+ImageHandler::execute_done (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err)
+{
+    XCAM_ASSERT (param.ptr ());
+
+    if (err < XCAM_RETURN_NO_ERROR) {
+        XCAM_LOG_WARNING (
+            "image_handler(%s) broken with errno %d", XCAM_STR (get_name ()), (int)err);
+        return ;
+    }
+
+    if (err > XCAM_RETURN_NO_ERROR) {
+        XCAM_LOG_WARNING (
+            "image_handler(%s) continued with errno %d", XCAM_STR (get_name ()), (int)err);
+    }
+
+    execute_status_check (param, err);
+}
+
+XCamReturn
 ImageHandler::finish ()
 {
     return XCAM_RETURN_NO_ERROR;
 }
 
-
 XCamReturn
 ImageHandler::terminate ()
 {
@@ -72,13 +181,13 @@
 {
     XCAM_FAIL_RETURN (
         ERROR, _allocator.ptr (), XCAM_RETURN_ERROR_PARAM,
-        "softhandler(%s) reserve buffers failed, alloctor was not set", XCAM_STR(get_name ()));
+        "ImageHandler(%s) reserve buffers failed, alloctor was not set", XCAM_STR(get_name ()));
 
     _allocator->set_video_info (info);
 
     XCAM_FAIL_RETURN (
         ERROR, _allocator->reserve (count), XCAM_RETURN_ERROR_MEM,
-        "softhandler(%s) reserve buffers(%d) failed", XCAM_STR(get_name ()), count);
+        "ImageHandler(%s) reserve buffers(%d) failed", XCAM_STR(get_name ()), count);
 
     return XCAM_RETURN_NO_ERROR;
 }
@@ -88,7 +197,7 @@
 {
     XCAM_FAIL_RETURN (
         ERROR, _allocator.ptr (), NULL,
-        "softhandler(%s) get free buffer failed since allocator was not initilized", XCAM_STR(get_name ()));
+        "ImageHandler(%s) get free buffer failed since allocator was not initilized", XCAM_STR(get_name ()));
 
     return _allocator->get_buffer (_allocator);
 }
diff --git a/xcore/image_handler.h b/xcore/image_handler.h
index 2c3fba8..80c64f5 100644
--- a/xcore/image_handler.h
+++ b/xcore/image_handler.h
@@ -37,6 +37,8 @@
             _h->mem_func (handler, params, error);  }                    \
     }
 
+#define XCAM_DEFAULT_HANDLER_BUF_CAP 4
+
 namespace XCam {
 
 class ImageHandler;
@@ -85,14 +87,22 @@
     const char *get_name () const {
         return _name;
     }
+    bool set_out_video_info (const VideoBufferInfo &info);
+    bool enable_allocator (bool enable, uint32_t buf_count = XCAM_DEFAULT_HANDLER_BUF_CAP);
 
     // virtual functions
     // execute_buffer params should  NOT be const
-    virtual XCamReturn execute_buffer (const SmartPtr<Parameters> &params, bool sync) = 0;
+    virtual XCamReturn execute_buffer (const SmartPtr<Parameters> &params, bool sync);
+    virtual void execute_done (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err);
     virtual XCamReturn finish ();
     virtual XCamReturn terminate ();
 
 protected:
+    virtual XCamReturn configure_resource (const SmartPtr<Parameters> &param) = 0;
+    virtual SmartPtr<BufferPool> create_allocator () = 0;
+    virtual XCamReturn configure_rest ();
+    virtual XCamReturn start_work (const SmartPtr<Parameters> &param) = 0;
+
     virtual void execute_status_check (const SmartPtr<Parameters> &params, const XCamReturn error);
 
     bool set_allocator (const SmartPtr<BufferPool> &allocator);
@@ -102,12 +112,22 @@
     XCamReturn reserve_buffers (const VideoBufferInfo &info, uint32_t count);
     SmartPtr<VideoBuffer> get_free_buf ();
 
+    const VideoBufferInfo &get_out_video_info () {
+        return _out_video_info;
+    }
+
 private:
     XCAM_DEAD_COPY (ImageHandler);
 
+protected:
+    bool                    _need_configure;
+    bool                    _enable_allocator;
+
 private:
     SmartPtr<Callback>      _callback;
+    VideoBufferInfo         _out_video_info;
     SmartPtr<BufferPool>    _allocator;
+    uint32_t                _buf_capacity;
     char                   *_name;
 };
 
diff --git a/xcore/image_processor.cpp b/xcore/image_processor.cpp
index 928cbcc..f2cdc2d 100644
--- a/xcore/image_processor.cpp
+++ b/xcore/image_processor.cpp
@@ -144,8 +144,13 @@
     if (name)
         _name = strndup (name, XCAM_MAX_STR_SIZE);
 
-    _processor_thread = new ImageProcessorThread (this);
-    _results_thread = new X3aResultsProcessThread (this);
+    SmartPtr<ImageProcessorThread> processor_thread = new ImageProcessorThread (this);
+    XCAM_ASSERT (processor_thread.ptr ());
+    _processor_thread = processor_thread;
+
+    SmartPtr<X3aResultsProcessThread> results_thread = new X3aResultsProcessThread (this);
+    XCAM_ASSERT (results_thread.ptr ());
+    _results_thread = results_thread;
 }
 
 ImageProcessor::~ImageProcessor ()
diff --git a/xcore/interface/blender.h b/xcore/interface/blender.h
index 93b5fbe..2d56614 100644
--- a/xcore/interface/blender.h
+++ b/xcore/interface/blender.h
@@ -30,6 +30,7 @@
 namespace XCam {
 
 class Blender;
+class VKDevice;
 
 class Blender
 {
@@ -38,6 +39,8 @@
     virtual ~Blender ();
     static SmartPtr<Blender> create_ocl_blender ();
     static SmartPtr<Blender> create_soft_blender ();
+    static SmartPtr<Blender> create_gl_blender ();
+    static SmartPtr<Blender> create_vk_blender (const SmartPtr<VKDevice> &dev);
 
     void set_output_size (uint32_t width, uint32_t height);
     void get_output_size (uint32_t &width, uint32_t &height) const {
diff --git a/xcore/interface/data_types.h b/xcore/interface/data_types.h
index a4d6f4e..589ec29 100644
--- a/xcore/interface/data_types.h
+++ b/xcore/interface/data_types.h
@@ -31,6 +31,19 @@
     BowlView = 1
 };
 
+enum FeatureMatchMode {
+    FMNone = 0,
+    FMDefault,
+    FMCluster,
+    FMCapi
+};
+
+enum GeoMapScaleMode {
+    ScaleSingleConst = 0,
+    ScaleDualConst,
+    ScaleDualCurve
+};
+
 struct Rect {
     int32_t pos_x, pos_y;
     int32_t width, height;
diff --git a/xcore/interface/feature_match.cpp b/xcore/interface/feature_match.cpp
index 4a6a428..1ed625f 100644
--- a/xcore/interface/feature_match.cpp
+++ b/xcore/interface/feature_match.cpp
@@ -27,7 +27,9 @@
 
 FeatureMatch::FeatureMatch ()
     : _x_offset (0.0f)
+    , _y_offset (0.0f)
     , _mean_offset (0.0f)
+    , _mean_offset_y (0.0f)
     , _valid_count (0)
     , _fm_idx (-1)
     , _frame_num (0)
@@ -35,34 +37,73 @@
 }
 
 void
-FeatureMatch::set_config (CVFMConfig config)
-{
-    _config = config;
-}
-
-CVFMConfig
-FeatureMatch::get_config ()
-{
-    return _config;
-}
-
-void
 FeatureMatch::set_fm_index (int idx)
 {
     _fm_idx = idx;
 }
 
 void
+FeatureMatch::set_config (const FMConfig &config)
+{
+    _config = config;
+}
+
+void
+FeatureMatch::set_crop_rect (const Rect &left_rect, const Rect &right_rect)
+{
+    _left_rect = left_rect;
+    _right_rect = right_rect;
+}
+
+void
+FeatureMatch::get_crop_rect (Rect &left_rect, Rect &right_rect)
+{
+    left_rect = _left_rect;
+    right_rect = _right_rect;
+}
+
+void
 FeatureMatch::reset_offsets ()
 {
     _x_offset = 0.0f;
+    _y_offset = 0.0f;
     _mean_offset = 0.0f;
+    _mean_offset_y = 0.0f;
+}
+
+float
+FeatureMatch::get_current_left_offset_x ()
+{
+    return _x_offset;
+}
+
+float
+FeatureMatch::get_current_left_offset_y ()
+{
+    return _y_offset;
+}
+
+void
+FeatureMatch::set_dst_width (int width)
+{
+    XCAM_UNUSED (width);
+
+    XCAM_LOG_ERROR ("dst width is not supported");
+    XCAM_ASSERT (false);
+}
+
+void
+FeatureMatch::enable_adjust_crop_area ()
+{
+    XCAM_LOG_ERROR ("adjust crop area is not supported");
+    XCAM_ASSERT (false);
 }
 
 bool
-FeatureMatch::get_mean_offset (std::vector<float> &offsets, float sum, int &count, float &mean_offset)
+FeatureMatch::get_mean_offset (
+    const std::vector<float> &offsets, float sum, int &count, float &mean_offset)
 {
-    if (count < _config.min_corners)
+    if (count < _config.min_corners || count <= 0)
         return false;
 
     mean_offset = sum / count;
@@ -87,7 +128,7 @@
             ++recur_count;
         }
 
-        if (recur_count < _config.min_corners) {
+        if (recur_count < _config.min_corners || recur_count <= 0) {
             ret = false;
             break;
         }
@@ -115,29 +156,4 @@
     return ret;
 }
 
-void
-FeatureMatch::adjust_stitch_area (int dst_width, float &x_offset, Rect &stitch0, Rect &stitch1)
-{
-    if (fabs (x_offset) < 5.0f)
-        return;
-
-    int last_overlap_width = stitch1.pos_x + stitch1.width + (dst_width - (stitch0.pos_x + stitch0.width));
-    // int final_overlap_width = stitch1.pos_x + stitch1.width + (dst_width - (stitch0.pos_x - x_offset + stitch0.width));
-    if ((stitch0.pos_x - x_offset + stitch0.width) > dst_width)
-        x_offset = dst_width - (stitch0.pos_x + stitch0.width);
-    int final_overlap_width = last_overlap_width + x_offset;
-    final_overlap_width = XCAM_ALIGN_AROUND (final_overlap_width, 8);
-    XCAM_ASSERT (final_overlap_width >= _config.sitch_min_width);
-    int center = final_overlap_width / 2;
-    XCAM_ASSERT (center >= _config.sitch_min_width / 2);
-
-    stitch1.pos_x = XCAM_ALIGN_AROUND (center - _config.sitch_min_width / 2, 8);
-    stitch1.width = _config.sitch_min_width;
-    stitch0.pos_x = dst_width - final_overlap_width + stitch1.pos_x;
-    stitch0.width = _config.sitch_min_width;
-
-    float delta_offset = final_overlap_width - last_overlap_width;
-    x_offset -= delta_offset;
-}
-
 }
diff --git a/xcore/interface/feature_match.h b/xcore/interface/feature_match.h
index 06c0b7b..a8dd72b 100644
--- a/xcore/interface/feature_match.h
+++ b/xcore/interface/feature_match.h
@@ -28,7 +28,7 @@
 
 namespace XCam {
 
-struct CVFMConfig {
+struct FMConfig {
     int sitch_min_width;
     int min_corners;           // number of minimum efficient corners
     float offset_factor;       // last_offset * offset_factor + cur_offset * (1.0f - offset_factor)
@@ -38,7 +38,7 @@
     float max_valid_offset_y;  // valid maximum offset in vertical direction
     float max_track_error;     // maximum track error
 
-    CVFMConfig ()
+    FMConfig ()
         : sitch_min_width (56)
         , min_corners (8)
         , offset_factor (0.8f)
@@ -56,41 +56,46 @@
     explicit FeatureMatch ();
     virtual ~FeatureMatch () {};
 
-    void set_config (CVFMConfig config);
-    CVFMConfig get_config ();
+    static SmartPtr<FeatureMatch> create_default_feature_match ();
+    static SmartPtr<FeatureMatch> create_cluster_feature_match ();
+    static SmartPtr<FeatureMatch> create_capi_feature_match ();
+
+    virtual void feature_match (
+        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf) = 0;
 
     void set_fm_index (int idx);
+    void set_config (const FMConfig &config);
+
+    void set_crop_rect (const Rect &left_rect, const Rect &right_rect);
+    void get_crop_rect (Rect &left_rect, Rect &right_rect);
 
     void reset_offsets ();
+    float get_current_left_offset_x ();
+    float get_current_left_offset_y ();
 
-    virtual void optical_flow_feature_match (
-        const SmartPtr<VideoBuffer> &left_buf, const SmartPtr<VideoBuffer> &right_buf,
-        Rect &left_crop_rect, Rect &right_crop_rect, int dst_width) = 0;
-
-    float get_current_left_offset_x () const {
-        return _x_offset;
-    }
-
-    virtual void set_ocl (bool use_ocl) = 0;
-    virtual bool is_ocl_path () = 0;
+    virtual void set_dst_width (int width);
+    virtual void enable_adjust_crop_area ();
 
 protected:
-    bool get_mean_offset (std::vector<float> &offsets, float sum, int &count, float &mean_offset);
-
-    void adjust_stitch_area (int dst_width, float &x_offset, Rect &stitch0, Rect &stitch1);
+    bool get_mean_offset (const std::vector<float> &offsets, float sum, int &count, float &mean_offset);
 
 private:
     XCAM_DEAD_COPY (FeatureMatch);
 
 protected:
     float                _x_offset;
+    float                _y_offset;
     float                _mean_offset;
+    float                _mean_offset_y;
     int                  _valid_count;
-    CVFMConfig           _config;
+    FMConfig             _config;
+
+    Rect                 _left_rect;
+    Rect                 _right_rect;
 
     // debug parameters
     int                  _fm_idx;
-    uint                 _frame_num;
+    uint32_t             _frame_num;
 };
 
 }
diff --git a/xcore/interface/geo_mapper.h b/xcore/interface/geo_mapper.h
index 0ddd495..8a779af 100644
--- a/xcore/interface/geo_mapper.h
+++ b/xcore/interface/geo_mapper.h
@@ -27,6 +27,8 @@
 
 namespace XCam {
 
+class VKDevice;
+
 class GeoMapper
 {
 public:
@@ -34,6 +36,8 @@
     virtual ~GeoMapper ();
     static SmartPtr<GeoMapper> create_ocl_geo_mapper ();
     static SmartPtr<GeoMapper> create_soft_geo_mapper ();
+    static SmartPtr<GeoMapper> create_gl_geo_mapper ();
+    static SmartPtr<GeoMapper> create_vk_geo_mapper (const SmartPtr<VKDevice> &dev, const char* name);
 
     //2D table
     virtual bool set_lookup_table (const PointFloat2 *data, uint32_t width, uint32_t height) = 0;
@@ -53,7 +57,7 @@
         SmartPtr<VideoBuffer> &out_buf) = 0;
 
 protected:
-    bool auto_calculate_factors (uint32_t lut_w, uint32_t lut_h);
+    virtual bool auto_calculate_factors (uint32_t lut_w, uint32_t lut_h);
 
 private:
     uint32_t     _out_width, _out_height;
diff --git a/xcore/interface/stitcher.cpp b/xcore/interface/stitcher.cpp
index 70da11f..3b0ed6d 100644
--- a/xcore/interface/stitcher.cpp
+++ b/xcore/interface/stitcher.cpp
@@ -77,8 +77,7 @@
 }
 
 Stitcher::Stitcher (uint32_t align_x, uint32_t align_y)
-    : _is_crop_set (false)
-    , _alignment_x (align_x)
+    : _alignment_x (align_x)
     , _alignment_y (align_y)
     , _output_width (0)
     , _output_height (0)
@@ -86,7 +85,10 @@
     , _camera_num (0)
     , _is_round_view_set (false)
     , _is_overlap_set (false)
+    , _is_crop_set (false)
     , _is_center_marked (false)
+    , _scale_mode (ScaleSingleConst)
+    , _fm_mode (FMNone)
 {
     XCAM_ASSERT (align_x >= 1);
     XCAM_ASSERT (align_y >= 1);
@@ -629,7 +631,7 @@
 
             vertices.push_back (PointFloat3(world_pos0.x / _config.a, world_pos0.y / _config.b, world_pos0.z / _config.c));
             indeices.push_back (indicator++);
-            texture_points.push_back (PointFloat2(texture_pos0.x / _bowl_img_width, (_bowl_img_height - texture_pos0.y) / _bowl_img_height));
+            texture_points.push_back (PointFloat2(texture_pos0.x / _bowl_img_width, texture_pos0.y / _bowl_img_height));
 
             PointFloat3 world_pos1 =
                 bowl_view_image_to_world (
@@ -637,7 +639,7 @@
 
             vertices.push_back (PointFloat3(world_pos1.x / _config.a, world_pos1.y / _config.b, world_pos1.z / _config.c));
             indeices.push_back (indicator++);
-            texture_points.push_back (PointFloat2(texture_pos1.x / _bowl_img_width, (_bowl_img_height - texture_pos1.y) / _bowl_img_height));
+            texture_points.push_back (PointFloat2(texture_pos1.x / _bowl_img_width, texture_pos1.y / _bowl_img_height));
         }
     }
     return true;
diff --git a/xcore/interface/stitcher.h b/xcore/interface/stitcher.h
index e38a98e..8987507 100644
--- a/xcore/interface/stitcher.h
+++ b/xcore/interface/stitcher.h
@@ -70,6 +70,8 @@
     float             angle_range;;
 };
 
+class VKDevice;
+
 class Stitcher
 {
 public:
@@ -126,6 +128,8 @@
     virtual ~Stitcher ();
     static SmartPtr<Stitcher> create_ocl_stitcher ();
     static SmartPtr<Stitcher> create_soft_stitcher ();
+    static SmartPtr<Stitcher> create_gl_stitcher ();
+    static SmartPtr<Stitcher> create_vk_stitcher (const SmartPtr<VKDevice> dev);
 
     bool set_bowl_config (const BowlDataConfig &config);
     const BowlDataConfig &get_bowl_config () {
@@ -153,11 +157,25 @@
         _output_width = width; //XCAM_ALIGN_UP (width, XCAM_BLENDER_ALIGNED_WIDTH);
         _output_height = height;
     }
-
     void get_output_size (uint32_t &width, uint32_t &height) const {
         width = _output_width;
         height = _output_height;
     }
+
+    void set_scale_mode (GeoMapScaleMode scale_mode) {
+        _scale_mode = scale_mode;
+    }
+    GeoMapScaleMode get_scale_mode () {
+        return _scale_mode;
+    }
+
+    void set_fm_mode (FeatureMatchMode fm_mode) {
+        _fm_mode = fm_mode;
+    }
+    FeatureMatchMode get_fm_mode () {
+        return _fm_mode;
+    }
+
     virtual XCamReturn stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf) = 0;
 
 protected:
@@ -186,12 +204,6 @@
 private:
     XCAM_DEAD_COPY (Stitcher);
 
-protected:
-    ImageCropInfo               _crop_info[XCAM_STITCH_MAX_CAMERAS];
-    bool                        _is_crop_set;
-    //update after each feature match
-    ScaleFactor                 _scale_factors[XCAM_STITCH_MAX_CAMERAS];
-
 private:
     uint32_t                    _alignment_x, _alignment_y;
     uint32_t                    _output_width, _output_height;
@@ -205,10 +217,19 @@
     BowlDataConfig              _bowl_config;
     bool                        _is_overlap_set;
 
+    ImageCropInfo               _crop_info[XCAM_STITCH_MAX_CAMERAS];
+    bool                        _is_crop_set;
+
     //auto calculation
     CenterMark                  _center_marks[XCAM_STITCH_MAX_CAMERAS];
     bool                        _is_center_marked;
     CopyAreaArray               _copy_areas;
+
+    GeoMapScaleMode             _scale_mode;
+    //update after each feature match
+    ScaleFactor                 _scale_factors[XCAM_STITCH_MAX_CAMERAS];
+
+    FeatureMatchMode            _fm_mode;
 };
 
 class BowlModel {
diff --git a/xcore/once_map_video_buffer_priv.cpp b/xcore/once_map_video_buffer_priv.cpp
new file mode 100644
index 0000000..1d4793c
--- /dev/null
+++ b/xcore/once_map_video_buffer_priv.cpp
@@ -0,0 +1,97 @@
+/*
+ * once_map_video_buffer_priv.cpp
+ *
+ *  Copyright (c) 2017 Intel Corporation
+ *
+ * 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.
+ *
+ * Author: Zong Wei <wei.zong@intel.com>
+ */
+
+#include <xcam_std.h>
+#include <video_buffer.h>
+
+namespace XCam {
+
+class OnceMapVideoBuffer
+    : public VideoBuffer
+{
+public:
+    OnceMapVideoBuffer (const VideoBufferInfo &info, uint8_t* buffer);
+
+    virtual ~OnceMapVideoBuffer ();
+
+    virtual uint8_t *map ();
+    virtual bool unmap ();
+    virtual int get_fd ();
+
+private:
+
+    XCAM_DEAD_COPY (OnceMapVideoBuffer);
+
+private:
+    uint8_t* _buffer;
+};
+
+OnceMapVideoBuffer::OnceMapVideoBuffer (const VideoBufferInfo &info, uint8_t* buffer)
+    : VideoBuffer (info)
+    , _buffer (buffer)
+{
+    XCAM_ASSERT (buffer != NULL);
+}
+
+OnceMapVideoBuffer::~OnceMapVideoBuffer ()
+{
+}
+
+uint8_t *
+OnceMapVideoBuffer::map ()
+{
+    return _buffer;
+}
+
+bool
+OnceMapVideoBuffer::unmap ()
+{
+    return true;
+}
+
+int
+OnceMapVideoBuffer::get_fd ()
+{
+    XCAM_ASSERT (false && "OnceMapVideoBuffer::get_fd not supported");
+    return -1;
+}
+
+SmartPtr<VideoBuffer>
+external_buf_to_once_map_buf (
+    uint8_t* buf, uint32_t format,
+    uint32_t width, uint32_t height,
+    uint32_t aligned_width, uint32_t aligned_height,
+    uint32_t size)
+{
+    VideoBufferInfo buf_info;
+    SmartPtr<OnceMapVideoBuffer> video_buffer;
+
+    XCAM_FAIL_RETURN (
+        ERROR, buf, NULL,
+        "external_buf_to_map_buf failed since buf is NULL");
+
+    buf_info.init (format, width, height,
+                   aligned_width, aligned_height, size);
+    video_buffer = new OnceMapVideoBuffer (buf_info, buf);
+    XCAM_ASSERT (video_buffer.ptr ());
+    return video_buffer;
+}
+
+}
diff --git a/xcore/poll_thread.cpp b/xcore/poll_thread.cpp
index dcb778b..013a543 100644
--- a/xcore/poll_thread.cpp
+++ b/xcore/poll_thread.cpp
@@ -83,8 +83,13 @@
     : _poll_callback (NULL)
     , _stats_callback (NULL)
 {
-    _event_loop = new EventPollThread(this);
-    _capture_loop = new CapturePollThread (this);
+    SmartPtr<EventPollThread> event_loop = new EventPollThread(this);
+    XCAM_ASSERT (event_loop.ptr ());
+    _event_loop = event_loop;
+
+    SmartPtr<CapturePollThread> capture_loop = new CapturePollThread (this);
+    XCAM_ASSERT (capture_loop.ptr ());
+    _capture_loop = capture_loop;
 
     XCAM_LOG_DEBUG ("PollThread constructed");
 }
diff --git a/xcore/surview_fisheye_dewarp.cpp b/xcore/surview_fisheye_dewarp.cpp
index 6c0830c..7e45eac 100644
--- a/xcore/surview_fisheye_dewarp.cpp
+++ b/xcore/surview_fisheye_dewarp.cpp
@@ -60,18 +60,19 @@
 }
 
 void
-SurViewFisheyeDewarp::fisheye_dewarp(MapTable &map_table, uint32_t table_w, uint32_t table_h, uint32_t image_w, uint32_t image_h, const BowlDataConfig &bowl_config)
+SurViewFisheyeDewarp::fisheye_dewarp(MapTable &map_table, uint32_t table_w, uint32_t table_h,
+    uint32_t image_w, uint32_t image_h, const BowlDataConfig &bowl_config)
 {
     PointFloat3 world_coord;
     PointFloat3 cam_coord;
     PointFloat3 cam_world_coord;
     PointFloat2 image_coord;
 
-    XCAM_LOG_DEBUG ("fisheye-dewarp:\n table(%dx%d), out_size(%dx%d)"
-                    "bowl(start:%.1f, end:%.1f, ground:%.2f, wall:%.2f, a:%.2f, b:%.2f, c:%.2f, center_z:%.2f )",
+    XCAM_LOG_DEBUG ("fisheye-dewarp:\n table(%dx%d) out_size(%dx%d) "
+                    "bowl(start:%.1f, end:%.1f, ground:%.2f, wall:%.2f, a:%.2f, b:%.2f, c:%.2f, center_z:%.2f)",
                     table_w, table_h, image_w, image_h,
                     bowl_config.angle_start, bowl_config.angle_end,
-                    bowl_config.wall_height, bowl_config.ground_length,
+                    bowl_config.ground_length, bowl_config.wall_height,
                     bowl_config.a, bowl_config.b, bowl_config.c, bowl_config.center_z);
 
     float scale_factor_w = (float)image_w / table_w;
diff --git a/xcore/surview_fisheye_dewarp.h b/xcore/surview_fisheye_dewarp.h
index 571b02a..3754942 100644
--- a/xcore/surview_fisheye_dewarp.h
+++ b/xcore/surview_fisheye_dewarp.h
@@ -36,7 +36,8 @@
     explicit SurViewFisheyeDewarp ();
     virtual ~SurViewFisheyeDewarp ();
 
-    void fisheye_dewarp(MapTable &map_table, uint32_t table_w, uint32_t table_h, uint32_t image_w, uint32_t image_h, const BowlDataConfig &bowl_config);
+    void fisheye_dewarp(MapTable &map_table, uint32_t table_w, uint32_t table_h,
+        uint32_t image_w, uint32_t image_h, const BowlDataConfig &bowl_config);
 
     void set_intrinsic_param(const IntrinsicParameter &intrinsic_param);
     void set_extrinsic_param(const ExtrinsicParameter &extrinsic_param);
diff --git a/xcore/vec_mat.h b/xcore/vec_mat.h
index 51add21..eccb52e 100644
--- a/xcore/vec_mat.h
+++ b/xcore/vec_mat.h
@@ -27,10 +27,6 @@
 
 namespace XCam {
 
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
 #ifndef FLT_EPSILON
 #define FLT_EPSILON 1.19209290e-07F // float
 #endif
@@ -40,11 +36,11 @@
 #endif
 
 #ifndef DEGREE_2_RADIANS
-#define DEGREE_2_RADIANS(x) (((x) * PI) / 180.0)
+#define DEGREE_2_RADIANS(x) (((x) * XCAM_PI) / 180.0)
 #endif
 
 #ifndef RADIANS_2_DEGREE
-#define RADIANS_2_DEGREE(x) (((x) * 180.0) / PI)
+#define RADIANS_2_DEGREE(x) (((x) * 180.0) / XCAM_PI)
 #endif
 
 #define XCAM_VECT2_OPERATOR_VECT2(op)                       \
@@ -157,11 +153,11 @@
     inline bool operator == (const VectorN<T, N>& rhs) const;
 
     inline T& operator [] (uint32_t index) {
-        XCAM_ASSERT(index >= 0 && index < N);
+        XCAM_ASSERT(index < N);
         return data[index];
     }
     inline const T& operator [] (uint32_t index) const {
-        XCAM_ASSERT(index >= 0 && index < N);
+        XCAM_ASSERT(index < N);
         return data[index];
     }
 
@@ -521,15 +517,11 @@
     inline void eye ();
 
     inline T& at (uint32_t row, uint32_t col) {
-        XCAM_ASSERT(row >= 0 && row < N);
-        XCAM_ASSERT(col >= 0 && col < N);
-
+        XCAM_ASSERT(row < N && col < N);
         return data[row * N + col];
     };
     inline const T& at (uint32_t row, uint32_t col) const {
-        XCAM_ASSERT(row >= 0 && row < N);
-        XCAM_ASSERT(col >= 0 && col < N);
-
+        XCAM_ASSERT(row < N && col < N);
         return data[row * N + col];
     };
 
diff --git a/xcore/worker.cpp b/xcore/worker.cpp
index 6d8a7ab..c4b52d0 100644
--- a/xcore/worker.cpp
+++ b/xcore/worker.cpp
@@ -25,6 +25,8 @@
 Worker::Worker (const char *name, const SmartPtr<Callback> &cb)
     : _name (NULL)
     , _callback (cb)
+    , _global (1, 1, 1)
+    , _local (1, 1, 1)
 {
     if (name)
         _name = strndup (name, XCAM_MAX_STR_SIZE);
@@ -69,6 +71,31 @@
         _callback->work_status (this, args, error);
 }
 
+bool
+Worker::set_global_size (const WorkSize &size)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, size.value[0] && size.value[1] && size.value[2], false,
+        "Worker(%s) set global size(x:%d, y:%d, z:%d) failed.",
+        XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]);
+
+    _global = size;
+    return true;
+}
+
+bool
+Worker::set_local_size (const WorkSize &size)
+{
+    XCAM_FAIL_RETURN (
+        ERROR, size.value[0] && size.value[1] && size.value[2], false,
+        "Worker(%s) set local size(x:%d, y:%d, z:%d) failed.",
+        XCAM_STR (get_name ()), size.value[0], size.value[1], size.value[2]);
+
+    _local = size;
+    return true;
+}
+
+
 #if ENABLE_FUNC_OBJ
 bool
 Worker::set_func_obj (const SmartPtr<FuncObj> &obj)
diff --git a/xcore/worker.h b/xcore/worker.h
index 16807c1..9a4eec0 100644
--- a/xcore/worker.h
+++ b/xcore/worker.h
@@ -23,6 +23,8 @@
 
 #include <xcam_std.h>
 
+#define WORK_MAX_DIM 3
+
 #define ENABLE_FUNC_OBJ 0
 
 #define DECLARE_WORK_CALLBACK(CbClass, Handler, mem_func)                 \
@@ -38,6 +40,15 @@
 
 namespace XCam {
 
+struct WorkSize {
+    uint32_t value[WORK_MAX_DIM];
+    WorkSize (uint32_t x = 1, uint32_t y = 1, uint32_t z = 1) {
+        value[0] = x;
+        value[1] = y;
+        value[2] = z;
+    }
+};
+
 class Worker
     : public RefObj
 {
@@ -82,6 +93,15 @@
     const char *get_name () const {
         return _name;
     }
+    bool set_global_size (const WorkSize &size);
+    const WorkSize &get_global_size () const {
+        return _global;
+    }
+    bool set_local_size (const WorkSize &size);
+    const WorkSize &get_local_size () const {
+        return _local;
+    }
+
 #if ENABLE_FUNC_OBJ
     bool set_func_obj (const SmartPtr<FuncObj> &obj);
 #endif
@@ -99,6 +119,9 @@
 private:
     char                      *_name;
     SmartPtr<Callback>         _callback;
+    WorkSize                   _global;
+    WorkSize                   _local;
+
 #if ENABLE_FUNC_OBJ
     SmartPtr<FuncObj>          _func_obj;
 #endif
diff --git a/xcore/xcam_analyzer.cpp b/xcore/xcam_analyzer.cpp
index 8191a79..13ee457 100644
--- a/xcore/xcam_analyzer.cpp
+++ b/xcore/xcam_analyzer.cpp
@@ -118,7 +118,9 @@
     if (name)
         _name = strndup (name, XCAM_MAX_STR_SIZE);
 
-    _analyzer_thread  = new AnalyzerThread (this);
+    SmartPtr<AnalyzerThread> thread= new AnalyzerThread (this);
+    XCAM_ASSERT (thread.ptr ());
+    _analyzer_thread = thread;
 }
 
 XAnalyzer::~XAnalyzer()
diff --git a/xcore/xcam_utils.cpp b/xcore/xcam_utils.cpp
index 4393961..246be93 100644
--- a/xcore/xcam_utils.cpp
+++ b/xcore/xcam_utils.cpp
@@ -32,11 +32,11 @@
     const float bowl_x, const float bowl_y,
     const uint32_t img_width)
 {
-    float offset_radian = (bowl_x < 0.0f) ? PI : ((bowl_y >= 0.0f) ? 2.0f * PI : 0.0f);
-    float arctan_radian = (bowl_x != 0.0f) ? atan (-bowl_y / bowl_x) : ((bowl_y >= 0.0f) ? -PI / 2.0f : PI / 2.0f);
+    float offset_radian = (bowl_x < 0.0f) ? XCAM_PI : ((bowl_y >= 0.0f) ? 2.0f * XCAM_PI : 0.0f);
+    float arctan_radian = (bowl_x != 0.0f) ? atan (-bowl_y / bowl_x) : ((bowl_y >= 0.0f) ? -XCAM_PI / 2.0f : XCAM_PI / 2.0f);
 
     float img_x = arctan_radian + offset_radian;
-    img_x *= img_width / (2.0f * PI);
+    img_x *= img_width / (2.0f * XCAM_PI);
     return XCAM_CLAMP (img_x, 0.0f, img_width - 1.0f);
 }
 
@@ -95,10 +95,10 @@
     float b = config.b;
     float c = config.c;
 
-    float wall_image_height = config.wall_height / (float)(config.wall_height + config.ground_length) * (float)img_height;
-    float ground_image_height = (float)img_height - wall_image_height;
+    float wall_image_height = config.wall_height / (config.wall_height + config.ground_length) * img_height;
+    float ground_image_height = img_height - wall_image_height;
 
-    float z_step = (float)config.wall_height / wall_image_height;
+    float z_step = config.wall_height / wall_image_height;
     float angle_step = fabs(config.angle_end - config.angle_start) / img_width;
 
     if(img_pos.y < wall_image_height) {
@@ -106,13 +106,13 @@
         angle = degree2radian (config.angle_start + img_pos.x * angle_step);
         float r2 = 1 - (world.z - config.center_z) * (world.z - config.center_z) / (c * c);
 
-        if(XCAM_DOUBLE_EQUAL_AROUND (angle, PI / 2)) {
+        if(XCAM_DOUBLE_EQUAL_AROUND (angle, XCAM_PI / 2)) {
             world.x = 0.0f;
             world.y = -sqrt(r2 * b * b);
-        } else if (XCAM_DOUBLE_EQUAL_AROUND (angle, PI * 3 / 2)) {
+        } else if (XCAM_DOUBLE_EQUAL_AROUND (angle, XCAM_PI * 3 / 2)) {
             world.x = 0.0f;
             world.y = sqrt(r2 * b * b);
-        } else if((angle < PI / 2) || (angle > PI * 3 / 2)) {
+        } else if((angle < XCAM_PI / 2) || (angle > XCAM_PI * 3 / 2)) {
             world.x = sqrt(r2 * a * a * b * b / (b * b + a * a * tan(angle) * tan(angle)));
             world.y = -world.x * tan(angle);
         } else {
@@ -124,7 +124,6 @@
         b = b * sqrt(1 - config.center_z * config.center_z / (c * c));
 
         float ratio_ab = b / a;
-
         float step_b = config.ground_length / ground_image_height;
 
         b = b - (img_pos.y - wall_image_height) * step_b;
@@ -132,13 +131,13 @@
 
         angle = degree2radian (config.angle_start + img_pos.x * angle_step);
 
-        if(XCAM_DOUBLE_EQUAL_AROUND (angle, PI / 2)) {
+        if(XCAM_DOUBLE_EQUAL_AROUND (angle, XCAM_PI / 2)) {
             world.x = 0.0f;
             world.y = -b;
-        } else if (XCAM_DOUBLE_EQUAL_AROUND (angle, PI * 3 / 2)) {
+        } else if (XCAM_DOUBLE_EQUAL_AROUND (angle, XCAM_PI * 3 / 2)) {
             world.x = 0.0f;
             world.y = b;
-        } else if((angle < PI / 2) || (angle > PI * 3 / 2)) {
+        } else if((angle < XCAM_PI / 2) || (angle > XCAM_PI * 3 / 2)) {
             world.x = a * b / sqrt(b * b + a * a * tan(angle) * tan(angle));
             world.y = -world.x * tan(angle);
         } else {
@@ -193,13 +192,13 @@
     if (dist_start == 0) {
         weight_start = 10000000.0;
     } else {
-        weight_start = ((double)dist_sum / dist_start);
+        weight_start = (dist_sum / dist_start);
     }
 
     if (dist_end == 0) {
         weight_end = 10000000.0;
     } else {
-        weight_end = ((double)dist_sum / dist_end);
+        weight_end = (dist_sum / dist_end);
     }
 
     value = (value_start * weight_start + value_end * weight_end) / (weight_start + weight_end);
@@ -227,36 +226,35 @@
     double dist_sum = 0;
     double value = 0;
 
-    dist_lt = (double)abs(ref_curr_x - ref_lt_x) + (double)abs(ref_curr_y - ref_lt_y);
-    dist_rt = (double)abs(ref_curr_x - ref_rt_x) + (double)abs(ref_curr_y - ref_rt_y);
-    dist_lb = (double)abs(ref_curr_x - ref_lb_x) + (double)abs(ref_curr_y - ref_lb_y);
-    dist_rb = (double)abs(ref_curr_x - ref_rb_x) + (double)abs(ref_curr_y - ref_rb_y);
+    dist_lt = abs(ref_curr_x - ref_lt_x) + abs(ref_curr_y - ref_lt_y);
+    dist_rt = abs(ref_curr_x - ref_rt_x) + abs(ref_curr_y - ref_rt_y);
+    dist_lb = abs(ref_curr_x - ref_lb_x) + abs(ref_curr_y - ref_lb_y);
+    dist_rb = abs(ref_curr_x - ref_rb_x) + abs(ref_curr_y - ref_rb_y);
     dist_sum = dist_lt + dist_rt + dist_lb + dist_rb;
 
     if (dist_lt == 0) {
         weight_lt = 10000000.0;
     } else {
-        weight_lt = ((float)dist_sum / dist_lt);
+        weight_lt = (dist_sum / dist_lt);
     }
     if (dist_rt == 0) {
         weight_rt = 10000000.0;
     } else {
-        weight_rt = ((float)dist_sum / dist_rt);
+        weight_rt = (dist_sum / dist_rt);
     }
     if (dist_lb == 0) {
         weight_lb = 10000000.0;
     } else {
-        weight_lb = ((float)dist_sum / dist_lb);
+        weight_lb = (dist_sum / dist_lb);
     }
     if (dist_rb == 0) {
         weight_rb = 10000000.0;
     } else {
-        weight_rb = ((float)dist_sum / dist_rt);
+        weight_rb = (dist_sum / dist_rt);
     }
 
-    value = (double)floor ( (value_lt * weight_lt + value_rt * weight_rt +
-                             value_lb * weight_lb + value_rb * weight_rb) /
-                            (weight_lt + weight_rt + weight_lb + weight_rb) + 0.5 );
+    value = floor ((value_lt * weight_lt + value_rt * weight_rt + value_lb * weight_lb + value_rb * weight_rb) /
+                   (weight_lt + weight_rt + weight_lb + weight_rb) + 0.5);
     return value;
 }
 
@@ -272,7 +270,7 @@
     table[radius] = 1.0f;
 
     for (i = 0; i < radius; i++)  {
-        dis = ((float)i - radius) * ((float)i - radius);
+        dis = (i - radius) * (i - radius);
         table[i] = table[scale - i - 1] = exp(-dis / (2.0f * sigma * sigma));
         sum += table[i] * 2.0f;
     }
diff --git a/xcore/xcam_utils.h b/xcore/xcam_utils.h
index 492744a..f72efa0 100644
--- a/xcore/xcam_utils.h
+++ b/xcore/xcam_utils.h
@@ -64,6 +64,13 @@
 void dump_buf_perfix_path (const SmartPtr<VideoBuffer> buf, const char *prefix_name);
 bool dump_video_buf (const SmartPtr<VideoBuffer> buf, const char *file_name);
 
+SmartPtr<VideoBuffer>
+external_buf_to_once_map_buf (
+    uint8_t* buf, uint32_t format,
+    uint32_t width, uint32_t height,
+    uint32_t aligned_width, uint32_t aligned_height,
+    uint32_t size);
+
 };
 
 #endif //XCAM_UTILS_H