Sync with master: Vulkan GPU pipeline and other fixes

Syncs rvc-qpr branch with master

CL combines all changes for Vulkan based SV2D pipeline and other related fixes:

2020-12-13 Merge "Adds validity masks filenames for core_lib"
2020-12-11 Pass the correct Graphic Buffer for GPU solution.
2020-12-10 Adds validity masks filenames for core_lib
2020-12-10 Fix a null pointer exception for SV2D
2020-12-09 Introduce per-frame logic for GPU process.
2020-11-19 Make use of the GpuAccelerationEnabled flag.
2020-11-05 Add sv2dGpuAcceleration flag in SV Config
2020-10-14 Fix a bug caused by fetching EVS camera too late.
2020-10-12 Add sys trace loggings for Surround View Service
2020-10-08 Adds tests for sv 2d and 3d sessions
2020-10-08 Fixes sv config tests and xml files

Bug: 170322090

Test:
m -j
atest sv_2d_session_tests
atest sv_3d_session_tests

Below are merged-in tags to avoid auto-merger for CLs already in master:
Merged-In: I46b45bda576920faa3753b234ccda1d29ee0ed1d
Merged-In: Idffd0b4c0d5d5e9cf46125f215373c5ba9a4dc21
Merged-In: I77c4db32276a922a7db5de69f33062998f206a43
Merged-In: Ifc6bf5e01546ccabdcbc88e7973c24199e9924e6
Merged-In: Ib1214429fb4af79432340bf02f2796f65292a9bb
Merged-In: I83f641222f525cfe8d7a831ed9d49776743513c1
Merged-In: I28cdc0af8870da9e0e59dbf15aa4509afa4f6a3f
Merged-In: I62933bd705262b93c9cbafa5c6dadf356e44a856
Merged-In: I00dcf3cc731e7c490a7f2b1293fb3e90d8a5af67
Merged-In: Ibafccc9da0d1e3f1cbfc4d23d2f64a08f77e37f3
Merged-In: I39cd4b28b7c0fea30713a0b59d93d8678a134a3f

Change-Id: I47e2c4475583fc775b1a0e992352c3a25fb00664
diff --git a/cpp/surround_view/app/SurroundViewServiceCallback.cpp b/cpp/surround_view/app/SurroundViewServiceCallback.cpp
index 05a598f..12dba98 100644
--- a/cpp/surround_view/app/SurroundViewServiceCallback.cpp
+++ b/cpp/surround_view/app/SurroundViewServiceCallback.cpp
@@ -144,17 +144,15 @@
         return false;
     }
 
-    // Create a dummy pbuffer so we have a surface to bind -- we never intend
+    // Create a placeholder pbuffer so we have a surface to bind -- we never intend
     // to draw to this because attachRenderTarget will be called first.
     EGLint surface_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
-    EGLSurface sDummySurface = eglCreatePbufferSurface(display, egl_config,
-                                                       surface_attribs);
-    if (sDummySurface == EGL_NO_SURFACE) {
-        LOG(ERROR) << "Failed to create OpenGL ES Dummy surface: "
-                   << getEGLError();
+    EGLSurface sPlaceholderSurface = eglCreatePbufferSurface(display, egl_config, surface_attribs);
+    if (sPlaceholderSurface == EGL_NO_SURFACE) {
+        LOG(ERROR) << "Failed to create OpenGL ES Placeholder surface: " << getEGLError();
         return false;
     } else {
-        LOG(INFO) << "Dummy surface looks good!  :)";
+        LOG(INFO) << "Placeholder surface looks good!  :)";
     }
 
     //
@@ -169,7 +167,7 @@
     }
 
     // Activate our render target for drawing
-    if (!eglMakeCurrent(display, sDummySurface, sDummySurface, context)) {
+    if (!eglMakeCurrent(display, sPlaceholderSurface, sPlaceholderSurface, context)) {
         LOG(ERROR) << "Failed to make the OpenGL ES Context current: "
                    << getEGLError();
         return false;
diff --git a/cpp/surround_view/service-impl/Android.bp b/cpp/surround_view/service-impl/Android.bp
index d05c4d8..c82857f 100644
--- a/cpp/surround_view/service-impl/Android.bp
+++ b/cpp/surround_view/service-impl/Android.bp
@@ -174,9 +174,11 @@
         "libhardware",
         "libhidlbase",
         "libhidlmemory",
+        "libnativewindow",
         "libio_module",
         "libui",
         "libutils",
+        "libvulkan",
         "libvhal_handler",
     ],
     required : [
@@ -205,11 +207,11 @@
 }
 
 cc_test{
-    name : "sv_session_tests",
+    name : "sv_2d_session_tests",
     test_suites : ["device-tests"],
     vendor : true,
     srcs : [
-        "SurroundViewSessionTests.cpp",
+        "SurroundView2dSessionTests.cpp",
         "mock-evs/MockEvsCamera.cpp",
         "mock-evs/MockEvsEnumerator.cpp",
         "mock-evs/MockSurroundViewCallback.cpp",
@@ -253,6 +255,70 @@
             enabled : true,
         },
     },
+    required : [
+        "sample_car.obj",
+        "sample_car_material.mtl",
+        "sv_sample_config.xml",
+        "sv_sample_car_model_config.xml",
+    ],
+}
+
+cc_test{
+    name : "sv_3d_session_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : [
+        "SurroundView3dSessionTests.cpp",
+        "mock-evs/MockEvsCamera.cpp",
+        "mock-evs/MockEvsEnumerator.cpp",
+        "mock-evs/MockSurroundViewCallback.cpp",
+    ],
+    include_dirs: [
+        "packages/services/Car/evs/sampleDriver",
+    ],
+    shared_libs : [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.automotive.vehicle@2.0",
+        "android.hidl.memory@1.0",
+        "android.hidl.allocator@1.0",
+        "libanimation_module",
+        "libbase",
+        "libbinder",
+        "libcamera_metadata",
+        "libcore_lib_shared",
+        "libcutils",
+        "libevsconfigmanager",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libio_module",
+        "libsvsession",
+        "libtinyxml2",
+        "libui",
+        "libutils",
+        "libvhal_handler",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled : false,
+    arch : {
+        arm64 : {
+            enabled : true,
+        },
+        x86 : {
+            enabled : true,
+        },
+        x86_64 : {
+            enabled : true,
+        },
+    },
+    required : [
+        "sample_car.obj",
+        "sample_car_material.mtl",
+        "sv_sample_config.xml",
+        "sv_sample_car_model_config.xml",
+    ],
 }
 
 cc_binary{
@@ -332,6 +398,7 @@
         "libdl",
         "libz",
         "liblog",
+        "libvulkan",
     ],
 }
 
diff --git a/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp b/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp
index 916002b..81f8192 100644
--- a/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp
+++ b/cpp/surround_view/service-impl/CarModelConfigReaderTests.cpp
@@ -34,7 +34,7 @@
 
 TEST(CarModelConfigReaderTests, CarModelReadConfigSuccess) {
     AnimationConfig animationConfig;
-    EXPECT_EQ(ReadCarModelConfig("/vendor/automotive/sv/sv_sample_car_model_config.xml",
+    EXPECT_EQ(ReadCarModelConfig("/vendor/etc/automotive/sv/sv_sample_car_model_config.xml",
                                  &animationConfig),
               IOStatus::OK);
 
@@ -45,7 +45,7 @@
     {
         AnimationInfo doorAnimation = animationConfig.animations.at(0);
         EXPECT_EQ(doorAnimation.partId, "door");
-        EXPECT_EQ(doorAnimation.childIds.size(), 2);
+        EXPECT_EQ(doorAnimation.childIds.size(), 1);
         EXPECT_EQ(doorAnimation.pose, gMat4Identity);
 
         EXPECT_EQ(doorAnimation.rotationOpsMap.size(), 1);
diff --git a/cpp/surround_view/service-impl/ConfigReader.cpp b/cpp/surround_view/service-impl/ConfigReader.cpp
index cc97d4e..cc1c81b 100644
--- a/cpp/surround_view/service-impl/ConfigReader.cpp
+++ b/cpp/surround_view/service-impl/ConfigReader.cpp
@@ -132,6 +132,10 @@
             RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "LowQuality",
                                                  &sv2dParams->low_quality_blending));
         }
+
+        // GPU Acceleration enabled or not
+        RETURN_IF_FALSE(ReadValue(param2dElem, "GpuAccelerationEnabled",
+                                  &sv2dParams->gpu_acceleration_enabled));
     }
     return true;
 }
diff --git a/cpp/surround_view/service-impl/ConfigReaderTests.cpp b/cpp/surround_view/service-impl/ConfigReaderTests.cpp
index ef51a5f..7d12322 100644
--- a/cpp/surround_view/service-impl/ConfigReaderTests.cpp
+++ b/cpp/surround_view/service-impl/ConfigReaderTests.cpp
@@ -36,7 +36,7 @@
 
 TEST(ConfigReaderTests, ReadConfigSuccess) {
     SurroundViewConfig svConfig;
-    EXPECT_EQ(ReadSurroundViewConfig("/vendor/automotive/sv/sv_sample_config.xml", &svConfig),
+    EXPECT_EQ(ReadSurroundViewConfig("/vendor/etc/automotive/sv/sv_sample_config.xml", &svConfig),
               IOStatus::OK);
 
     EXPECT_EQ(svConfig.version, "1.0");
@@ -45,26 +45,27 @@
     EXPECT_EQ(svConfig.cameraConfig.evsGroupId, "v4l2loopback_group0");
 
     // Camera Ids
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[0], "/dev/video90");
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[1], "/dev/video91");
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[2], "/dev/video92");
-    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[3], "/dev/video93");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[0], "/dev/video60");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[1], "/dev/video61");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[2], "/dev/video62");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[3], "/dev/video63");
 
     // Masks
     EXPECT_EQ(svConfig.cameraConfig.maskFilenames.size(), 4);
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[0], "/vendor/mask_front.png");
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[1], "/vendor/mask_right.png");
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[2], "/vendor/mask_rear.png");
-    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[3], "/vendor/mask_left.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[0], "/vendor/etc/automotive/sv/mask_front.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[1], "/vendor/etc/automotive/sv/mask_right.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[2], "/vendor/etc/automotive/sv/mask_rear.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[3], "/vendor/etc/automotive/sv/mask_left.png");
 
     // Surround view 2D
     EXPECT_EQ(svConfig.sv2dConfig.sv2dEnabled, true);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.width, 600);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.height, 900);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.width, 6.0);
