diff --git a/CMake/External/External_VTK.cmake b/CMake/External/External_VTK.cmake
index c9a55f7313cb6cf38f7d3ad8a1e96ce77450e552..fa76b5db9616056532385ee8dc9aa10cf16f598c 100644
--- a/CMake/External/External_VTK.cmake
+++ b/CMake/External/External_VTK.cmake
@@ -21,7 +21,8 @@ endif()
 
 set(VTK_MODULE_SETTINGS
   -DVTK_MODULE_ENABLE_VTK_ChartsCore:STRING=YES
-  -DVTK_MODULE_ENABLE_VTK_RenderingOpenGL2:STRING=YES
+  -DVTK_MODULE_ENABLE_MODULE_FiltersExtraction:STRING=YES
+  -DVTK_MODULE_ENABLE_MODULE_FiltersModeling:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_IOExport:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_IOImport:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_IOParallel:STRING=YES
@@ -36,15 +37,14 @@ set(VTK_MODULE_SETTINGS
   -DVTK_MODULE_ENABLE_VTK_InteractionWidgets:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_glew:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_RenderingContext2D:STRING=YES
+  -DVTK_MODULE_ENABLE_VTK_RenderingContextOpenGL2:STRING=YES
+  -DVTK_MODULE_ENABLE_VTK_RenderingOpenGL2:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_RenderingVolumeOpenGL2:STRING=YES
   -DVTK_MODULE_ENABLE_VTK_ViewsContext2D:STRING=YES
   -DVTK_BUILD_EXAMPLES:STRING=DONT_WANT
   -DVTK_BUILD_TESTING:STRING=OFF
   -DVTK_GROUP_ENABLE_StandAlone:STRING=DONT_WANT
-  -DVTK_GROUP_ENABLE_Rendering:STRING=DONT_WANT
--DVTK_MODULE_ENABLE_MODULE_FiltersModeling:STRING=YES
--DVTK_MODULE_ENABLE_MODULE_FiltersExtraction:STRING=YES
-    )
+  -DVTK_GROUP_ENABLE_Rendering:STRING=DONT_WANT)
 set(${PROJECT_NAME}_VTK_SOURCE GIT_REPOSITORY https://gitlab.kitware.com/vtk/vtk.git)
 
 if(${PROJECT_NAME}_VTK_REPO_SOURCE EQUAL "9.0")
diff --git a/CMake/iMSTKConfig.cmake.in b/CMake/iMSTKConfig.cmake.in
index d786876fc47d125cd2ada5f0e18a6b15cd5f305d..691c06bdcdcc4aa9a34ae9104b1936e8acd2325c 100644
--- a/CMake/iMSTKConfig.cmake.in
+++ b/CMake/iMSTKConfig.cmake.in
@@ -101,10 +101,13 @@ else()
   # modules are linked via `VTK::CommonCore`
   # vtk_module_autoinit is needed
   find_dependency(VTK COMPONENTS
+    ChartsCore
     CommonCore
     CommonDataModel
     FiltersGeneral
     FiltersSources
+    FiltersModeling
+    FiltersExtraction
     IOExport
     IOImport
     IOPLY
@@ -113,10 +116,13 @@ else()
     ImagingCore
     InteractionStyle
     RenderingAnnotation
+    RenderingContext2D
+    RenderingContextOpenGL2
     RenderingCore
     RenderingOpenGL2
     RenderingVolume
-    RenderingVolumeOpenGL2)
+    RenderingVolumeOpenGL2
+    ViewsContext2D)
 endif()
 
 # glfw, gli
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c1f28d9cf750c655f7e9068e9d423071bfabc46c..52488774396ba1a2c680f3610a02260753ccbb03 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -282,8 +282,8 @@ find_package(VTK COMPONENTS
   CommonDataModel
   FiltersGeneral
   FiltersSources
-FiltersModeling
-FiltersExtraction
+  FiltersModeling
+  FiltersExtraction
   IOExport
   IOImport
   IOPLY
@@ -292,12 +292,13 @@ FiltersExtraction
   ImagingCore
   InteractionStyle
   RenderingAnnotation
+  RenderingContext2D
+  RenderingContextOpenGL2
   RenderingCore
   RenderingOpenGL2
   RenderingVolume
   RenderingVolumeOpenGL2
-  ViewsContext2D
-)
+  ViewsContext2D)
 
 # Vulkan
 set(Vulkan_Dependency)
diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt
index fffe47d6cd413c2d3dc0eb2b71d8193e8b5ca9d3..e94b6841418ed96bd8f9ff11fe8a8e21d3496655 100644
--- a/Source/Rendering/CMakeLists.txt
+++ b/Source/Rendering/CMakeLists.txt
@@ -134,9 +134,12 @@ imstk_add_library( Rendering
     Animation
     glm
     ${VTK_LIBRARIES}
-    ${RENDERING_LIBRARIES}
-  #VERBOSE
-  )
+    ${RENDERING_LIBRARIES})
+  #VERBOSE)
+
+if( NOT iMSTK_USE_Vulkan )
+  vtk_module_autoinit(TARGETS Rendering MODULES ${VTK_LIBRARIES})
+endif()
 
 #-----------------------------------------------------------------------------
 # Testing
diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
index 60a92b28d55a506065484e52917880b4fe17fe07..f2606e9e083bb2fea8e19fc84bf8b8b3ce627464 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
+++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp
@@ -419,76 +419,76 @@ VTKRenderer::getAxesVisibility() const
     return m_AxesActor->GetVisibility();
 }
 
-//void
-//VTKRenderer::setTimeTable(const std::unordered_map<std::string, double>& timeTable)
-//{
-//    // Sort by elapsed times
-//    std::vector<std::pair<std::string, double>> nameToTimesVec(timeTable.begin(), timeTable.end());
-//    std::sort(nameToTimesVec.begin(), nameToTimesVec.end(),
-//        [](const std::pair<std::string, double>& a, const std::pair<std::string, double>& b) { return a.second < b.second; });
-//
-//    // Construct vtkTable from provided data
-//    vtkSmartPointer<vtkDoubleArray> xIndices      = vtkDoubleArray::SafeDownCast(m_timeTable->GetColumn(0));
-//    vtkSmartPointer<vtkDoubleArray> yElapsedTimes = vtkDoubleArray::SafeDownCast(m_timeTable->GetColumn(1));
-//    vtkSmartPointer<vtkStringArray> labels = vtkStringArray::SafeDownCast(m_timeTable->GetColumn(2));
-//
-//    labels->SetNumberOfValues(nameToTimesVec.size());
-//    xIndices->SetNumberOfValues(nameToTimesVec.size());
-//    yElapsedTimes->SetNumberOfValues(nameToTimesVec.size());
-//    for (size_t i = 0; i < nameToTimesVec.size(); i++)
-//    {
-//        labels->SetValue(i, nameToTimesVec[i].first.c_str());
-//        xIndices->SetValue(i, i + 1);
-//        yElapsedTimes->SetValue(i, nameToTimesVec[i].second);
-//    }
-//
-//    // The range for the x axis is based on history of the elapsed times
-//    vtkAxis* botAxis = m_timeTableChart->GetAxis(vtkAxis::BOTTOM);
-//
-//    // Get the previous and current range
-//    double newMaxElapsed = yElapsedTimes->GetRange()[1];
-//    yElapsedTimes->Modified();
-//    double currMaxElapsed = botAxis->GetMaximum();
-//
-//    // Always respect the max as all information should be shown
-//    if (newMaxElapsed > currMaxElapsed)
-//    {
-//        botAxis->SetRange(0.0, newMaxElapsed);
-//    }
-//    // But if current elapsed is less than the existing one we can lag
-//    else
-//    {
-//        // Lag downscaling by 400 iterations
-//        if (m_timeTableIter % 400 == 0)
-//        {
-//            botAxis->SetRange(0.0, newMaxElapsed);
-//        }
-//        else
-//        {
-//            botAxis->SetRange(0.0, currMaxElapsed);
-//        }
-//        m_timeTableIter++;
-//    }
-//    botAxis->Modified();
-//
-//    vtkAxis* leftAxis = m_timeTableChart->GetAxis(vtkAxis::LEFT);
-//    leftAxis->SetRange(xIndices->GetRange());
-//    leftAxis->SetCustomTickPositions(xIndices, labels);
-//
-//    m_timeTable->Modified();
-//}
-//
-//void
-//VTKRenderer::setTimeTableVisibility(const bool visible)
-//{
-//    m_timeTableChartActor->SetVisibility(visible);
-//}
-//
-//bool
-//VTKRenderer::getTimeTableVisibility() const
-//{
-//    return m_timeTableChartActor->GetVisibility();
-//}
+void
+VTKRenderer::setTimeTable(const std::unordered_map<std::string, double>& timeTable)
+{
+    // Sort by elapsed times
+    std::vector<std::pair<std::string, double>> nameToTimesVec(timeTable.begin(), timeTable.end());
+    std::sort(nameToTimesVec.begin(), nameToTimesVec.end(),
+        [](const std::pair<std::string, double>& a, const std::pair<std::string, double>& b) { return a.second < b.second; });
+
+    // Construct vtkTable from provided data
+    vtkSmartPointer<vtkDoubleArray> xIndices      = vtkDoubleArray::SafeDownCast(m_timeTable->GetColumn(0));
+    vtkSmartPointer<vtkDoubleArray> yElapsedTimes = vtkDoubleArray::SafeDownCast(m_timeTable->GetColumn(1));
+    vtkSmartPointer<vtkStringArray> labels = vtkStringArray::SafeDownCast(m_timeTable->GetColumn(2));
+
+    labels->SetNumberOfValues(nameToTimesVec.size());
+    xIndices->SetNumberOfValues(nameToTimesVec.size());
+    yElapsedTimes->SetNumberOfValues(nameToTimesVec.size());
+    for (size_t i = 0; i < nameToTimesVec.size(); i++)
+    {
+        labels->SetValue(i, nameToTimesVec[i].first.c_str());
+        xIndices->SetValue(i, i + 1);
+        yElapsedTimes->SetValue(i, nameToTimesVec[i].second);
+    }
+
+    // The range for the x axis is based on history of the elapsed times
+    vtkAxis* botAxis = m_timeTableChart->GetAxis(vtkAxis::BOTTOM);
+
+    // Get the previous and current range
+    double newMaxElapsed = yElapsedTimes->GetRange()[1];
+    yElapsedTimes->Modified();
+    double currMaxElapsed = botAxis->GetMaximum();
+
+    // Always respect the max as all information should be shown
+    if (newMaxElapsed > currMaxElapsed)
+    {
+        botAxis->SetRange(0.0, newMaxElapsed);
+    }
+    // But if current elapsed is less than the existing one we can lag
+    else
+    {
+        // Lag downscaling by 400 iterations
+        if (m_timeTableIter % 400 == 0)
+        {
+            botAxis->SetRange(0.0, newMaxElapsed);
+        }
+        else
+        {
+            botAxis->SetRange(0.0, currMaxElapsed);
+        }
+        m_timeTableIter++;
+    }
+    botAxis->Modified();
+
+    vtkAxis* leftAxis = m_timeTableChart->GetAxis(vtkAxis::LEFT);
+    leftAxis->SetRange(xIndices->GetRange());
+    leftAxis->SetCustomTickPositions(xIndices, labels);
+
+    m_timeTable->Modified();
+}
+
+void
+VTKRenderer::setTimeTableVisibility(const bool visible)
+{
+    m_timeTableChartActor->SetVisibility(visible);
+}
+
+bool
+VTKRenderer::getTimeTableVisibility() const
+{
+    return m_timeTableChartActor->GetVisibility();
+}
 
 void
 VTKRenderer::updateSceneCamera(std::shared_ptr<Camera> imstkCam)
