diff --git a/liblava/frame/renderer.cpp b/liblava/frame/renderer.cpp
index e8fce7edf34bb8285273df8c4f2832f8ff2d8717..fcea4c64625d5613db5c881efc8c693ab5f7d16c 100644
--- a/liblava/frame/renderer.cpp
+++ b/liblava/frame/renderer.cpp
@@ -137,7 +137,9 @@ namespace lava {
         std::vector<VkSemaphore> complete_semaphores = { render_complete_semaphores[current_sync] };
         
         for (frame_submission& submission : submissions) {
-            complete_semaphores.push_back(submission.semaphore);
+            if (submission.semaphore != VK_NULL_HANDLE) {
+                complete_semaphores.push_back(submission.semaphore);
+            }
         }
 
         VkPipelineStageFlags const wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
diff --git a/src/headset/openvr_headset.cpp b/src/headset/openvr_headset.cpp
index 2d1b5739cb8434c0c652c42f8cf457b68720b793..bf2db060edd6adcc630d97569c51c29f9f732584 100644
--- a/src/headset/openvr_headset.cpp
+++ b/src/headset/openvr_headset.cpp
@@ -143,36 +143,43 @@ void OpenVRHeadset::submit_frame(VkCommandBuffer command_buffer, VkImageLayout f
         frame_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
         frame_barrier.subresourceRange = frame_image->get_subresource_range();
 
-        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &frame_barrier);
+        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &frame_barrier);
     }
 
-    lava::device_ptr device = this->get_application()->get_device();
-
-    vr::VRVulkanTextureArrayData_t texture_data;
-    texture_data.m_nImage = (uint64_t)frame_image->get();
-    texture_data.m_pDevice = device->get();
-    texture_data.m_pPhysicalDevice = device->get_physical_device()->get();
-    texture_data.m_pInstance = this->get_application()->get_instance().get();
-    texture_data.m_pQueue = device->get_graphics_queue().vk_queue;
-    texture_data.m_nQueueFamilyIndex = device->get_graphics_queue().family;
-    texture_data.m_nWidth = this->resolution.x;
-    texture_data.m_nHeight = this->resolution.y;
-    texture_data.m_nFormat = this->get_format();
-    texture_data.m_nSampleCount = VK_SAMPLE_COUNT_1_BIT;
-    texture_data.m_unArrayIndex = frame_id;
-    texture_data.m_unArraySize = this->framebuffers.size();
-
-    vr::Texture_t texture;
-    texture.handle = &texture_data;
-    texture.eType = vr::TextureType_Vulkan;
-    texture.eColorSpace = vr::ColorSpace_Auto;
-
-    vr::EVRCompositorError error = vr::VRCompositor()->Submit((vr::EVREye)frame_id, &texture, nullptr, vr::Submit_VulkanTextureWithArrayData);
-    
-    if (error != vr::VRCompositorError_None)
+    lava::frame_submission submission;
+    submission.semaphore = VK_NULL_HANDLE;
+    submission.callback = [this, frame_id, frame_image]()
     {
-        lava::log()->error("OpenVR: Can't submit image to OpenVR. Maybe due to headset standby. Error code '{}'", error);
-    }
+        lava::device_ptr device = this->get_application()->get_device();
+
+        vr::VRVulkanTextureArrayData_t texture_data;
+        texture_data.m_nImage = (uint64_t)frame_image->get();
+        texture_data.m_pDevice = device->get();
+        texture_data.m_pPhysicalDevice = device->get_physical_device()->get();
+        texture_data.m_pInstance = this->get_application()->get_instance().get();
+        texture_data.m_pQueue = device->get_graphics_queue().vk_queue;
+        texture_data.m_nQueueFamilyIndex = device->get_graphics_queue().family;
+        texture_data.m_nWidth = this->resolution.x;
+        texture_data.m_nHeight = this->resolution.y;
+        texture_data.m_nFormat = this->get_format();
+        texture_data.m_nSampleCount = VK_SAMPLE_COUNT_1_BIT;
+        texture_data.m_unArrayIndex = frame_id;
+        texture_data.m_unArraySize = this->framebuffers.size();
+
+        vr::Texture_t texture;
+        texture.handle = &texture_data;
+        texture.eType = vr::TextureType_Vulkan;
+        texture.eColorSpace = vr::ColorSpace_Auto;
+
+        vr::EVRCompositorError error = vr::VRCompositor()->Submit((vr::EVREye)frame_id, &texture, nullptr, vr::Submit_VulkanTextureWithArrayData);
+    
+        if (error != vr::VRCompositorError_None)
+        {
+            lava::log()->error("OpenVR: Can't submit image to OpenVR. Maybe due to headset standby. Error code '{}'", error);
+        }
+    };
+
+    this->get_application()->get_renderer().add_submission(submission);
 }
 
 VkFormat OpenVRHeadset::get_format() const