-    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.height, 9.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.width, 768);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.height, 1024);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.width, 9.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.height, 12.0);
     EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.x, 0.0);
     EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.y, 0.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.gpu_acceleration_enabled, false);
     EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.width, 2.0);
     EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.height, 3.0);
     EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.x, 1.0);
@@ -78,12 +79,12 @@
     EXPECT_EQ(svConfig.sv3dConfig.sv3dEnabled, true);
     EXPECT_NE(svConfig.sv3dConfig.carModelConfigFile, "");
     EXPECT_NE(svConfig.sv3dConfig.carModelObjFile, "");
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_radius, 6.0);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_divisions, 20);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_height, 5.0);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_divisions, 30);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.angular_divisions, 50);
-    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_coefficient, 2.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_radius, 8.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_divisions, 50);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_height, 6.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_divisions, 50);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.angular_divisions, 90);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_coefficient, 3.0);
     EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_shadows, true);
     EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_reflections, true);
 }
diff --git a/cpp/surround_view/service-impl/ObjReaderTests.cpp b/cpp/surround_view/service-impl/ObjReaderTests.cpp
index 9dae171..1c86737 100644
--- a/cpp/surround_view/service-impl/ObjReaderTests.cpp
+++ b/cpp/surround_view/service-impl/ObjReaderTests.cpp
@@ -33,9 +33,9 @@
 namespace implementation {
 namespace {
 
-TEST(ObjParserTests, ReadCubeSuccess) {
+TEST(ObjParserTests, ReadObjFileSuccess) {
     std::map<std::string, CarPart> carPartsMap;
-    EXPECT_TRUE(ReadObjFromFile("/etc/automotive/sv/cube.obj", &carPartsMap));
+    EXPECT_TRUE(ReadObjFromFile("vendor/etc/automotive/sv/sample_car.obj", &carPartsMap));
     EXPECT_NE(carPartsMap.size(), 0);
 }
 
diff --git a/cpp/surround_view/service-impl/SurroundView2dSession.cpp b/cpp/surround_view/service-impl/SurroundView2dSession.cpp
index cbf652e..a92372c 100644
--- a/cpp/surround_view/service-impl/SurroundView2dSession.cpp
+++ b/cpp/surround_view/service-impl/SurroundView2dSession.cpp
@@ -13,20 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define ATRACE_TAG ATRACE_TAG_CAMERA
 
 #include "SurroundView2dSession.h"
 
+#include "CameraUtils.h"
+
 #include <android-base/logging.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware_buffer.h>
 #include <system/camera_metadata.h>
 #include <utils/SystemClock.h>
+#include <utils/Trace.h>
+#include <vndk/hardware_buffer.h>
 
 #include <thread>
 
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-
-#include "CameraUtils.h"
-
 using ::std::adopt_lock;
 using ::std::lock;
 using ::std::lock_guard;
@@ -63,7 +65,6 @@
 } RawStreamConfig;
 
 static const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
-static const uint8_t kGrayColor = 128;
 static const int kInputNumChannels = 4;
 static const int kOutputNumChannels = 3;
 static const int kNumFrames = 4;
@@ -85,6 +86,8 @@
 
 Return<void> SurroundView2dSession::FramesHandler::deliverFrame_1_1(
     const hidl_vec<BufferDesc_1_1>& buffers) {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
     mSession->mSequenceId++;
 
@@ -132,20 +135,48 @@
             return {};
         }
 
-        for (int i = 0; i < kNumFrames; i++) {
-            LOG(DEBUG) << "Copying buffer from camera ["
-                       << buffers[indices[i]].deviceId
-                       << "] to Surround View Service";
-            mSession->copyFromBufferToPointers(buffers[indices[i]],
-                                               mSession->mInputPointers[i]);
+        if (mSession->mGpuAccelerationEnabled) {
+            for (int i = 0; i < kNumFrames; i++) {
+                LOG(DEBUG) << "Importing graphic buffer from camera ["
+                           << buffers[indices[i]].deviceId << "]";
+                const AHardwareBuffer_Desc* pDesc = reinterpret_cast<const AHardwareBuffer_Desc*>(
+                        &buffers[indices[i]].buffer.description);
+
+                AHardwareBuffer* hardwareBuffer;
+                status_t status = AHardwareBuffer_createFromHandle(
+                        pDesc, buffers[indices[i]].buffer.nativeHandle,
+                        AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer);
+
+                if (status != NO_ERROR) {
+                    LOG(ERROR) << "Can't create AHardwareBuffer from handle. Error: " << status;
+                    return {};
+                }
+
+                mSession->mInputPointers[i].gpu_data_pointer = static_cast<void*>(hardwareBuffer);
+
+                // Keep a reference to the EVS graphic buffers, so we can
+                // release them after Surround View stitching is done.
+                mSession->mEvsGraphicBuffers = buffers;
+            }
+        } else {
+            for (int i = 0; i < kNumFrames; i++) {
+                LOG(DEBUG) << "Copying buffer from camera [" << buffers[indices[i]].deviceId
+                           << "] to Surround View Service";
+                mSession->copyFromBufferToPointers(buffers[indices[i]],
+                                                   mSession->mInputPointers[i]);
+            }
+
+            // On the CPU version, we do not need to hold the Graphic Buffers
+            // any more since they are copied already.
+            mCamera->doneWithFrame_1_1(buffers);
         }
     }
 
-    mCamera->doneWithFrame_1_1(buffers);
-
     // Notify the session that a new set of frames is ready
     mSession->mFramesSignal.notify_all();
 
+    ATRACE_END();
+
     return {};
 }
 
@@ -182,10 +213,12 @@
 
 bool SurroundView2dSession::copyFromBufferToPointers(
     BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
 
     AHardwareBuffer_Desc* pDesc =
         reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
 
+    ATRACE_BEGIN("Create Graphic Buffer");
     // create a GraphicBuffer from the existing handle
     sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
         buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
@@ -205,7 +238,9 @@
                   << " format: " << pDesc->format
                   << " stride: " << pDesc->stride;
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Lock input buffer (gpu to cpu)");
     // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
     // lock, return false.
     void* inputDataPtr;
@@ -219,16 +254,28 @@
     } else {
         LOG(INFO) << "Managed to get read access to GraphicBuffer";
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Copy input data");
     // Both source and destination are with 4 channels
     memcpy(pointers.cpu_data_pointer, inputDataPtr,
            pDesc->height * pDesc->width * kInputNumChannels);
     LOG(DEBUG) << "Buffer copying finished";
+    ATRACE_END();
+
+    ATRACE_BEGIN("Unlock input buffer (cpu to gpu)");
+    inputBuffer->unlock();
+    ATRACE_END();
+
+    // Paired with ATRACE_BEGIN in the beginning of the method.
+    ATRACE_END();
 
     return true;
 }
 
 void SurroundView2dSession::processFrames() {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     while (true) {
         {
             unique_lock<mutex> lock(mAccessLock);
@@ -259,15 +306,15 @@
         mStream = nullptr;
         LOG(DEBUG) << "Stream marked STOPPED.";
     }
+
+    ATRACE_END();
 }
 
 SurroundView2dSession::SurroundView2dSession(sp<IEvsEnumerator> pEvs,
                                              IOModuleConfig* pConfig)
     : mEvs(pEvs),
       mIOModuleConfig(pConfig),
-      mStreamState(STOPPED) {
-    mEvsCameraIds = {"0", "1", "2", "3"};
-}
+      mStreamState(STOPPED) {}
 
 SurroundView2dSession::~SurroundView2dSession() {
     // In case the client did not call stopStream properly, we should stop the
@@ -281,6 +328,8 @@
     }
 
     mEvs->closeCamera(mCamera);
+
+    // TODO(b/175176576): properly release the mInputPointers and mOutputPointer
 }
 
 // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
@@ -447,9 +496,12 @@
     return {};
 }
 