diff --git a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h
index fca9a81520cdc09d76844786d3480b34732e0499..17f0a6382a707f1b96d343ee5e8e7f8c42c1e3a9 100644
--- a/Source/Rendering/VTKRenderer/imstkVTKRenderer.h
+++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h
@@ -102,17 +102,17 @@ public:
     ///
     /// \brief Sets the benchmarking table using unordered_map
     ///
-    //void setTimeTable(const std::unordered_map<std::string, double>& timeTable);
+    void setTimeTable(const std::unordered_map<std::string, double>& timeTable);
 
     ///
     /// \brief Set the visibility of the benchmark graph
     ///
-    //void setTimeTableVisibility(const bool visible);
+    void setTimeTableVisibility(const bool visible);
 
     ///
     /// \brief Get the visibility of the benchmark graph
     ///
-    //bool getTimeTableVisibility() const;
+    bool getTimeTableVisibility() const;
 
     ///
     /// \brief Updates the scene camera's position and orientation
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp
index d5ab9f6b983c4d52c82ff1f0134a3b480bfacf23..e53ca868bf6ea18f80a3479c8f6749eae1ae272e 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp
@@ -80,9 +80,9 @@ VTKViewer::VTKViewer(SimulationManager* manager /*= nullptr*/, bool enableVR /*=
 #endif
 
     // Setup callback for timer on the interactor
-    /*timerCallbackCommand = vtkSmartPointer<vtkCallbackCommand>::New();
+    timerCallbackCommand = vtkSmartPointer<vtkCallbackCommand>::New();
     timerCallbackCommand->SetCallback(timerCallback);
-    timerCallbackCommand->SetClientData(this);*/
+    timerCallbackCommand->SetClientData(this);
 }
 
 void