diff --git a/src/headset/openxr_headset.cpp b/src/headset/openxr_headset.cpp
index d04cf5ba19a776a23f8cc0ed4e05a686c2bf7476..a9d3038ff90b534da7818f6b072fe5157c973341 100644
--- a/src/headset/openxr_headset.cpp
+++ b/src/headset/openxr_headset.cpp
@@ -374,7 +374,7 @@ void OpenXRHeadset::submit_frame(VkCommandBuffer command_buffer, VkImageLayout f
 
         image_barriers.push_back(swapchain_begin_barrier);
 
-        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, image_barriers.size(), image_barriers.data());
+        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, image_barriers.size(), image_barriers.data());
 
         VkImageCopy copy_region;
         copy_region.srcSubresource = frame_image->get_subresource_layers(),
@@ -404,16 +404,21 @@ void OpenXRHeadset::submit_frame(VkCommandBuffer command_buffer, VkImageLayout f
         swapchain_end_barrier.subresourceRange.baseArrayLayer = 0;
         swapchain_end_barrier.subresourceRange.layerCount = 1;
 
-        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &swapchain_end_barrier);
+        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &swapchain_end_barrier);
 
-        this->release_image(frame_id);
+        lava::frame_submission submission;
+        submission.semaphore = VK_NULL_HANDLE;
+        submission.callback = [this, frame_id]()
+        {
+            this->release_image(frame_id);
 
-        this->submit_count++;
+            this->submit_count++;
 
-        if (this->submit_count == this->views.size())
-        {
-            this->end_frame();
-        }
+            if (this->submit_count == this->views.size())
+            {
+                this->end_frame();
+            }
+        };
     }
 }
 
@@ -728,68 +733,13 @@ bool OpenXRHeadset::create_actions()
         }
     }
 
-    std::vector<std::string> path_strings =
-    {
-        "/user/hand/right/input/a/click",
-        "/user/hand/right/input/b/click",
-        "/user/hand/left/input/x/click",
-        "/user/hand/left/input/y/click",
-        "/user/hand/left/input/trigger/click",
-        "/user/hand/right/input/trigger/click",
-        "/user/hand/left/input/thumbstick",
-        "/user/hand/right/input/thumbstick",
-        "/user/hand/left/input/aim/pose",
-        "/user/hand/right/input/aim/pose",
-        "/interaction_profiles/htc/vive_cosmos_controller"
-    };
-
-    std::vector<XrPath> paths;
-    paths.resize(path_strings.size());
-
-    for (uint32_t index = 0; index < path_strings.size(); index++)
-    {
-        if (xrStringToPath(this->instance, path_strings[index].c_str(), &paths[index]) != XR_SUCCESS)
-        {
-            lava::log()->error("OpenXR: Can't create path for string: " + path_strings[index]);
-
-            return false;
-        }
-    }
-
-    std::vector<XrAction> actions =
-    {
-        this->controller_button_actions[0],
-        this->controller_button_actions[1],
-        this->controller_button_actions[2],
-        this->controller_button_actions[3],
-        this->controller_button_actions[4],
-        this->controller_button_actions[5],
-        this->controller_thumbstick_actions[0],
-        this->controller_thumbstick_actions[1],
-        this->controller_transform_actions[0],
-        this->controller_transform_actions[1]
-    };
-
-    std::vector<XrActionSuggestedBinding> bindings;
-    bindings.resize(actions.size());
-
-    for (uint32_t index = 0; index < bindings.size(); index++)
+    if (!this->suggest_vive_controller_binding())
     {
-        bindings[index].action = actions[index];
-        bindings[index].binding = paths[index];
+        return false;
     }
 