+// TODO(b/175176765): implement a GPU version of this method separately.
 bool SurroundView2dSession::handleFrames(int sequenceId) {
     LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
 
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     // TODO(b/157498592): Now only one sets of EVS input frames and one SV
     // output frame is supported. Implement buffer queue for both of them.
     {
@@ -458,93 +510,111 @@
         if (mFramesRecord.inUse) {
             LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
             mStream->notify(SvEvent::FRAME_DROPPED);
+
+            // For GPU solution only (the frames were released already for CPU solution).
+            if (mGpuAccelerationEnabled) {
+                mCamera->doneWithFrame_1_1(mEvsGraphicBuffers);
+            }
             return true;
         }
     }
 
-    if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
-        LOG(DEBUG) << "Config changed. Re-allocate memory."
-                   << " Old width: "
-                   << mOutputWidth
-                   << " Old height: "
-                   << mOutputHeight
-                   << " New width: "
-                   << mConfig.width
-                   << " New height: "
-                   << mHeight;
-        delete[] static_cast<char*>(mOutputPointer.data_pointer);
-        mOutputWidth = mConfig.width;
-        mOutputHeight = mHeight;
-        mOutputPointer.height = mOutputHeight;
-        mOutputPointer.width = mOutputWidth;
-        mOutputPointer.format = Format::RGB;
-        mOutputPointer.data_pointer =
-            new char[mOutputHeight * mOutputWidth * kOutputNumChannels];
+    // TODO(b/175177030): modifying the width/length on the fly is not supported by the GPU approach
+    // yet.
+    if (!mGpuAccelerationEnabled) {
+        if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
+            LOG(DEBUG) << "Config changed. Re-allocate memory."
+                       << " Old width: " << mOutputWidth << " Old height: " << mOutputHeight
+                       << " New width: " << mConfig.width << " New height: " << mHeight;
+            delete[] static_cast<char*>(mOutputPointer.cpu_data_pointer);
+            mOutputWidth = mConfig.width;
+            mOutputHeight = mHeight;
+            mOutputPointer.height = mOutputHeight;
+            mOutputPointer.width = mOutputWidth;
+            mOutputPointer.format = Format::RGB;
+            mOutputPointer.cpu_data_pointer =
+                    static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
 
-        if (!mOutputPointer.data_pointer) {
-            LOG(ERROR) << "Memory allocation failed. Exiting.";
-            return false;
+            if (!mOutputPointer.cpu_data_pointer) {
+                LOG(ERROR) << "Memory allocation failed. Exiting.";
+                return false;
+            }
+
+            Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
+            mSurroundView->Update2dOutputResolution(size);
+
+            mSvTexture = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGB_888, 1,
+                                           GRALLOC_USAGE_HW_TEXTURE, "SvTexture");
+            if (mSvTexture->initCheck() == OK) {
+                LOG(INFO) << "Successfully allocated Graphic Buffer";
+            } else {
+                LOG(ERROR) << "Failed to allocate Graphic Buffer";
+                return false;
+            }
         }
-
-        Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
-        mSurroundView->Update2dOutputResolution(size);
-
-        mSvTexture = new GraphicBuffer(mOutputWidth,
-                                       mOutputHeight,
-                                       HAL_PIXEL_FORMAT_RGB_888,
-                                       1,
-                                       GRALLOC_USAGE_HW_TEXTURE,
-                                       "SvTexture");
-        if (mSvTexture->initCheck() == OK) {
-            LOG(INFO) << "Successfully allocated Graphic Buffer";
-        } else {
-            LOG(ERROR) << "Failed to allocate Graphic Buffer";
-            return false;
-        }
+        LOG(INFO) << "Output Pointer data format: " << mOutputPointer.format;
     }
 
-    LOG(INFO) << "Output Pointer data format: " << mOutputPointer.format;
+    ATRACE_BEGIN("SV core lib method: Get2dSurroundView");
+    const string gpuEnabledText = mGpuAccelerationEnabled ? " with GPU acceleration flag enabled"
+                                                          : " with GPU acceleration flag disabled";
     if (mSurroundView->Get2dSurroundView(mInputPointers, &mOutputPointer)) {
-        LOG(INFO) << "Get2dSurroundView succeeded";
+        LOG(INFO) << "Get2dSurroundView succeeded" << gpuEnabledText;
     } else {
-        LOG(ERROR) << "Get2dSurroundView failed. "
-                   << "Using memset to initialize to gray";
-        memset(mOutputPointer.data_pointer, kGrayColor,
-               mOutputHeight * mOutputWidth * kOutputNumChannels);
+        LOG(ERROR) << "Get2dSurroundView failed" << gpuEnabledText;
+    }
+    ATRACE_END();
+
+    // For GPU solution only (the frames were released already for CPU solution).
+    if (mGpuAccelerationEnabled) {
+        ATRACE_BEGIN("Release the evs frames");
+        mCamera->doneWithFrame_1_1(mEvsGraphicBuffers);
+        ATRACE_END();
     }
 
-    void* textureDataPtr = nullptr;
-    mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
-                     | GRALLOC_USAGE_SW_READ_NEVER,
-                     &textureDataPtr);
-    if (!textureDataPtr) {
-        LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
-        return false;
-    }
-
-    // Note: there is a chance that the stride of the texture is not the same
-    // as the width. For example, when the input frame is 1920 * 1080, the
-    // width is 1080, but the stride is 2048. So we'd better copy the data line
-    // by line, instead of single memcpy.
-    uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
-    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
-    const int readStride = mOutputWidth * kOutputNumChannels;
-    const int writeStride = mSvTexture->getStride() * kOutputNumChannels;
-    if (readStride == writeStride) {
-        memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+    ANativeWindowBuffer* buffer;
+    if (mGpuAccelerationEnabled) {
+        buffer = mOutputHolder->getNativeBuffer();
     } else {
-        for (int i=0; i<mSvTexture->getHeight(); i++) {
-            memcpy(writePtr, readPtr, readStride);
-            writePtr = writePtr + writeStride;
-            readPtr = readPtr + readStride;
+        ATRACE_BEGIN("Lock output texture (gpu to cpu)");
+        void* textureDataPtr = nullptr;
+        mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                         &textureDataPtr);
+        ATRACE_END();
+
+        if (!textureDataPtr) {
+            LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
+            return false;
         }
-    }
-    LOG(DEBUG) << "memcpy finished";
-    mSvTexture->unlock();
 
-    ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
-    LOG(DEBUG) << "ANativeWindowBuffer->handle: "
-               << buffer->handle;
+        ATRACE_BEGIN("Copy output result");
+        // Note: there is a chance that the stride of the texture is not the same
+        // as the width. For example, when the input frame is 1920 * 1080, the
+        // width is 1080, but the stride is 2048. So we'd better copy the data line
+        // by line, instead of single memcpy.
+        uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
+        uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.cpu_data_pointer);
+        const int readStride = mOutputWidth * kOutputNumChannels;
+        const int writeStride = mSvTexture->getStride() * kOutputNumChannels;
+        if (readStride == writeStride) {
+            memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+        } else {
+            for (int i = 0; i < mSvTexture->getHeight(); i++) {
+                memcpy(writePtr, readPtr, readStride);
+                writePtr = writePtr + writeStride;
+                readPtr = readPtr + readStride;
+            }
+        }
+        LOG(DEBUG) << "memcpy finished";
+        ATRACE_END();
+
+        ATRACE_BEGIN("Unlock output texture (cpu to gpu)");
+        mSvTexture->unlock();
+        ATRACE_END();
+
+        buffer = mSvTexture->getNativeBuffer();
+        LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
+    }
 
     {
         scoped_lock<mutex> lock(mAccessLock);
@@ -556,12 +626,19 @@
         AHardwareBuffer_Desc* pDesc =
             reinterpret_cast<AHardwareBuffer_Desc*>(
                 &svBuffer.hardwareBuffer.description);
-        pDesc->width = mOutputWidth;
-        pDesc->height = mOutputHeight;
+        if (mGpuAccelerationEnabled) {
+            pDesc->width = mOutputPointer.width;
+            pDesc->height = mOutputPointer.height;
+            pDesc->stride = mOutputHolder->getStride();
+            pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+        } else {
+            pDesc->width = mOutputWidth;
+            pDesc->height = mOutputHeight;
+            pDesc->stride = mSvTexture->getStride();
+            pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
+        }
         pDesc->layers = 1;
         pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
-        pDesc->stride = mSvTexture->getStride();
-        pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
         mFramesRecord.frames.timestampNs = elapsedRealtimeNano();
         mFramesRecord.frames.sequenceId = sequenceId;
 
@@ -569,12 +646,18 @@
         mStream->receiveFrames(mFramesRecord.frames);
     }
 
+    ATRACE_END();
+
     return true;
 }
 