@@ -190,13 +190,13 @@ VTKViewer::startRenderingLoop()
         m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0);
 
         // If the Scene wants benchmarking hookup timer to update the table
-        /*auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer());
+        auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(getActiveRenderer());
         vtkRen->setTimeTableVisibility(m_activeScene->getConfig()->taskTimingEnabled);
         if (m_activeScene->getConfig()->taskTimingEnabled)
         {
             m_vtkRenderWindow->GetInteractor()->AddObserver(vtkCommand::TimerEvent, timerCallbackCommand);
             m_vtkRenderWindow->GetInteractor()->CreateRepeatingTimer(500);
-        }*/
+        }
 
         m_vtkRenderWindow->SetWindowName(m_config->m_windowName.c_str());
         m_vtkRenderWindow->GetInteractor()->Start();
@@ -254,17 +254,17 @@ VTKViewer::getTextStatusManager()
     return m_vtkInteractorStyle->getTextStatusManager();
 }
 
-//void
-//VTKViewer::timerCallback(vtkObject* caller, long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData))
-//{
-//    VTKViewer* self = static_cast<VTKViewer*>(clientData);
-//
-//    if (self->getActiveScene()->getConfig()->taskTimingEnabled)
-//    {
-//        auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(self->getActiveRenderer());
-//        self->getActiveScene()->lockComputeTimes();
-//        vtkRen->setTimeTable(self->getActiveScene()->getTaskComputeTimes());
-//        self->getActiveScene()->unlockComputeTimes();
-//    }
-//}
+void
+VTKViewer::timerCallback(vtkObject* caller, long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData))
+{
+    VTKViewer* self = static_cast<VTKViewer*>(clientData);
+
+    if (self->getActiveScene()->getConfig()->taskTimingEnabled)
+    {
+        auto vtkRen = std::dynamic_pointer_cast<VTKRenderer>(self->getActiveRenderer());
+        self->getActiveScene()->lockComputeTimes();
+        vtkRen->setTimeTable(self->getActiveScene()->getTaskComputeTimes());
+        self->getActiveScene()->unlockComputeTimes();
+    }
+}
 } // imstk
diff --git a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h
index 2cc0c11031e4f73775d04d3e31c919adbc423eef..a762bcae464ad529da08501784250c965d4dca52 100644
--- a/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h
+++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h
@@ -110,14 +110,14 @@ public:
     const std::shared_ptr<VTKTextStatusManager>& getTextStatusManager();
 
 protected:
-    /// \brief TODO
-    //static void timerCallback(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData);
+    /// \brief VTKTimer callback, every 500ms
+    static void timerCallback(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData);
 
     vtkSmartPointer<vtkRenderWindow>    m_vtkRenderWindow;
     std::shared_ptr<VTKInteractorStyle> m_vtkInteractorStyle;
     bool m_enableVR;
 
-    //vtkSmartPointer<vtkCallbackCommand> timerCallbackCommand;
+    vtkSmartPointer<vtkCallbackCommand> timerCallbackCommand;
 
 #ifdef iMSTK_ENABLE_VR
     vtkSmartPointer<OpenVRCommand> m_openVRCommand;