-    XrInteractionProfileSuggestedBinding suggested_bindings;
-    suggested_bindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
-    suggested_bindings.next = nullptr;
-    suggested_bindings.interactionProfile = paths.back();
-    suggested_bindings.countSuggestedBindings = bindings.size();
-    suggested_bindings.suggestedBindings = bindings.data();
-    
-    if (xrSuggestInteractionProfileBindings(this->instance, &suggested_bindings) != XR_SUCCESS)
+    if (!this->suggest_vive_cosmos_controller_binding())
     {
-        lava::log()->error("OpenXR: Can't set suggested bindings");
-
         return false;
     }
 
@@ -1487,6 +1437,146 @@ bool OpenXRHeadset::check_swapchain_format_support(int64_t required_format) cons
     return false;
 }
 
+bool OpenXRHeadset::suggest_vive_controller_binding()
+{
+    std::vector<std::string> path_strings =
+    {
+        "/user/hand/right/input/trackpad/click",
+        "/user/hand/right/input/squeeze/click",
+        "/user/hand/left/input/trackpad/click",
+        "/user/hand/left/input/squeeze/click",
+        "/user/hand/left/input/trigger/click",
+        "/user/hand/right/input/trigger/click",
+        "/user/hand/left/input/trackpad",
+        "/user/hand/right/input/trackpad",
+        "/user/hand/left/input/aim/pose",
+        "/user/hand/right/input/aim/pose",
+        "/interaction_profiles/htc/vive_controller"
+    };
+
+    std::vector<XrPath> paths;
+    paths.resize(path_strings.size());
+
+    for (uint32_t index = 0; index < path_strings.size(); index++)
+    {
+        if (xrStringToPath(this->instance, path_strings[index].c_str(), &paths[index]) != XR_SUCCESS)
+        {
+            lava::log()->error("OpenXR: Can't create path for string: " + path_strings[index]);
+
+            return false;
+        }
+    }
+
+    std::vector<XrAction> actions =
+    {
+        this->controller_button_actions[0],
+        this->controller_button_actions[1],
+        this->controller_button_actions[2],
+        this->controller_button_actions[3],
+        this->controller_button_actions[4],
+        this->controller_button_actions[5],
+        this->controller_thumbstick_actions[0],
+        this->controller_thumbstick_actions[1],
+        this->controller_transform_actions[0],
+        this->controller_transform_actions[1]
+    };
+
+    std::vector<XrActionSuggestedBinding> bindings;
+    bindings.resize(actions.size());
+
+    for (uint32_t index = 0; index < bindings.size(); index++)
+    {
+        bindings[index].action = actions[index];
+        bindings[index].binding = paths[index];
+    }
+
+    XrInteractionProfileSuggestedBinding suggested_bindings;
+    suggested_bindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
+    suggested_bindings.next = nullptr;
+    suggested_bindings.interactionProfile = paths.back();
+    suggested_bindings.countSuggestedBindings = bindings.size();
+    suggested_bindings.suggestedBindings = bindings.data();
+    
+    if (xrSuggestInteractionProfileBindings(this->instance, &suggested_bindings) != XR_SUCCESS)
+    {
+        lava::log()->error("OpenXR: Can't set suggested bindings for vive controller");
+
+        return false;
+    }
+
+    return true;
+}
+
+bool OpenXRHeadset::suggest_vive_cosmos_controller_binding()
+{
+    std::vector<std::string> path_strings =
+    {
+        "/user/hand/right/input/a/click",
+        "/user/hand/right/input/b/click",
+        "/user/hand/left/input/x/click",
+        "/user/hand/left/input/y/click",
+        "/user/hand/left/input/trigger/click",
+        "/user/hand/right/input/trigger/click",
+        "/user/hand/left/input/thumbstick",
+        "/user/hand/right/input/thumbstick",
+        "/user/hand/left/input/aim/pose",
+        "/user/hand/right/input/aim/pose",
+        "/interaction_profiles/htc/vive_cosmos_controller"
+    };
+
+    std::vector<XrPath> paths;
+    paths.resize(path_strings.size());
+
+    for (uint32_t index = 0; index < path_strings.size(); index++)
+    {
+        if (xrStringToPath(this->instance, path_strings[index].c_str(), &paths[index]) != XR_SUCCESS)
+        {
+            lava::log()->error("OpenXR: Can't create path for string: " + path_strings[index]);
+
+            return false;
+        }
+    }
+
+    std::vector<XrAction> actions =
+    {
+        this->controller_button_actions[0],
+        this->controller_button_actions[1],
+        this->controller_button_actions[2],
+        this->controller_button_actions[3],
+        this->controller_button_actions[4],
+        this->controller_button_actions[5],
+        this->controller_thumbstick_actions[0],
+        this->controller_thumbstick_actions[1],
+        this->controller_transform_actions[0],
+        this->controller_transform_actions[1]
+    };
+
+    std::vector<XrActionSuggestedBinding> bindings;
+    bindings.resize(actions.size());
+
+    for (uint32_t index = 0; index < bindings.size(); index++)
+    {
+        bindings[index].action = actions[index];
+        bindings[index].binding = paths[index];
+    }
+
+    XrInteractionProfileSuggestedBinding suggested_bindings;
+    suggested_bindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
+    suggested_bindings.next = nullptr;
+    suggested_bindings.interactionProfile = paths.back();
+    suggested_bindings.countSuggestedBindings = bindings.size();
+    suggested_bindings.suggestedBindings = bindings.data();
+    
+    if (xrSuggestInteractionProfileBindings(this->instance, &suggested_bindings) != XR_SUCCESS)
+    {
+        lava::log()->error("OpenXR: Can't set suggested bindings for vive cosmos controller");
+
+        return false;
+    }
+
+    return true;
+}
+
 std::vector<std::string> OpenXRHeadset::split_string(std::string string, char delimiter)
 {
     std::vector<std::string> strings;
diff --git a/src/headset/openxr_headset.hpp b/src/headset/openxr_headset.hpp
index 745c00a3c76e38efe5a5b3f747cb89031676d760..f19394b67442b8e7fa512ee46c24b24e4c6e88bb 100644
--- a/src/headset/openxr_headset.hpp
+++ b/src/headset/openxr_headset.hpp
@@ -72,6 +72,9 @@ private:
     bool check_view_type_support(XrViewConfigurationType required_type) const;
     bool check_swapchain_format_support(int64_t required_format) const;
 
+    bool suggest_vive_controller_binding();
+    bool suggest_vive_cosmos_controller_binding();
+
     static std::vector<std::string> split_string(std::string string, char delimiter = ' ');
 
 private:
diff --git a/src/scene.cpp b/src/scene.cpp
index c8882f3a6d7e7354a941cdc9c3af0d209ff88392..4013fd982e2f076b23b1a6a4f4e876bcf7e6b051 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -1187,14 +1187,24 @@ bool Scene::load_lights(const aiScene* scene, float scale, const std::map<std::s
             light_scale = glm::pow(scale, 1); //It should be a 2 instead of a 1
         }
 
+        glm::vec3 color = glm::make_vec3(&light->mColorDiffuse.r);
+        glm::vec3 position = glm::make_vec3(&light->mPosition.x);
+        glm::vec3 direction = glm::make_vec3(&light->mDirection.x);
+        float direction_length = glm::length(direction);
+
+        if (direction_length > 0.0f)
+        {
+            direction /= direction_length;            
+        }
+
         SceneLight& scene_light = this->lights.emplace_back();
         scene_light.node_index = node_indices.at(light->mName.C_Str());
-        scene_light.initial_position = glm::make_vec3(&light->mPosition.x) * scale;
-        scene_light.initial_direction = glm::normalize(glm::make_vec3(&light->mDirection.x));
+        scene_light.initial_position = position * scale;
+        scene_light.initial_direction = direction;
 
         glsl::LightData& light_data = scene_light.data;
         light_data.position = scene_light.initial_position;
-        light_data.color = glm::make_vec3(&light->mColorDiffuse.r) * light_scale;
+        light_data.color = color * light_scale;
         light_data.outer_angle = light->mAngleOuterCone;
         light_data.direction = scene_light.initial_direction;
         light_data.inner_angle = light->mAngleInnerCone;