+// TODO(b/175176765): consider to HW-specific initialization procedures into
+// separate methods.
 bool SurroundView2dSession::initialize() {
     lock_guard<mutex> lock(mAccessLock, adopt_lock);
 
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     if (!setupEvs()) {
         LOG(ERROR) << "Failed to setup EVS components for 2d session";
         return false;
@@ -587,32 +670,46 @@
     mSurroundView = unique_ptr<SurroundView>(Create());
 
     SurroundViewStaticDataParams params =
-            SurroundViewStaticDataParams(
-                    mCameraParams,
-                    mIOModuleConfig->sv2dConfig.sv2dParams,
-                    mIOModuleConfig->sv3dConfig.sv3dParams,
-                    vector<float>(std::begin(kUndistortionScales),
-                                  std::end(kUndistortionScales)),
-                    mIOModuleConfig->sv2dConfig.carBoundingBox,
-                    mIOModuleConfig->carModelConfig.carModel.texturesMap,
-                    mIOModuleConfig->carModelConfig.carModel.partsMap);
+            SurroundViewStaticDataParams(mCameraParams,
+                                         mIOModuleConfig->sv2dConfig.sv2dParams,
+                                         mIOModuleConfig->sv3dConfig.sv3dParams,
+                                         vector<float>(std::begin(kUndistortionScales),
+                                                       std::end(kUndistortionScales)),
+                                         mIOModuleConfig->sv2dConfig.carBoundingBox,
+                                         mIOModuleConfig->carModelConfig.carModel.texturesMap,
+                                         mIOModuleConfig->carModelConfig.carModel.partsMap);
+    mGpuAccelerationEnabled = mIOModuleConfig->sv2dConfig.sv2dParams.gpu_acceleration_enabled;
+
+    ATRACE_BEGIN("SV core lib method: SetStaticData");
     mSurroundView->SetStaticData(params);
+    ATRACE_END();
+
+    ATRACE_BEGIN("SV core lib method: Start2dPipeline");
+    const string gpuEnabledText = mGpuAccelerationEnabled ? "with GPU acceleration flag enabled"
+                                                          : "with GPU acceleration flag disabled";
     if (mSurroundView->Start2dPipeline()) {
-        LOG(INFO) << "Start2dPipeline succeeded";
+        LOG(INFO) << "Start2dPipeline succeeded " << gpuEnabledText;
     } else {
-        LOG(ERROR) << "Start2dPipeline failed";
+        LOG(ERROR) << "Start2dPipeline failed " << gpuEnabledText;
         return false;
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Allocate cpu buffers");
     mInputPointers.resize(kNumFrames);
     for (int i = 0; i < kNumFrames; i++) {
         mInputPointers[i].width = mCameraParams[i].size.width;
         mInputPointers[i].height = mCameraParams[i].size.height;
-        mInputPointers[i].format = Format::RGBA;
-        mInputPointers[i].cpu_data_pointer =
-                (void*)new uint8_t[mInputPointers[i].width *
-                                   mInputPointers[i].height *
-                                   kInputNumChannels];
+
+        // Only allocate CPU memory for CPU solution
+        // For GPU solutions, the Graphic Buffers from EVS will be converted and
+        // stored in gpu_data_pointer
+        if (!mGpuAccelerationEnabled) {
+            mInputPointers[i].format = Format::RGBA;
+            mInputPointers[i].cpu_data_pointer =
+                    static_cast<void*>(new char[mInputPointers[i].width * mInputPointers[i].height *
+                                                kInputNumChannels]);
+        }
     }
     LOG(INFO) << "Allocated " << kNumFrames << " input pointers";
 
@@ -625,21 +722,41 @@
 
     mOutputPointer.height = mOutputHeight;
     mOutputPointer.width = mOutputWidth;
-    mOutputPointer.format = Format::RGB;
-    mOutputPointer.data_pointer = new char[
-        mOutputHeight * mOutputWidth * kOutputNumChannels];
 
-    if (!mOutputPointer.data_pointer) {
-        LOG(ERROR) << "Memory allocation failed. Exiting.";
-        return false;
+    // Only allocate CPU memory for CPU solution
+    if (!mGpuAccelerationEnabled) {
+        mOutputPointer.format = Format::RGB;
+        mOutputPointer.cpu_data_pointer =
+                static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
+
+        if (!mOutputPointer.cpu_data_pointer) {
+            LOG(ERROR) << "Memory allocation failed. Exiting.";
+            return false;
+        }
     }
+    ATRACE_END();
 
-    mSvTexture = new GraphicBuffer(mOutputWidth,
-                                   mOutputHeight,
-                                   HAL_PIXEL_FORMAT_RGB_888,
-                                   1,
-                                   GRALLOC_USAGE_HW_TEXTURE,
-                                   "SvTexture");
+    ATRACE_BEGIN("Allocate output texture");
+    if (mGpuAccelerationEnabled) {
+        mOutputHolder = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGBA_8888,
+                                          1, GRALLOC_USAGE_HW_TEXTURE, "SvOutputHolder");
+        if (mOutputHolder->initCheck() == OK) {
+            LOG(INFO) << "Successfully allocated Graphic Buffer for SvOutputHolder";
+        } else {
+            LOG(ERROR) << "Failed to allocate Graphic Buffer for SvOutputHolder";
+            return false;
+        }
+        mOutputPointer.gpu_data_pointer = static_cast<void*>(mOutputHolder->toAHardwareBuffer());
+    } else {
+        mSvTexture = new GraphicBuffer(mOutputWidth, mOutputHeight, HAL_PIXEL_FORMAT_RGB_888, 1,
+                                       GRALLOC_USAGE_HW_TEXTURE, "SvTexture");
+        if (mSvTexture->initCheck() == OK) {
+            LOG(INFO) << "Successfully allocated Graphic Buffer";
+        } else {
+            LOG(ERROR) << "Failed to allocate Graphic Buffer";
+            return false;
+        }
+    }
 
     // Note: sv2dParams is in meters while mInfo must be in milli-meters.
     mInfo.width = mIOModuleConfig->sv2dConfig.sv2dParams.physical_size.width * 1000.0;
@@ -648,18 +765,16 @@
     mInfo.center.x = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.x * 1000.0;
     mInfo.center.y = mIOModuleConfig->sv2dConfig.sv2dParams.physical_center.y * 1000.0;
 
-    if (mSvTexture->initCheck() == OK) {
-        LOG(INFO) << "Successfully allocated Graphic Buffer";
-    } else {
-        LOG(ERROR) << "Failed to allocate Graphic Buffer";
-        return false;
-    }
-
     mIsInitialized = true;
+
+    ATRACE_END();
+
     return true;
 }
 
 bool SurroundView2dSession::setupEvs() {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     // Reads the camera related information from the config object
     const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
 
@@ -729,11 +844,17 @@
         LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
         return false;
     } else {
-        LOG(INFO) << "Camera " << camId << " is opened successfully";
+        LOG(INFO) << "Logical camera " << camId << " is opened successfully";
+    }
+
+    mEvsCameraIds = mIOModuleConfig->cameraConfig.evsCameraIds;
+    if (mEvsCameraIds.size() < kNumFrames) {
+        LOG(ERROR) << "Incorrect camera info is stored in the camera config";
+        return false;
     }
 
     map<string, AndroidCameraParams> cameraIdToAndroidParameters;
-    for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
+    for (const auto& id : mEvsCameraIds) {
         AndroidCameraParams params;
         if (getAndroidCameraParams(mCamera, id, params)) {
             cameraIdToAndroidParameters.emplace(id, params);
@@ -755,10 +876,17 @@
         camera.circular_fov = 179;
     }
 
+    // Add validity mask filenames.
+    for (int i = 0; i < mCameraParams.size(); i++) {
+        mCameraParams[i].validity_mask_filename = mIOModuleConfig->cameraConfig.maskFilenames[i];
+    }
+    ATRACE_END();
     return true;
 }
 
 bool SurroundView2dSession::startEvs() {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     mFramesHandler = new FramesHandler(mCamera, this);
     Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
     if (result != EvsResult::OK) {
@@ -768,6 +896,8 @@
         LOG(INFO) << "Video stream was started successfully";
     }
 
+    ATRACE_END();
+
     return true;
 }
 
diff --git a/cpp/surround_view/service-impl/SurroundView2dSession.h b/cpp/surround_view/service-impl/SurroundView2dSession.h
index 8061f23..e7a9e17 100644
--- a/cpp/surround_view/service-impl/SurroundView2dSession.h
+++ b/cpp/surround_view/service-impl/SurroundView2dSession.h
@@ -169,10 +169,14 @@
     // TODO(b/158479099): Rename it to mMappingInfo
     Sv2dMappingInfo mInfo GUARDED_BY(mAccessLock);
     int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
+    sp<GraphicBuffer> mOutputHolder;
 
     sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
 
     bool mIsInitialized GUARDED_BY(mAccessLock) = false;
+
+    bool mGpuAccelerationEnabled;
+    hidl_vec<BufferDesc_1_1> mEvsGraphicBuffers;
 };
 
 }  // namespace implementation
diff --git a/cpp/surround_view/service-impl/SurroundView2dSessionTests.cpp b/cpp/surround_view/service-impl/SurroundView2dSessionTests.cpp
new file mode 100644
index 0000000..a452ddf
--- /dev/null
+++ b/cpp/surround_view/service-impl/SurroundView2dSessionTests.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurroundView2dSessionTests"
+
+#include "mock-evs/MockEvsEnumerator.h"
+#include "mock-evs/MockSurroundViewCallback.h"
+
+#include "IOModule.h"
+#include "SurroundView2dSession.h"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+#include <android-base/logging.h>
+
+#include <gtest/gtest.h>
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
+
+using android::hardware::automotive::sv::V1_0::Sv2dMappingInfo;
+using android::hardware::automotive::sv::V1_0::SvQuality;
+
+// Sv 2D output height and width set by the config file.
+const int kSv2dWidth = 768;
+const int kSv2dHeight = 1024;
+
+class SurroundView2dSessionTests : public ::testing::Test {
+protected:
+    void SetUp() override {
+        sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
+        mIoModule = new IOModule(kSvConfigFilename);
+        EXPECT_EQ(mIoModule->initialize(), IOStatus::OK);
+
+        mIoModule->getConfig(&mIoModuleConfig);
+
+        mSv2dSession = new SurroundView2dSession(fakeEvs, &mIoModuleConfig);
+        EXPECT_TRUE(mSv2dSession->initialize());
+    }
+
+    IOModule* mIoModule;
+    IOModuleConfig mIoModuleConfig;
+    sp<SurroundView2dSession> mSv2dSession;
+};
+
+TEST_F(SurroundView2dSessionTests, startAndStopSurroundView2dSession) {
+    sp<MockSurroundViewCallback> sv2dCallback =
+            new MockSurroundViewCallback(mSv2dSession);
+
+    EXPECT_EQ(mSv2dSession->startStream(sv2dCallback), SvResult::OK);
+
+    sleep(5);
+
+    mSv2dSession->stopStream();
+}
+
+TEST_F(SurroundView2dSessionTests, get2dMappingInfoSuccess) {
+    Sv2dMappingInfo sv2dMappingInfo;
+    mSv2dSession->get2dMappingInfo(
+        [&sv2dMappingInfo](const Sv2dMappingInfo& mappingInfo) {
+            sv2dMappingInfo = mappingInfo;
+        });
+
+    EXPECT_NE(sv2dMappingInfo.width, 0);
+    EXPECT_NE(sv2dMappingInfo.height, 0);
+    EXPECT_EQ(sv2dMappingInfo.center.x, 0.0f);
+    EXPECT_EQ(sv2dMappingInfo.center.y, 0.0f);
+}
+
+TEST_F(SurroundView2dSessionTests, get2dConfigSuccess) {
+    Sv2dConfig sv2dConfig;
+    mSv2dSession->get2dConfig(
+        [&sv2dConfig](const Sv2dConfig& config) {
+            sv2dConfig = config;
+        });
+
+    EXPECT_EQ(sv2dConfig.width, kSv2dWidth);
+    EXPECT_EQ(sv2dConfig.blending, SvQuality::HIGH);
+}
+
+// Sets a different config and checks of the received config matches.
+TEST_F(SurroundView2dSessionTests, setAndGet2dConfigSuccess) {
+    // Set config.
+    Sv2dConfig sv2dConfigSet = {kSv2dWidth / 2, SvQuality::LOW};
+    EXPECT_EQ(mSv2dSession->set2dConfig(sv2dConfigSet), SvResult::OK);
+
+    // Get config.
+    Sv2dConfig sv2dConfigReceived;
+    mSv2dSession->get2dConfig(
+        [&sv2dConfigReceived](const Sv2dConfig& config) {
+            sv2dConfigReceived = config;
+        });
+
+    EXPECT_EQ(sv2dConfigReceived.width, sv2dConfigSet.width);
+    EXPECT_EQ(sv2dConfigReceived.blending, sv2dConfigSet.blending);
+}
+
+// Projects center of each cameras and checks if valid projected point is received.
+TEST_F(SurroundView2dSessionTests, projectPoints2dSuccess) {
+    hidl_vec<Point2dInt> points2dCamera = {
+        /*Center point*/{.x = kSv2dWidth / 2, .y = kSv2dHeight /2}
+    };
+
+    std::vector<hidl_string> cameraIds = {"/dev/video60", "/dev/video61", "/dev/video62" ,
+            "/dev/video63"};
+
+    for (int i = 0; i < cameraIds.size(); i++) {
+        mSv2dSession->projectCameraPoints(points2dCamera, cameraIds[i],
+            [](const hidl_vec<Point2dFloat>& projectedPoints) {
+                EXPECT_TRUE(projectedPoints[0].isValid);
+            });
+    }
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/cpp/surround_view/service-impl/SurroundView3dSession.cpp b/cpp/surround_view/service-impl/SurroundView3dSession.cpp
index 3bb2203..c6f1ab1 100644
--- a/cpp/surround_view/service-impl/SurroundView3dSession.cpp
+++ b/cpp/surround_view/service-impl/SurroundView3dSession.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define ATRACE_TAG ATRACE_TAG_CAMERA
 
 #include "SurroundView3dSession.h"
 
@@ -22,6 +23,7 @@
 #include <hidlmemory/mapping.h>
 #include <system/camera_metadata.h>
 #include <utils/SystemClock.h>
+#include <utils/Trace.h>
 
 #include <array>
 #include <thread>
@@ -91,6 +93,8 @@
 
 Return<void> SurroundView3dSession::FramesHandler::deliverFrame_1_1(
     const hidl_vec<BufferDesc_1_1>& buffers) {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     LOG(INFO) << "Received " << buffers.size() << " frames from the camera";
     mSession->mSequenceId++;
 
@@ -159,6 +163,8 @@
     // Notify the session that a new set of frames is ready
     mSession->mFramesSignal.notify_all();
 
+    ATRACE_END();
+
     return {};
 }
 
@@ -196,9 +202,12 @@
 bool SurroundView3dSession::copyFromBufferToPointers(
     BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
 
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     AHardwareBuffer_Desc* pDesc =
         reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
 
+    ATRACE_BEGIN("Create Graphic Buffer");
     // create a GraphicBuffer from the existing handle
     sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
         buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
@@ -218,7 +227,9 @@
                   << " format: " << pDesc->format
                   << " stride: " << pDesc->stride;
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Lock input buffer (gpu to cpu)");
     // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
     // lock, return false.
     void* inputDataPtr;
@@ -232,22 +243,36 @@
     } else {
         LOG(INFO) << "Managed to get read access to GraphicBuffer";
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Copy input data");
     // Both source and destination are with 4 channels
     memcpy(pointers.cpu_data_pointer, inputDataPtr,
            pDesc->height * pDesc->width * kInputNumChannels);
     LOG(INFO) << "Buffer copying finished";
+    ATRACE_END();
+
+    ATRACE_BEGIN("Unlock input buffer (cpu to gpu)");
+    inputBuffer->unlock();
+    ATRACE_END();
+
+    // Paired with ATRACE_BEGIN in the beginning of the method.
+    ATRACE_END();
 
     return true;
 }
 
 void SurroundView3dSession::processFrames() {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
+    ATRACE_BEGIN("SV core lib method: Start3dPipeline");
     if (mSurroundView->Start3dPipeline()) {
         LOG(INFO) << "Start3dPipeline succeeded";
     } else {
         LOG(ERROR) << "Start3dPipeline failed";
         return;
     }
+    ATRACE_END();
 
     while (true) {
         {
@@ -279,6 +304,8 @@
         mStream = nullptr;
         LOG(DEBUG) << "Stream marked STOPPED.";
     }
+
+    ATRACE_END();
 }
 
 SurroundView3dSession::SurroundView3dSession(sp<IEvsEnumerator> pEvs,
@@ -289,9 +316,7 @@
       mStreamState(STOPPED),
       mVhalHandler(vhalHandler),
       mAnimationModule(animationModule),
-      mIOModuleConfig(pConfig) {
-    mEvsCameraIds = {"0" , "1", "2", "3"};
-}
+      mIOModuleConfig(pConfig) {}
 
 SurroundView3dSession::~SurroundView3dSession() {
     // In case the client did not call stopStream properly, we should stop the
@@ -602,6 +627,8 @@
 bool SurroundView3dSession::handleFrames(int sequenceId) {
     LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
 
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     // TODO(b/157498592): Now only one sets of EVS input frames and one SV
     // output frame is supported. Implement buffer queue for both of them.
     {
@@ -626,16 +653,16 @@
                    << mConfig.width
                    << ", new height: "
                    << mConfig.height;
-        delete[] static_cast<char*>(mOutputPointer.data_pointer);
+        delete[] static_cast<char*>(mOutputPointer.cpu_data_pointer);
         mOutputWidth = mConfig.width;
         mOutputHeight = mConfig.height;
         mOutputPointer.height = mOutputHeight;
         mOutputPointer.width = mOutputWidth;
         mOutputPointer.format = Format::RGBA;
-        mOutputPointer.data_pointer =
-            new char[mOutputHeight * mOutputWidth * kOutputNumChannels];
+        mOutputPointer.cpu_data_pointer =
+                static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
 
-        if (!mOutputPointer.data_pointer) {
+        if (!mOutputPointer.cpu_data_pointer) {
             LOG(ERROR) << "Memory allocation failed. Exiting.";
             return false;
         }
@@ -657,6 +684,7 @@
         }
     }
 
+    ATRACE_BEGIN("SV core lib method: Set3dOverlay");
     // Set 3d overlays.
     {
         scoped_lock<mutex> lock(mAccessLock);
@@ -667,7 +695,9 @@
             mOverlayIsUpdated = false;
         }
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("VhalHandler method: getPropertyValues");
     // Get the latest VHal property values
     if (mVhalHandler != nullptr) {
         if (!mVhalHandler->getPropertyValues(&mPropertyValues)) {
@@ -676,19 +706,24 @@
     } else {
         LOG(WARNING) << "VhalHandler is null. Ignored";
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("AnimationModule method: getUpdatedAnimationParams");
     vector<AnimationParam> params;
     if (mAnimationModule != nullptr) {
         params = mAnimationModule->getUpdatedAnimationParams(mPropertyValues);
     } else {
         LOG(WARNING) << "AnimationModule is null. Ignored";
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("SV core lib method: SetAnimations");
     if (!params.empty()) {
         mSurroundView->SetAnimations(params);
     } else {
         LOG(INFO) << "AnimationParams is empty. Ignored";
     }
+    ATRACE_END();
 
     // Get the view.
     // TODO(161399517): Only single view is currently supported, add support for multiple views.
@@ -698,31 +733,37 @@
     const std::array<float, 4> viewQuaternion = {quat.x, quat.y, quat.z, quat.w};
     const std::array<float, 3> viewTranslation = {trans.x, trans.y, trans.z};
 
+    ATRACE_BEGIN("SV core lib method: Get3dSurroundView");
     if (mSurroundView->Get3dSurroundView(
             mInputPointers, viewQuaternion, viewTranslation, &mOutputPointer)) {
         LOG(INFO) << "Get3dSurroundView succeeded";
     } else {
         LOG(ERROR) << "Get3dSurroundView failed. "
                    << "Using memset to initialize to gray.";
-        memset(mOutputPointer.data_pointer, kGrayColor,
+        memset(mOutputPointer.cpu_data_pointer, kGrayColor,
                mOutputHeight * mOutputWidth * kOutputNumChannels);
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Lock output texture (gpu to cpu)");
     void* textureDataPtr = nullptr;
     mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
                     | GRALLOC_USAGE_SW_READ_NEVER,
                     &textureDataPtr);
+    ATRACE_END();
+
     if (!textureDataPtr) {
         LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
         return false;
     }
 
+    ATRACE_BEGIN("Copy output result");
     // Note: there is a chance that the stride of the texture is not the
     // same as the width. For example, when the input frame is 1920 * 1080,
     // the width is 1080, but the stride is 2048. So we'd better copy the
     // data line by line, instead of single memcpy.
     uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
-    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
+    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.cpu_data_pointer);
     const int readStride = mOutputWidth * kOutputNumChannels;
     const int writeStride = mSvTexture->getStride() * kOutputNumChannels;
     if (readStride == writeStride) {
@@ -735,7 +776,11 @@
         }
     }
     LOG(INFO) << "memcpy finished!";
+    ATRACE_END();
+
+    ATRACE_BEGIN("Unlock output texture (cpu to gpu)");
     mSvTexture->unlock();
+    ATRACE_END();
 
     ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
     LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
@@ -763,12 +808,16 @@
         mStream->receiveFrames(mFramesRecord.frames);
     }
 
+    ATRACE_END();
+
     return true;
 }
 
 bool SurroundView3dSession::initialize() {
     lock_guard<mutex> lock(mAccessLock, adopt_lock);
 
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     if (!setupEvs()) {
         LOG(ERROR) << "Failed to setup EVS components for 3d session";
         return false;
@@ -790,17 +839,19 @@
                     mIOModuleConfig->sv2dConfig.carBoundingBox,
                     mIOModuleConfig->carModelConfig.carModel.texturesMap,
                     mIOModuleConfig->carModelConfig.carModel.partsMap);
+    ATRACE_BEGIN("SV core lib method: SetStaticData");
     mSurroundView->SetStaticData(params);
+    ATRACE_END();
 
+    ATRACE_BEGIN("Allocate cpu buffers");
     mInputPointers.resize(kNumFrames);
     for (int i = 0; i < kNumFrames; i++) {
         mInputPointers[i].width = mCameraParams[i].size.width;
         mInputPointers[i].height = mCameraParams[i].size.height;
         mInputPointers[i].format = Format::RGBA;
         mInputPointers[i].cpu_data_pointer =
-                (void*)new uint8_t[mInputPointers[i].width *
-                                   mInputPointers[i].height *
-                                   kInputNumChannels];
+                static_cast<void*>(new uint8_t[mInputPointers[i].width * mInputPointers[i].height *
+                                               kInputNumChannels]);
     }
     LOG(INFO) << "Allocated " << kNumFrames << " input pointers";
 
@@ -814,14 +865,16 @@
     mOutputPointer.height = mOutputHeight;
     mOutputPointer.width = mOutputWidth;
     mOutputPointer.format = Format::RGBA;
-    mOutputPointer.data_pointer = new char[
-        mOutputHeight * mOutputWidth * kOutputNumChannels];
+    mOutputPointer.cpu_data_pointer =
+            static_cast<void*>(new char[mOutputHeight * mOutputWidth * kOutputNumChannels]);
 
-    if (!mOutputPointer.data_pointer) {
+    if (!mOutputPointer.cpu_data_pointer) {
         LOG(ERROR) << "Memory allocation failed. Exiting.";
         return false;
     }
+    ATRACE_END();
 
+    ATRACE_BEGIN("Allocate output texture");
     mSvTexture = new GraphicBuffer(mOutputWidth,
                                    mOutputHeight,
                                    HAL_PIXEL_FORMAT_RGBA_8888,
@@ -835,13 +888,18 @@
         LOG(ERROR) << "Failed to allocate Graphic Buffer";
         return false;
     }
-
+    ATRACE_END();
 
     mIsInitialized = true;
+
+    ATRACE_END();
+
     return true;
 }
 
 bool SurroundView3dSession::setupEvs() {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     // Reads the camera related information from the config object
     const string evsGroupId = mIOModuleConfig->cameraConfig.evsGroupId;
 
@@ -911,11 +969,17 @@
         LOG(ERROR) << "Failed to allocate EVS Camera interface for " << camId;
         return false;
     } else {
-        LOG(INFO) << "Camera " << camId << " is opened successfully";
+        LOG(INFO) << "Logical camera " << camId << " is opened successfully";
+    }
+
+    mEvsCameraIds = mIOModuleConfig->cameraConfig.evsCameraIds;
+    if (mEvsCameraIds.size() < kNumFrames) {
+        LOG(ERROR) << "Incorrect camera info is stored in the camera config";
+        return false;
     }
 
     map<string, AndroidCameraParams> cameraIdToAndroidParameters;
-    for (const auto& id : mIOModuleConfig->cameraConfig.evsCameraIds) {
+    for (const auto& id : mEvsCameraIds) {
         AndroidCameraParams params;
         if (getAndroidCameraParams(mCamera, id, params)) {
             cameraIdToAndroidParameters.emplace(id, params);
@@ -937,10 +1001,17 @@
         camera.circular_fov = 179;
     }
 
+    // Add validity mask filenames.
+    for (int i = 0; i < mCameraParams.size(); i++) {
+        mCameraParams[i].validity_mask_filename = mIOModuleConfig->cameraConfig.maskFilenames[i];
+    }
+    ATRACE_END();
     return true;
 }
 
 bool SurroundView3dSession::startEvs() {
+    ATRACE_BEGIN(__PRETTY_FUNCTION__);
+
     mFramesHandler = new FramesHandler(mCamera, this);
     Return<EvsResult> result = mCamera->startVideoStream(mFramesHandler);
     if (result != EvsResult::OK) {
@@ -950,6 +1021,8 @@
         LOG(INFO) << "Video stream was started successfully";
     }
 
+    ATRACE_END();
+
     return true;
 }
 
diff --git a/cpp/surround_view/service-impl/SurroundView3dSessionTests.cpp b/cpp/surround_view/service-impl/SurroundView3dSessionTests.cpp
new file mode 100644
index 0000000..afe8f07
--- /dev/null
+++ b/cpp/surround_view/service-impl/SurroundView3dSessionTests.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurroundView3dSessionTests"
+
+#include "AnimationModule.h"
+#include "IOModule.h"
+#include "SurroundView3dSession.h"
+#include "VhalHandler.h"
+#include "mock-evs/MockEvsEnumerator.h"
+#include "mock-evs/MockSurroundViewCallback.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <gtest/gtest.h>
+#include <hidlmemory/mapping.h>
+
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+using ::android::sp;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::automotive::sv::V1_0::OverlayMemoryDesc;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
+
+// Sv 3D output height and width set by the config file.
+const int kSv3dWidth = 1920;
+const int kSv3dHeight = 1080;
+
+// Constants for overlays.
+const int kVertexByteSize = (3 * sizeof(float)) + 4;
+const int kIdByteSize = 2;
+
+class SurroundView3dSessionTests : public ::testing::Test {
+protected:
+    // Setup sv3d session without vhal and animations.
+    void SetupSv3dSession() {
+        mFakeEvs = new MockEvsEnumerator();
+        mIoModule = new IOModule(kSvConfigFilename);
+        EXPECT_EQ(mIoModule->initialize(), IOStatus::OK);
+
+        mIoModule->getConfig(&mIoModuleConfig);
+
+        mSv3dSession = new SurroundView3dSession(mFakeEvs, nullptr,
+                                                 nullptr,
+                                                 &mIoModuleConfig);
+
+        EXPECT_TRUE(mSv3dSession->initialize());
+        mSv3dCallback = new MockSurroundViewCallback(mSv3dSession);
+        vector<View3d> views = {
+        {
+            .viewId = 0,
+            .pose = {
+                .rotation = {.x = 0, .y = 0, .z = 0, .w = 1.0f},
+                .translation = {.x = 0, .y = 0, .z = 0},
+            },
+            .horizontalFov = 90,
+        }};
+        mSv3dSession->setViews(views);
+    }
+
+    // Setup sv3d session with vhal and animations.
+    void SetupSv3dSessionVhalAnimation() {
+        mFakeEvs = new MockEvsEnumerator();
+        mIoModule = new IOModule(kSvConfigFilename);
+        EXPECT_EQ(mIoModule->initialize(), IOStatus::OK);
+
+        mIoModule->getConfig(&mIoModuleConfig);
+
+        mVhalHandler = new VhalHandler();
+        ASSERT_TRUE(mVhalHandler->initialize(VhalHandler::UpdateMethod::GET, 10));
+
+        mAnimationModule = new AnimationModule(mIoModuleConfig.carModelConfig.carModel.partsMap,
+                                    mIoModuleConfig.carModelConfig.carModel.texturesMap,
+                                    mIoModuleConfig.carModelConfig.animationConfig.animations);
+
+        const std::vector<uint64_t> animationPropertiesToRead =
+                getAnimationPropertiesToRead(mIoModuleConfig.carModelConfig.animationConfig);
+        ASSERT_TRUE(mVhalHandler->setPropertiesToRead(animationPropertiesToRead));
+
+        mSv3dSessionAnimations = new SurroundView3dSession(mFakeEvs, mVhalHandler,
+                                                 mAnimationModule,
+                                                 &mIoModuleConfig);
+
+        EXPECT_TRUE(mSv3dSessionAnimations->initialize());
+
+        mSv3dCallbackAnimations = new MockSurroundViewCallback(mSv3dSessionAnimations);
+        vector<View3d> views = {
+        // View 0
+        {
+            .viewId = 0,
+            .pose = {
+                .rotation = {.x = 0, .y = 0, .z = 0, .w = 1.0f},
+                .translation = {.x = 0, .y = 0, .z = 0},
+            },
+            .horizontalFov = 90,
+        }};
+
+        mSv3dSessionAnimations->setViews(views);
+    }
+
+    // Helper function to get list of vhal properties to read from car config file for animations.
+    std::vector<uint64_t> getAnimationPropertiesToRead(const AnimationConfig& animationConfig) {
+        std::set<uint64_t> propertiesSet;
+        for (const auto& animation : animationConfig.animations) {
+            for (const auto& opPair : animation.gammaOpsMap) {
+                propertiesSet.insert(opPair.first);
+            }
+
+            for (const auto& opPair : animation.textureOpsMap) {
+                propertiesSet.insert(opPair.first);
+            }
+
+            for (const auto& opPair : animation.rotationOpsMap) {
+                propertiesSet.insert(opPair.first);
+            }
+
+            for (const auto& opPair : animation.translationOpsMap) {
+                propertiesSet.insert(opPair.first);
+            }
+        }
+        std::vector<uint64_t> propertiesToRead;
+        propertiesToRead.assign(propertiesSet.begin(), propertiesSet.end());
+        return propertiesToRead;
+    }
+
+    void TearDown() override {
+        mSv3dSession = nullptr;
+        mFakeEvs = nullptr;
+        mSv3dCallback = nullptr;
+        delete mVhalHandler;
+        delete mAnimationModule;
+        delete mIoModule;
+    }
+
+    sp<IEvsEnumerator> mFakeEvs;
+    IOModule* mIoModule;
+    IOModuleConfig mIoModuleConfig;
+    sp<SurroundView3dSession> mSv3dSession;
+    sp<MockSurroundViewCallback> mSv3dCallback;
+
+    VhalHandler* mVhalHandler;
+    AnimationModule* mAnimationModule;
+    sp<SurroundView3dSession> mSv3dSessionAnimations;
+    sp<MockSurroundViewCallback> mSv3dCallbackAnimations;
+};
+
+TEST_F(SurroundView3dSessionTests, startAndStop3dSession) {
+    SetupSv3dSession();
+    EXPECT_EQ(mSv3dSession->startStream(mSv3dCallback), SvResult::OK);
+    sleep(5);
+    mSv3dSession->stopStream();
+    EXPECT_GT(mSv3dCallback->getReceivedFramesCount(), 0);
+}
+
+TEST_F(SurroundView3dSessionTests, get3dConfigSuccess) {
+    SetupSv3dSession();
+    Sv3dConfig sv3dConfig;
+    mSv3dSession->get3dConfig([&sv3dConfig](const Sv3dConfig& config) { sv3dConfig = config; });
+
+    EXPECT_EQ(sv3dConfig.width, kSv3dWidth);
+    EXPECT_EQ(sv3dConfig.height, kSv3dHeight);
+    EXPECT_EQ(sv3dConfig.carDetails, SvQuality::HIGH);
+}
+
+// Sets a different config and checks of the received config matches.
+TEST_F(SurroundView3dSessionTests, setAndGet3dConfigSuccess) {
+    SetupSv3dSession();
+    Sv3dConfig sv3dConfigSet = {kSv3dWidth / 2, kSv3dHeight / 2, SvQuality::LOW};
+
+    EXPECT_EQ(mSv3dSession->set3dConfig(sv3dConfigSet), SvResult::OK);
+
+    Sv3dConfig sv3dConfigReceived;
+    mSv3dSession->get3dConfig(
+            [&sv3dConfigReceived](const Sv3dConfig& config) { sv3dConfigReceived = config; });
+
+    EXPECT_EQ(sv3dConfigReceived.width, sv3dConfigSet.width);
+    EXPECT_EQ(sv3dConfigReceived.height, sv3dConfigSet.height);
+    EXPECT_EQ(sv3dConfigReceived.carDetails, sv3dConfigSet.carDetails);
+}
+
+// Projects center of each cameras and checks if valid projected point is received.
+TEST_F(SurroundView3dSessionTests, projectPoints3dSuccess) {
+    SetupSv3dSession();
+    hidl_vec<Point2dInt> points2dCamera = {
+            /*Center point*/ {.x = kSv3dWidth / 2, .y = kSv3dHeight / 2}};
+
+    std::vector<hidl_string> cameraIds = {"/dev/video60", "/dev/video61", "/dev/video62",
+                                          "/dev/video63"};
+
+    for (int i = 0; i < cameraIds.size(); i++) {
+        mSv3dSession
+                ->projectCameraPointsTo3dSurface(points2dCamera, cameraIds[i],
+                                                 [](const hidl_vec<Point3dFloat>& projectedPoints) {
+                                                     EXPECT_TRUE(projectedPoints[0].isValid);
+                                                 });
+    }
+}
+
+std::pair<hidl_memory, sp<IMemory>> GetMappedSharedMemory(int bytesSize) {
+    const auto nullResult = std::make_pair(hidl_memory(), nullptr);
+
+    sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+    if (ashmemAllocator.get() == nullptr) {
+        return nullResult;
+    }
+
+    // Allocate shared memory.
+    hidl_memory hidlMemory;
+    bool allocateSuccess = false;
+    Return<void> result =
+            ashmemAllocator->allocate(bytesSize, [&](bool success, const hidl_memory& hidlMem) {
+                if (!success) {
+                    return;
+                }
+                allocateSuccess = success;
+                hidlMemory = hidlMem;
+            });
+
+    // Check result of allocated memory.
+    if (!result.isOk() || !allocateSuccess) {
+        return nullResult;
+    }
+
+    // Map shared memory.
+    sp<IMemory> pIMemory = mapMemory(hidlMemory);
+    if (pIMemory.get() == nullptr) {
+        return nullResult;
+    }
+
+    return std::make_pair(hidlMemory, pIMemory);
+}
+
+void SetIndexOfOverlaysMemory(const std::vector<OverlayMemoryDesc>& overlaysMemDesc,
+                              sp<IMemory> pIMemory, int indexPosition, uint16_t indexValue) {
+    // Count the number of vertices until the index.
+    int totalVerticesCount = 0;
+    for (int i = 0; i < indexPosition; i++) {
+        totalVerticesCount += overlaysMemDesc[i].verticesCount;
+    }
+
+    const int indexBytePosition =
+            (indexPosition * kIdByteSize) + (kVertexByteSize * totalVerticesCount);
+
+    uint8_t* pSharedMemoryData = reinterpret_cast<uint8_t*>((void*)pIMemory->getPointer());
+    pSharedMemoryData += indexBytePosition;
+    uint16_t* pIndex16bit = reinterpret_cast<uint16_t*>(pSharedMemoryData);
+
+    // Modify shared memory.
+    pIMemory->update();
+    *pIndex16bit = indexValue;
+    pIMemory->commit();
+}
+
+std::pair<OverlaysData, sp<IMemory>> GetSampleOverlaysData() {
+    OverlaysData overlaysData;
+    overlaysData.overlaysMemoryDesc.resize(2);
+
+    int sharedMemBytesSize = 0;
+    OverlayMemoryDesc overlayMemDesc1, overlayMemDesc2;
+    overlayMemDesc1.id = 0;
+    overlayMemDesc1.verticesCount = 6;
+    overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+    overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+    sharedMemBytesSize += kIdByteSize + kVertexByteSize * overlayMemDesc1.verticesCount;
+
+    overlayMemDesc2.id = 1;
+    overlayMemDesc2.verticesCount = 4;
+    overlayMemDesc2.overlayPrimitive = OverlayPrimitive::TRIANGLES_STRIP;
+    overlaysData.overlaysMemoryDesc[1] = overlayMemDesc2;
+    sharedMemBytesSize += kIdByteSize + kVertexByteSize * overlayMemDesc2.verticesCount;
+
+    std::pair<hidl_memory, sp<IMemory>> sharedMem = GetMappedSharedMemory(sharedMemBytesSize);
+    sp<IMemory> pIMemory = sharedMem.second;
+    if (pIMemory.get() == nullptr) {
+        return std::make_pair(OverlaysData(), nullptr);
+    }
+
+    // Get pointer to shared memory data and set all bytes to 0.
+    uint8_t* pSharedMemoryData = reinterpret_cast<uint8_t*>((void*)pIMemory->getPointer());
+    pIMemory->update();
+    memset(pSharedMemoryData, 0, sharedMemBytesSize);
+    pIMemory->commit();
+
+    std::vector<OverlayMemoryDesc> overlaysDesc = {overlayMemDesc1, overlayMemDesc2};
+
+    // Set indexes in shared memory.
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlayMemDesc2.id);
+
+    overlaysData.overlaysMemoryDesc = overlaysDesc;
+    overlaysData.overlaysMemory = sharedMem.first;
+
+    return std::make_pair(overlaysData, pIMemory);
+}
+
+// Verifies a valid overlay can be updated while streaming.
+TEST_F(SurroundView3dSessionTests, updateOverlaysSuccess) {
+    SetupSv3dSession();
+    std::pair<OverlaysData, sp<IMemory>> overlaysData = GetSampleOverlaysData();
+    ASSERT_NE(overlaysData.second, nullptr);
+    EXPECT_EQ(mSv3dSession->startStream(mSv3dCallback), SvResult::OK);
+    SvResult result = mSv3dSession->updateOverlays(overlaysData.first);
+    mSv3dSession->stopStream();
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+// Setup sv 3d sessin with vhal and animations and verify frames are received successfully.
+TEST_F(SurroundView3dSessionTests, vhalAnimationSuccess) {
+    SetupSv3dSessionVhalAnimation();
+    EXPECT_EQ(mSv3dSessionAnimations->startStream(mSv3dCallbackAnimations), SvResult::OK);
+    sleep(5);
+    mSv3dSessionAnimations->stopStream();
+    EXPECT_GT(mSv3dCallbackAnimations->getReceivedFramesCount(), 0);
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/cpp/surround_view/service-impl/core_lib.h b/cpp/surround_view/service-impl/core_lib.h
index 7a9e67d..fd8f1ec 100644
--- a/cpp/surround_view/service-impl/core_lib.h
+++ b/cpp/surround_view/service-impl/core_lib.h
@@ -200,20 +200,26 @@
     // Blending type for low quality preset.
     BlendingType low_quality_blending;
 
+    // whether gpu acceleration is enabled or not
+    bool gpu_acceleration_enabled;
+
     SurroundView2dParams() :
           resolution{0, 0},
           physical_size{0.0f, 0.0f},
           physical_center{0.0f, 0.0f},
           high_quality_blending(BlendingType::MULTIBAND),
-          low_quality_blending(BlendingType::ALPHA) {}
+          low_quality_blending(BlendingType::ALPHA),
+          gpu_acceleration_enabled(false) {}
 
     SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
-                         Coordinate2dFloat physical_center_) :
+                         Coordinate2dFloat physical_center_,
+                         bool gpu_acceleration_enabled_ = false) :
           resolution(resolution_),
           physical_size(physical_size_),
           physical_center(physical_center_),
           high_quality_blending(BlendingType::MULTIBAND),
-          low_quality_blending(BlendingType::ALPHA) {}
+          low_quality_blending(BlendingType::ALPHA),
+          gpu_acceleration_enabled(gpu_acceleration_enabled_) {}
 
     // Checks if data is valid.
     bool IsValid() const { return resolution.IsValid() && physical_size.IsValid(); }
@@ -222,7 +228,8 @@
         return resolution == rhs.resolution && physical_size == rhs.physical_size &&
                 physical_center == rhs.physical_center &&
                 high_quality_blending == rhs.high_quality_blending &&
-                low_quality_blending == rhs.low_quality_blending;
+                low_quality_blending == rhs.low_quality_blending &&
+                gpu_acceleration_enabled == rhs.gpu_acceleration_enabled;
     }
 
     SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
@@ -231,6 +238,7 @@
         physical_center = rhs.physical_center;
         high_quality_blending = rhs.high_quality_blending;
         low_quality_blending = rhs.low_quality_blending;
+        gpu_acceleration_enabled = rhs.gpu_acceleration_enabled;
         return *this;
     }
 };
@@ -354,6 +362,10 @@
     // fisheye circular fov.
     float circular_fov;
 
+    // Full path and filename to the validity mask image file.
+    // Mask specifies the valid region of pixels within input camera image.
+    std::string validity_mask_filename;
+
     bool operator==(const SurroundViewCameraParams& rhs) const {
         return (0 == std::memcmp(intrinsics, rhs.intrinsics, 9 * sizeof(float))) &&
                 (0 == std::memcmp(distorion, rhs.distorion, 4 * sizeof(float))) &&
@@ -675,42 +687,57 @@
           height(height_) {}
 };
 
+// Currently we keep both cpu and gpu data pointers, and only one of them should
+// be valid at a certain point. Users need to check null before they make use of
+// the data pointers.
+// TODO(b/174778117): consider use only one data pointer once GPU migration is
+// done. If we are going to keep both cpu and gpu data pointer, specify the type
+// of data for cpu data pointer, instead of using a void pointer.
 struct SurroundViewResultPointer {
-    void* data_pointer;
+    void* gpu_data_pointer;
+    void* cpu_data_pointer;
     Format format;
     int width;
     int height;
     bool is_data_preallocated;
     SurroundViewResultPointer() :
-          data_pointer(nullptr), width(0), height(0), is_data_preallocated(false) {}
+          gpu_data_pointer(nullptr),
+          cpu_data_pointer(nullptr),
+          width(0),
+          height(0),
+          is_data_preallocated(false) {}
 
     // Constructor with result data pointer being allocated within core lib.
     // Use for cases when no already existing buffer is available.
     SurroundViewResultPointer(Format format_, int width_, int height_) :
-          format(format_), width(width_), height(height_) {
+          gpu_data_pointer(nullptr),
+          format(format_),
+          width(width_),
+          height(height_),
+          is_data_preallocated(false) {
         // default formate is gray.
         const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
-        data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
-        is_data_preallocated = false;
+        cpu_data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
     }
 
     // Constructor with pre-allocated data.
     // Use for cases when results must be added to an existing allocated buffer.
     // Example, pre-allocated buffer of a display.
-    SurroundViewResultPointer(void* data_pointer_, Format format_, int width_, int height_) :
-          data_pointer(data_pointer_),
+    SurroundViewResultPointer(void* gpu_data_pointer_, void* cpu_data_pointer_, Format format_,
+                              int width_, int height_) :
+          gpu_data_pointer(gpu_data_pointer_),
+          cpu_data_pointer(cpu_data_pointer_),
           format(format_),
           width(width_),
           height(height_),
           is_data_preallocated(true) {}
 
     ~SurroundViewResultPointer() {
-        if (data_pointer) {
-            // TODO(b/154365307): Fix freeing up of pre-allocated memory.
-            // if (!is_data_preallocated) {
-            //   delete[] static_cast<char*>(data_pointer);
-            // }
-            data_pointer = nullptr;
+        if (cpu_data_pointer) {
+            if (!is_data_preallocated) {
+                delete[] static_cast<char*>(cpu_data_pointer);
+            }
+            cpu_data_pointer = nullptr;
         }
     }
 };
diff --git a/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
index f0ad2e6..76456ea 100755
--- a/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
+++ b/cpp/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp b/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
index dcd7405..14be890 100644
--- a/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
+++ b/cpp/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
@@ -31,6 +31,12 @@
 const char kConfigFilePath[] =
         "/vendor/etc/automotive/evs/evs_sample_configuration.xml";
 
+// Evs Camera Id names defined in sv_sample_config.xml.
+const char kEvsCameraDeviceIdNames[4][20] = {
+    "/dev/video60", "/dev/video61", "/dev/video62", "/dev/video63"
+};
+
+
 MockEvsCamera::MockEvsCamera(const string& cameraId, const Stream& streamCfg) {
     mConfigManager = ConfigManager::Create(kConfigFilePath);
 
@@ -255,6 +261,7 @@
                                                label + (char)(i + 48));
         mBufferDescs[i].buffer.nativeHandle =
                 mGraphicBuffers[i]->getNativeBuffer()->handle;
+        mBufferDescs[i].deviceId = kEvsCameraDeviceIdNames[i];
         AHardwareBuffer_Desc* pDesc =
                 reinterpret_cast<AHardwareBuffer_Desc*>(
                         &mBufferDescs[i].buffer.description);
diff --git a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp b/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
index 03f9594..60108e6 100644
--- a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
+++ b/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
@@ -46,6 +46,12 @@
     LOG(INFO) << __FUNCTION__ << svFramesDesc.svBuffers.size()
               << " frames are received";
 
+    // Increment the count of received frames.
+    {
+        std::scoped_lock<std::mutex> lock(mAccessLock);
+        mReceivedFramesCount++;
+    }
+
     // Create a separate thread to return the frames to the session. This
     // simulates the behavior of oneway HIDL method call.
     thread mockHidlThread([this, &svFramesDesc]() {
@@ -55,6 +61,20 @@
     return {};
 }
 
+int MockSurroundViewCallback::getReceivedFramesCount() {
+    {
+        std::scoped_lock<std::mutex> lock(mAccessLock);
+        return mReceivedFramesCount;
+    }
+}
+
+void MockSurroundViewCallback::clearReceivedFramesCount() {
+    {
+        std::scoped_lock<std::mutex> lock(mAccessLock);
+        mReceivedFramesCount = 0;
+    }
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace sv
diff --git a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h b/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
index eeabc98..238e41a 100644
--- a/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
+++ b/cpp/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
@@ -19,6 +19,11 @@
 #include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
 #include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
 
+#include <ui/GraphicBuffer.h>
+
+#include <mutex>
+#include <thread>
+
 using namespace android::hardware::automotive::sv::V1_0;
 
 namespace android {
@@ -36,8 +41,15 @@
     android::hardware::Return<void> notify(SvEvent svEvent) override;
     android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
 
+    // Methods to get and clear the mReceivedFramesCount.
+    int getReceivedFramesCount();
+    void clearReceivedFramesCount();
 private:
+    std::mutex mAccessLock;
     android::sp<ISurroundViewSession> mSession;
+
+    // Keeps a count of the number of calls made to receiveFrames().
+    int mReceivedFramesCount GUARDED_BY(mAccessLock) = 0;
 };
 
 }  // namespace implementation
diff --git a/cpp/surround_view/service-impl/service.cpp b/cpp/surround_view/service-impl/service.cpp
index 3ccc68f..b7d82f7 100644
--- a/cpp/surround_view/service-impl/service.cpp
+++ b/cpp/surround_view/service-impl/service.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
 #include <android-base/logging.h>
 #include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
 #include <android/hardware_buffer.h>
@@ -23,6 +25,7 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 #include <utils/SystemClock.h>
+#include <utils/Trace.h>
 
 #include "SurroundViewService.h"
 
@@ -39,6 +42,8 @@
 
     configureRpcThreadpool(1, true /* callerWillJoin */);
 
+    ATRACE_BEGIN("SurroundViewServiceImpl: registerAsService");
+
     // Register our service -- if somebody is already registered by our name,
     // they will be killed (their thread pool will throw an exception).
     android::status_t status = service->registerAsService();
@@ -48,6 +53,8 @@
                    << status;
     }
 
+    ATRACE_END();
+
     joinRpcThreadpool();
 
     // In normal operation, we don't expect the thread pool to exit
diff --git a/cpp/surround_view/service-impl/test_data/sv_sample_config.xml b/cpp/surround_view/service-impl/test_data/sv_sample_config.xml
index 88a5413..9a4b124 100644
--- a/cpp/surround_view/service-impl/test_data/sv_sample_config.xml
+++ b/cpp/surround_view/service-impl/test_data/sv_sample_config.xml
@@ -11,22 +11,22 @@
             <Left>/dev/video63</Left>
         </EvsCameraIds>
         <Masks>
-            <Front>/vendor/mask_front.png</Front>
-            <Right>/vendor/mask_right.png</Right>
-            <Rear>/vendor/mask_rear.png</Rear>
-            <Left>/vendor/mask_left.png</Left>
+            <Front>/vendor/etc/automotive/sv/mask_front.png</Front>
+            <Right>/vendor/etc/automotive/sv/mask_right.png</Right>
+            <Rear>/vendor/etc/automotive/sv/mask_rear.png</Rear>
+            <Left>/vendor/etc/automotive/sv/mask_left.png</Left>
         </Masks>
     </CameraConfig>
 
     <Sv2dEnabled>true</Sv2dEnabled>
     <Sv2dParams>
         <OutputResolution>
-            <Width>1024</Width>
-            <Height>768</Height>
+            <Width>768</Width>
+            <Height>1024</Height>
         </OutputResolution>
         <GroundMapping>
-            <Width>8.0</Width>
-            <Height>6.0</Height>
+            <Width>9.0</Width>
+            <Height>12.0</Height>
             <Center>
                 <X>0.0</X>
                 <Y>0.0</Y>
@@ -44,6 +44,7 @@
             <HighQuality>multiband</HighQuality>
             <LowQuality>alpha</LowQuality>
         </BlendingType>
+        <GpuAccelerationEnabled>false</GpuAccelerationEnabled>
     </Sv2dParams>
 
     <Sv3dEnabled>true</Sv3dEnabled>
@@ -52,8 +53,8 @@
     <CarModelObjFile>/vendor/etc/automotive/sv/sample_car.obj</CarModelObjFile>
     <Sv3dParams>
         <OutputResolution>
-            <Width>1024</Width>
-            <Height>768</Height>
+            <Width>1920</Width>
+            <Height>1080</Height>
         </OutputResolution>
         <BowlParams>
             <PlaneRadius>8.0</PlaneRadius>